/*
 * Copyright (c) 2017. Mathias Ciliberto, Francisco Javier OrdoƱez Morales,
 * Hristijan Gjoreski, Daniel Roggen
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
 * Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package uk.ac.sussex.wear.android.datalogger;

import android.bluetooth.BluetoothAdapter;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.Snackbar;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.InputType;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.Chronometer;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.RelativeLayout;
import android.widget.Spinner;
import android.widget.TextView;

import java.text.SimpleDateFormat;
import java.util.Calendar;

import uk.ac.sussex.wear.android.datalogger.bt.BluetoothDeviceListActivity;
import uk.ac.sussex.wear.android.datalogger.data.CommandBTC;
import uk.ac.sussex.wear.android.datalogger.data.CommandBTS;
import uk.ac.sussex.wear.android.datalogger.data.CommandDCE;
import uk.ac.sussex.wear.android.datalogger.data.CommandFUC;
import uk.ac.sussex.wear.android.datalogger.data.CommandFUS;
import uk.ac.sussex.wear.android.datalogger.data.CommandLAE;


public class DisplayActivity extends AppCompatActivity implements DataLoggerStatusDelegate, View.OnLongClickListener {


    private static final String TAG = DisplayActivity.class.getSimpleName();

    // UI elements.
    private CoordinatorLayout mCoordinatorLayoutView;

    private Button mDataCollectionButton;
    private Button mLabelAnnotationButton;

    private Chronometer mLabelsChronometer;

    private Spinner mActivitiesSpinner, mBodyPositionsSpinner;
    private RadioGroup mLocationRadioGroup;

    private Menu menu;


    private static final int REQUEST_CONNECT_DEVICE = 1;
    private Button mBluetoothButton;

    private int mDeviceLocation = 3;

    // Control stop and start labelling when the activity is created. Otherwise onCreate will trigger
    // a label annotation event.
    private boolean allowStopStartLabelAnnotation = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mCoordinatorLayoutView = (CoordinatorLayout) findViewById(R.id.coordinatorLayout);

        mLabelsChronometer = (Chronometer) findViewById(R.id.label_annotation_chronometer);

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        // Registers a callback to be invoked when a change happens to a preference.
        getSharedPreferencesInstance().registerOnSharedPreferenceChangeListener(sharedPrefsListener);

        /******************************************************************************************/
        // Labels selection spinners initialization
        /******************************************************************************************/

        // Setting adapters for UI spinners
        mBodyPositionsSpinner = (Spinner) findViewById(R.id.ui_body_positions_spinner);
        assert mBodyPositionsSpinner != null;
        mBodyPositionsSpinner.setOnItemSelectedListener(mBodyPositionsSpinnerListener);

        mActivitiesSpinner = (Spinner) findViewById(R.id.ui_activities_spinner);
        assert mActivitiesSpinner != null;
        mActivitiesSpinner.setOnItemSelectedListener(mActivitiesSpinnerListener);
        mActivitiesSpinner.setAdapter(new CustomIconsListAdapter(
                getApplicationContext(),
                getResources().obtainTypedArray(R.array.activities_icons_array),
                getResources().getStringArray(R.array.activities_names_array))
        );
        // The activities spinner adapter is updated to the correct value
        mActivitiesSpinner.setSelection(SharedPreferencesHelper.getSelectedActivityLabel(this));

        // In case the label annotation is active in the service, the label chronometer is updated
        if (SharedPreferencesHelper.getLabelsAnnotationState(this)) {
            allowStopStartLabelAnnotation = false;
            long labelStartingTime = SharedPreferencesHelper.getLabelsAnnotationStartingTime(this);
            if (labelStartingTime > 0) {
                onLabelTimerStart(System.currentTimeMillis() - labelStartingTime);
            }
        }

        /******************************************************************************************/
        // Labels selection radio buttons initialization
        /******************************************************************************************/

        mLocationRadioGroup = (RadioGroup) findViewById(R.id.ui_iolocation_radioGroup);
        assert mLocationRadioGroup != null;
        mLocationRadioGroup.check(SharedPreferencesHelper.getSelectedLocationLabel(this));
        mLocationRadioGroup.setOnCheckedChangeListener(mBodyLocationRadioGroupListener);

        /******************************************************************************************/
        // Data collection and label annotation switches initialization
        /******************************************************************************************/

        // Setting listener for data collection switch
        mDataCollectionButton = (Button) findViewById(R.id.ui_data_collection_button);
        assert mDataCollectionButton != null;
        mDataCollectionButton.setOnLongClickListener(this);

        // Setting listener for labels annotation switch
        mLabelAnnotationButton = (Button) findViewById(R.id.ui_label_annotation_button);
        assert mLabelAnnotationButton != null;
        mLabelAnnotationButton.setOnLongClickListener(this);

        updateTextviewSwitch(false, R.id.ui_data_collection_custom_text);
        // Data collection switch can be activated/deactivated by default
        mDataCollectionButton.setEnabled(true);

        updateTextviewSwitch(false, R.id.ui_label_annotation_custom_text);
        // Data labelling switch can be activated only when data collection switch is active
        mLabelAnnotationButton.setEnabled(false);

        /******************************************************************************************/
        // Defining buttons listeners
        /******************************************************************************************/

        // Setting listener for bluetooth button
        mBluetoothButton = (Button) findViewById(R.id.ui_bluetooth_status_button);
        assert mBluetoothButton != null;
        mBluetoothButton.setOnClickListener(mClickBluetoothButton);

        /******************************************************************************************/
        // Starting main DataLogger service with 'Bluetooth start' command
        /******************************************************************************************/

        DataLoggerService.setStatusDelegate(this);
        startService(new Intent(this, DataLoggerService.class)
                .putExtra(Constants.COMMAND_SERVICE_INTENT_KEY, new CommandBTS().getMessage()));

    }


    @Override
    protected void onStart() {
        super.onStart();

        mDeviceLocation = SharedPreferencesHelper.getDeviceLocationValue(this);

        // If the state of the data collector when the activity starts was "collecting data"
        // a message is sent to the service to be sure the state is correct
        if (SharedPreferencesHelper.getDataCollectionState(this)) {
            startService(new Intent(this, DataLoggerService.class)
                    .putExtra(Constants.COMMAND_SERVICE_INTENT_KEY,
                            new CommandDCE(true).getMessage()));
            mDataCollectionButton.setEnabled(true);
            updateTextviewSwitch(true, R.id.ui_data_collection_custom_text);
            setChecked(mDataCollectionButton, true);
            mLabelAnnotationButton.setEnabled(true);
        } else {
            updateTextviewSwitch(false, R.id.ui_data_collection_custom_text);
            setChecked(mDataCollectionButton, false);
            mLabelAnnotationButton.setEnabled(false);
        }

        if (SharedPreferencesHelper.getLabelsAnnotationState(this)) {
            startService(new Intent(DisplayActivity.this, DataLoggerService.class)
                    .putExtra(Constants.COMMAND_SERVICE_INTENT_KEY,
                            new CommandLAE(true,
                                    SharedPreferencesHelper.getAnnotatedActivityLabel(this),
                                    SharedPreferencesHelper.getAnnotatedBodyPositionLabel(this),
                                    SharedPreferencesHelper.getAnnotatedLocationLabel(this)
                            ).getMessage()
                    )
            );
            mDataCollectionButton.setEnabled(false);
            updateTextviewSwitch(true, R.id.ui_label_annotation_custom_text);
            setChecked(mLabelAnnotationButton, true);
        } else {
            mDataCollectionButton.setEnabled(true);
            updateTextviewSwitch(false, R.id.ui_label_annotation_custom_text);
            setChecked(mLabelAnnotationButton, false);
        }


        // Update the bluetooth RelativeLayout based on the bluetooth adapter status.
        refreshBluetoothLayout();

        if (mDeviceLocation == Constants.DEVICE_LOCATION_HAND) { //if this is the master device
            // Update the TextView which shows the connectivity status of the slave devices.
            refreshBluetoothSlavesLayout();
        }

        // Update the main UI layout based on the device profile (master or slave)
        refreshContentLayout();

    }

    private void setChecked(Button button, boolean bool) {
        if (bool) {
            button.setText(R.string.on);
        } else {
            button.setText(R.string.off);
        }

    }


    /**********************************************************************************************/
    /**********************************************************************************************/
    /*                          Methods and fields related to the UI                              */
    /**********************************************************************************************/
    /**********************************************************************************************/

    public void refreshBluetoothSlavesLayout() {
        int value = SharedPreferencesHelper.getSlavesConnected(this);
        int[] bitmasks = new int[]{0x4, 0x2, 0x1};
        int[] layouts = new int[]{R.id.ui_bluetooth_status_slaves_torso,
                R.id.ui_bluetooth_status_slaves_hips,
                R.id.ui_bluetooth_status_slaves_bag};
        for (int i = 0; i < bitmasks.length; i++) {
            boolean isConnected = ((value & bitmasks[i]) == bitmasks[i]);
            TextView textView = (TextView) findViewById(layouts[i]);
            assert textView != null;
            textView.setTextColor(ContextCompat.getColor(DisplayActivity.this,
                    isConnected ? R.color.colorBtSlavesOn : R.color.colorBtSlavesOff));
        }
    }

    /**
     * The layout of the bluetooth controls must change based on the device location and the state
     * of the bluetooth adapter.
     */
    private void refreshBluetoothLayout() {
        // Current state of the bluetooth adapter
        int state = SharedPreferencesHelper.getBluetoothStatus(this);
        boolean slavesVisible = true;
        boolean buttonVisible = true;
        String[] bluetoothStateList = SharedPreferencesHelper.getBluetoothStateList(this);
        TextView bluetoothCustomText = (TextView) findViewById(R.id.ui_bluetooth_status_state_custom_text);

        if (mDeviceLocation != Constants.DEVICE_LOCATION_HAND) {
            slavesVisible = false;
        }

        switch (state) {
            case Constants.BLUETOOTH_STATE_NOT_SUPPORTED: // Bluetooth not supported
                buttonVisible = false;
                slavesVisible = false;
                bluetoothCustomText.setText(bluetoothStateList[state]);
                break;
            case Constants.BLUETOOTH_STATE_DISABLED: // Bluetooth disabled
                ((Button) findViewById(R.id.ui_bluetooth_status_button)).setText(
                        R.string.ui_bluetooth_button_text_enable);
                bluetoothCustomText.setText(bluetoothStateList[state]);
                break;
            case Constants.BLUETOOTH_STATE_ENABLED: // Bluetooth enabled
                int text = R.string.ui_bluetooth_button_text_connect;
                ((Button) findViewById(R.id.ui_bluetooth_status_button)).setText(text);
                bluetoothCustomText.setText(bluetoothStateList[state]);
                break;
            case Constants.BLUETOOTH_STATE_CONNECTING:
            case Constants.BLUETOOTH_STATE_CONNECTED:
                if (mDeviceLocation != Constants.DEVICE_LOCATION_HAND) {
                    bluetoothCustomText.setText(bluetoothStateList[state]);
                }
                break;
        }

        LinearLayout layoutSlaves = (LinearLayout) findViewById(R.id.ui_bluetooth_status_slaves);
        for (int i = 0; i < layoutSlaves.getChildCount(); i++) {
            layoutSlaves.getChildAt(i).setVisibility(slavesVisible ? View.VISIBLE : View.GONE);
        }

        LinearLayout layoutButton = (LinearLayout) findViewById(R.id.ui_bluetooth_button);
        for (int i = 0; i < layoutButton.getChildCount(); i++) {
            layoutButton.getChildAt(i).setVisibility(buttonVisible ? View.VISIBLE : View.GONE);
        }

    }

    public void updateTextviewSwitch(boolean isActive, int id) {
        TextView customText = (TextView) findViewById(id);
        if (isActive) {
            customText.setTextColor(ContextCompat.getColor(this, R.color.colorTextCollectionOn));
            customText.setText(getResources().getString(R.string.ui_switch_text_on));
        } else {
            customText.setTextColor(ContextCompat.getColor(this, R.color.colorTextCollectionOff));
            customText.setText(getResources().getString(R.string.ui_switch_text_off));
        }
    }

    private void setBodyPositionsSpinnerAdapter(TypedArray icons, int colorText) {
        mBodyPositionsSpinner.setAdapter(new CustomIconsListAdapter(
                this,
                icons,
                getResources().getStringArray(R.array.body_positions_names_array),
                colorText)
        );
    }

    private void setupLocationRadioButton() {
        boolean includeInOut = SharedPreferencesHelper.getSelectedActivityLabel(this)
                < getResources().getInteger(R.integer.num_labels_w_io_location);
        for (int i = 0; i < mLocationRadioGroup.getChildCount(); i++) {
            ((RadioButton) mLocationRadioGroup.getChildAt(i)).setEnabled(includeInOut);
        }
        TextView bodyLocationTextview = (TextView) findViewById(R.id.body_iolocation_textview);
        if (includeInOut) {
            bodyLocationTextview.setTextColor(ContextCompat.getColor(this, R.color.colorSpinnerOn));
        } else {
            bodyLocationTextview.setTextColor(ContextCompat.getColor(this, R.color.colorSpinnerOff));
            mLocationRadioGroup.check(R.id.ui_iolocation_radioButton_outside);
        }
    }

    private void setupBodyPositionsSpinner() {
        int activityLabel = SharedPreferencesHelper.getSelectedActivityLabel(this);
        boolean hasBodyPosition = (activityLabel
                >= getResources().getInteger(R.integer.num_labels_wo_pos) || activityLabel == 0);
        mBodyPositionsSpinner.setEnabled(hasBodyPosition);

        TextView bodyPositionsTextview = (TextView) findViewById(R.id.body_positions_textview);
        assert bodyPositionsTextview != null;

        // The adapter of the body positions spinner is modified according to the activity
        // This step will trigger the onItemSelected method of the body positions adapter
        if (hasBodyPosition) {
            setBodyPositionsSpinnerAdapter(
                    getResources().obtainTypedArray(R.array.body_positions_on_icons_array),
                    ContextCompat.getColor(this, R.color.colorSpinnerOn));
            bodyPositionsTextview.setTextColor(ContextCompat.getColor(this, R.color.colorSpinnerOn));
        } else {
            setBodyPositionsSpinnerAdapter(
                    getResources().obtainTypedArray(R.array.body_positions_off_icons_array),
                    ContextCompat.getColor(this, R.color.colorSpinnerOff));
            bodyPositionsTextview.setTextColor(ContextCompat.getColor(this, R.color.colorSpinnerOff));
        }
    }

    AdapterView.OnItemSelectedListener
            mActivitiesSpinnerListener = new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            // Store the activity label in SharedPreferences
            SharedPreferencesHelper.setSelectedActivityLabel(DisplayActivity.this, position);
            Log.i(TAG, "mActivitiesSpinnerListener::onItemSelected Current activity: " + position);
            setupBodyPositionsSpinner();
            setupLocationRadioButton();
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {

        }
    };

    private void checkStopStartLabelAnnotation() {
        // If the app is currently annotating
        if (SharedPreferencesHelper.getLabelsAnnotationState(DisplayActivity.this)) {
            if (allowStopStartLabelAnnotation) {

                long lengthLabelMillis = System.currentTimeMillis() - SharedPreferencesHelper.getLabelsAnnotationStartingTime(DisplayActivity.this);
                SharedPreferencesHelper.addLabelAnnotationTime(DisplayActivity.this,
                        SharedPreferencesHelper.getAnnotatedActivityLabel(DisplayActivity.this),
                        (int) (lengthLabelMillis / 1000)
                );

                SharedPreferencesHelper.setLabelsAnnotationStartingTime(DisplayActivity.this, 0);
                mLabelsChronometer.stop();
                startService(new Intent(DisplayActivity.this, DataLoggerService.class)
                        .putExtra(Constants.COMMAND_SERVICE_INTENT_KEY,
                                new CommandLAE(false)
                                        .setStopAndStartEvent(
                                                SharedPreferencesHelper.getSelectedActivityLabel(DisplayActivity.this),
                                                SharedPreferencesHelper.getSelectedBodyPositionLabel(DisplayActivity.this),
                                                SharedPreferencesHelper.getSelectedLocationLabel(DisplayActivity.this))
                                        .getMessage()
                        )
                );
                SharedPreferencesHelper.setLabelsAnnotationStartingTime(DisplayActivity.this, System.currentTimeMillis());
                onLabelTimerStart(0);

            } else {
                allowStopStartLabelAnnotation = true;
            }
        }
    }

    AdapterView.OnItemSelectedListener
            mBodyPositionsSpinnerListener = new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            SharedPreferencesHelper.setSelectedBodyPositionLabel(DisplayActivity.this, position);
            Log.i(TAG, "mBodyPositionsSpinnerListener::onItemSelected Current body position: " + position);
            checkStopStartLabelAnnotation();
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
        }
    };


    RadioGroup.OnCheckedChangeListener
            mBodyLocationRadioGroupListener = new RadioGroup.OnCheckedChangeListener() {

        @Override
        public void onCheckedChanged(RadioGroup group, int checkedId) {
            SharedPreferencesHelper.setSelectedLocationLabel(DisplayActivity.this, checkedId);
            String logMessage = "mBodyLocationRadioGroupListener::onCheckedChanged Current body location: ";
            if (checkedId == R.id.ui_iolocation_radioButton_outside) {
                logMessage += "outside";
            } else if (checkedId == R.id.ui_iolocation_radioButton_inside) {
                logMessage += "inside";
            }
            Log.i(TAG, logMessage);
            checkStopStartLabelAnnotation();
        }
    };

    public void refreshContentLayout() {

        // The toolbar is updated to include a reference to the current location of the device
        getSupportActionBar().setTitle(
                getResources().getString(R.string.toolbar_base_title)
                        + " | @"
                        + SharedPreferencesHelper.getDeviceLocation(this)
        );

        // When the location is not the hand, the visibility of several layouts (file upload,
        // activity selection, data collection switch and label annotation) is GONE
        int visibility = (mDeviceLocation != Constants.DEVICE_LOCATION_HAND) ? View.GONE : View.VISIBLE;
        int[] layoutsId = new int[]{R.id.connectivity_ui,
                R.id.activities_labels_ui,
                R.id.data_collection_ui,
                R.id.label_annotation_ui,
                R.id.label_annotation_timer};

        for (int layoutId : layoutsId) {
            if (layoutId == R.id.data_collection_ui) {
                Button dataCollectionButton = ((Button) findViewById(R.id.ui_data_collection_button));
                if (dataCollectionButton != null)
                    dataCollectionButton.setVisibility(visibility);
            } else {
                RelativeLayout layout = (RelativeLayout) findViewById(layoutId);
                for (int i = 0; i < layout.getChildCount(); i++) {
                    layout.getChildAt(i).setVisibility(visibility);
                }
            }
        }

        mBluetoothButton = (Button) findViewById(R.id.ui_bluetooth_status_button);
        if (mDeviceLocation == Constants.DEVICE_LOCATION_HAND) {
            mBluetoothButton.setVisibility(View.INVISIBLE);
            if (menu != null)
                menu.findItem(R.id.action_pair).setVisible(true);
        } else if (menu != null)
            menu.findItem(R.id.action_pair).setVisible(false);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        this.menu = menu;
        getMenuInflater().inflate(R.menu.menu_main, menu);
        if (SharedPreferencesHelper.getDeviceLocationValue(this) != Constants.DEVICE_LOCATION_HAND)
            menu.findItem(R.id.action_pair).setVisible(false);
        else
            menu.findItem(R.id.action_pair).setVisible(true);
        return true;
    }

    /**********************************************************************************************/
    /**********************************************************************************************/


    View.OnClickListener mClickBluetoothButton = new View.OnClickListener() {

        public void onClick(View v) {
            int state = SharedPreferencesHelper.getBluetoothStatus(DisplayActivity.this);
            switch (state) {
                case Constants.BLUETOOTH_STATE_DISABLED:
                    startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), 0);
                    break;
                case Constants.BLUETOOTH_STATE_ENABLED:
                case Constants.BLUETOOTH_STATE_CONNECTING:
                case Constants.BLUETOOTH_STATE_CONNECTED:
                    boolean isMaster = (mDeviceLocation == Constants.DEVICE_LOCATION_HAND);
                    if (isMaster) {
                        Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
                        discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
                        startActivity(discoverableIntent);
                    } else {
                        Intent serverIntent = new Intent(DisplayActivity.this, BluetoothDeviceListActivity.class);
                        startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);
                    }
                    break;
            }
        }

    };


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case REQUEST_CONNECT_DEVICE:
                if (resultCode == RESULT_OK) {
                    String address = data.getExtras().getString(Constants.BLUETOOTH_DEVICE_ADDRESS_INTENT_KEY);
                    startService(new Intent(this, DataLoggerService.class)
                            .putExtra(Constants.COMMAND_SERVICE_INTENT_KEY, new CommandBTC(address).getMessage()));
                }
                break;
        }
    }


    public void onLabelTimerStart(long elapsedMillis) {
        mLabelsChronometer.setBase(SystemClock.elapsedRealtime() - elapsedMillis);
        mLabelsChronometer.start();
    }


    /**
     * Retrieves the default SharedPreference object used to store or read values in this app.
     */
    private SharedPreferences getSharedPreferencesInstance() {
        return PreferenceManager.getDefaultSharedPreferences(this);
    }


    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.

        switch (item.getItemId()) {
            case R.id.action_flag_event:
                //User chose the "Flag event" item.
                Intent flagEventIntent = new Intent(this, FlagEventActivity.class);
                startActivity(flagEventIntent);
                return true;

            case R.id.action_settings:
                // User chose the "Settings" item.
                if (SharedPreferencesHelper.getDataCollectionState(this)) {
                    Snackbar.make(mCoordinatorLayoutView, "Stop data collection before change settings.", Snackbar.LENGTH_LONG).show();
                } else {
                    final EditText view = new EditText(this);
                    view.setInputType(InputType.TYPE_CLASS_NUMBER);
                    new AlertDialog.Builder(this)
                            .setTitle("Settings access protected")
                            .setMessage("Enter admin pass:")
                            .setView(view)
                            .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    if (Constants.ADMIN_CODE == Integer.parseInt(view.getText().toString())) {
                                        startActivity(new Intent(DisplayActivity.this, SettingsActivity.class));
                                    } else {
                                        Snackbar.make(mCoordinatorLayoutView, "Incorrect admin password", Snackbar.LENGTH_LONG).show();
                                    }
                                }
                            })
                            .setNegativeButton("Cancel", null)
                            .show();
                }
                return true;

            case R.id.action_upload:
                String upload_confirmation_message = String.format("Before to confirm the upload, please check that:\n"
                        + "- The phones are connected to the chargers\n"
                        + "- The phones are connected to a WiFi network\n"
                        + "The upload could take a while. Please, do not use the phone while they are uploading.");
                new AlertDialog.Builder(this)
                        .setTitle(getResources().getString(R.string.upload_confirmation_title))
                        .setMessage(upload_confirmation_message)
                        .setPositiveButton("Confirm", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                startService(new Intent(DisplayActivity.this, DataLoggerService.class)
                                        .putExtra(Constants.COMMAND_SERVICE_INTENT_KEY, new CommandFUS().getMessage()));
                                menu.findItem(R.id.action_cancel_upload).setVisible(true);
                                menu.findItem(R.id.action_upload).setVisible(false);
                            }
                        })
                        .setNegativeButton("Cancel", null)
                        .show();
                return true;
            case R.id.action_cancel_upload:
                String cancel_confirmation_message = "Are you sure to cancel the upload?";
                new AlertDialog.Builder(this)
                        .setTitle(getResources().getString(R.string.cancel_confirmation_title))
                        .setMessage(cancel_confirmation_message)
                        .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                startService(new Intent(DisplayActivity.this, DataLoggerService.class)
                                        .putExtra(Constants.COMMAND_SERVICE_INTENT_KEY, new CommandFUC().getMessage()));
                                menu.findItem(R.id.action_upload).setVisible(true);
                                menu.findItem(R.id.action_cancel_upload).setVisible(false);
                            }
                        })
                        .setNegativeButton("No", null)
                        .show();
                return true;
            case R.id.action_pair:
                Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
                discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
                startActivity(discoverableIntent);
                return true;

            case R.id.action_stats:
                Intent showStatsIntent = new Intent(this, ShowStatsActivity.class);
                startActivity(showStatsIntent);
                return true;

            case R.id.action_about:
                Intent showAppInfo = new Intent(this, AboutActivity.class);
                startActivity(showAppInfo);
                return true;

            default:
                // If we got here, the user's action was not recognized.
                // Invoke the superclass to handle it.
                return super.onOptionsItemSelected(item);

        }

    }

    SharedPreferences.OnSharedPreferenceChangeListener sharedPrefsListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
        public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {

            if (key.equals(getResources().getString(R.string.pref_general_key_device_location))) {
                startService(new Intent(DisplayActivity.this, DataLoggerService.class)
                        .putExtra(Constants.COMMAND_SERVICE_INTENT_KEY, new CommandBTS().getMessage()));
            }

            if (key.equals(Constants.BLUETOOTH_STATE_KEY)) {
                refreshBluetoothLayout();
            }

            if (key.equals(Constants.BLUETOOTH_SLAVES_CONNECTED_KEY)) {
                refreshBluetoothSlavesLayout();
            }

            if (key.equals(Constants.DATA_COLLECTION_SESSION_OBJECT_KEY)) {
                if (SharedPreferencesHelper.getDeviceLocationValue(DisplayActivity.this) != Constants.DEVICE_LOCATION_HAND)
                    updateTextviewSwitch(SharedPreferencesHelper.getDataCollectionState(DisplayActivity.this), R.id.ui_data_collection_custom_text);
            }
        }
    };

    View.OnLongClickListener mClickUploadButton = new View.OnLongClickListener() {

        public boolean onLongClick(View v) {

            if (!SharedPreferencesHelper.getUploadServiceState(DisplayActivity.this)) {
                startService(new Intent(DisplayActivity.this, DataLoggerService.class)
                        .putExtra(Constants.COMMAND_SERVICE_INTENT_KEY, new CommandFUS().getMessage()));
            } else {
                startService(new Intent(DisplayActivity.this, DataLoggerService.class)
                        .putExtra(Constants.COMMAND_SERVICE_INTENT_KEY, new CommandFUC().getMessage()));
            }
            return true;
        }

    };

    private void refreshConnectivityTextview(String firstMessage, String secondMessage) {

        TextView textviewFirst = (TextView) findViewById(R.id.ui_connectivity_first_message);
        assert textviewFirst != null;
        textviewFirst.setText(firstMessage);
        TextView textviewSecond = (TextView) findViewById(R.id.ui_connectivity_second_message);
        assert textviewSecond != null;
        textviewSecond.setText(secondMessage);
    }


    /**********************************************************************************************/
    /**********************************************************************************************/
    /*                          Data logger service delegate methods                               */
    /**********************************************************************************************/
    /**********************************************************************************************/

    @Override
    public void onError(int errorCode) {
        Log.d(TAG, "::onError Receiving from DataLoggerService delegate the error code " + errorCode);

        switch (errorCode) {
            case Constants.UI_ERROR_CODE_EXTERNAL_STORAGE:
            case Constants.UI_ERROR_CODE_SENSORS_DISABLED:
            case Constants.UI_ERROR_CODE_COLLECTORS_START:
                setChecked(mDataCollectionButton, false);
                break;
            case Constants.UI_ERROR_CODE_FILE_UPLOAD:
                SharedPreferencesHelper.setUploadServiceState(this, false);
                refreshConnectivityTextview(
                        getResources().getString(R.string.ui_connectivity_first_message_default_text),
                        SharedPreferencesHelper.getDateLastUpload(this));
                break;
        }

        String errorMessage = SharedPreferencesHelper.getUiErrorMessage(this, errorCode);
        Snackbar.make(mCoordinatorLayoutView, errorMessage, Snackbar.LENGTH_LONG).show();
    }

    @Override
    public void onUploadProgress(int nbFilesUpload, int nbRemainingFilesUpload, String uploadRate, long pct) {
        if (SharedPreferencesHelper.getUploadServiceState(this)) {
            refreshConnectivityTextview(
                    "Processed " + (nbFilesUpload - nbRemainingFilesUpload) + " of " + nbFilesUpload + " files",
                    " Rate: " + uploadRate + " Pct: " + pct + "%"
            );
        }
    }

    @Override
    public void onUploadCancelled() {
        SharedPreferencesHelper.setUploadServiceState(this, false);
        refreshConnectivityTextview(
                getResources().getString(R.string.ui_connectivity_first_message_default_text),
                SharedPreferencesHelper.getDateLastUpload(this)
        );
    }

    @Override
    public void onUploadComplete() {
        SharedPreferencesHelper.setUploadServiceState(this, false);
        String dateFormat = getResources().getString(R.string.ui_connectivity_upload_file_date_dateformat);
        String date = new SimpleDateFormat(dateFormat).format(Calendar.getInstance().getTime());
        SharedPreferencesHelper.setDateLastUpload(this, date);
        refreshConnectivityTextview(
                getResources().getString(R.string.ui_connectivity_first_message_default_text),
                date
        );
    }


    @Override
    public boolean onLongClick(View v) {
        int id = v.getId();
        switch (id) {
            case R.id.ui_data_collection_button:
                if (!SharedPreferencesHelper.getDataCollectionState(DisplayActivity.this)) {
                    startService(new Intent(DisplayActivity.this, DataLoggerService.class)
                            .putExtra(Constants.COMMAND_SERVICE_INTENT_KEY,
                                    new CommandDCE(true).getMessage()));
                    setChecked(mDataCollectionButton, true);
                    MenuItem flagEventItem = menu.findItem(R.id.action_flag_event);
                    flagEventItem.setVisible(true);
                    updateTextviewSwitch(true, R.id.ui_data_collection_custom_text);
                    mLabelAnnotationButton.setEnabled(true);
                } else {
                    startService(new Intent(DisplayActivity.this, DataLoggerService.class)
                            .putExtra(Constants.COMMAND_SERVICE_INTENT_KEY,
                                    new CommandDCE(false).getMessage()));
                    setChecked(mDataCollectionButton, false);
                    MenuItem flagEventItem = menu.findItem(R.id.action_flag_event);
                    flagEventItem.setVisible(false);
                    updateTextviewSwitch(false, R.id.ui_data_collection_custom_text);
                    mLabelAnnotationButton.setEnabled(false);
                }
                break;
            case R.id.ui_label_annotation_button:
                if (!SharedPreferencesHelper.getLabelsAnnotationState(DisplayActivity.this)) {
                    startService(new Intent(DisplayActivity.this, DataLoggerService.class)
                            .putExtra(Constants.COMMAND_SERVICE_INTENT_KEY,
                                    new CommandLAE(true,
                                            SharedPreferencesHelper.getSelectedActivityLabel(DisplayActivity.this),
                                            SharedPreferencesHelper.getSelectedBodyPositionLabel(DisplayActivity.this),
                                            SharedPreferencesHelper.getSelectedLocationLabel(DisplayActivity.this)
                                    ).getMessage()
                            )
                    );
                    SharedPreferencesHelper.setLabelsAnnotationStartingTime(DisplayActivity.this, System.currentTimeMillis());
                    onLabelTimerStart(0);
                    setChecked(mLabelAnnotationButton, true);
                    updateTextviewSwitch(true, R.id.ui_label_annotation_custom_text);
                    mDataCollectionButton.setEnabled(false);
                } else {
                    long lengthLabelMillis = System.currentTimeMillis() - SharedPreferencesHelper.getLabelsAnnotationStartingTime(DisplayActivity.this);
                    SharedPreferencesHelper.addLabelAnnotationTime(DisplayActivity.this,
                            SharedPreferencesHelper.getAnnotatedActivityLabel(DisplayActivity.this),
                            (int) (lengthLabelMillis / 1000));

                    SharedPreferencesHelper.setLabelsAnnotationStartingTime(DisplayActivity.this, 0);
                    mLabelsChronometer.stop();
                    startService(new Intent(DisplayActivity.this, DataLoggerService.class)
                            .putExtra(Constants.COMMAND_SERVICE_INTENT_KEY,
                                    new CommandLAE(false).getMessage()
                            )
                    );
                    setChecked(mLabelAnnotationButton, false);
                    updateTextviewSwitch(false, R.id.ui_label_annotation_custom_text);
                    mDataCollectionButton.setEnabled(true);
                }
                break;
        }
        return true;
    }

}