/*
 * Copyright (c) 2015, Nordic Semiconductor
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, getActivity() list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, getActivity() list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from getActivity()
 * software without specific prior written permission.
 *
 * getActivity() SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 * USE OF getActivity() SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package no.nordicsemi.android.nrfbeacon.nearby.beacon;

import android.Manifest;
import android.app.Activity;
import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationManagerCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.CommonStatusCodes;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.nearby.Nearby;
import com.google.android.gms.nearby.messages.Message;
import com.google.android.gms.nearby.messages.MessageFilter;
import com.google.android.gms.nearby.messages.MessageListener;
import com.google.android.gms.nearby.messages.MessagesOptions;
import com.google.android.gms.nearby.messages.NearbyPermissions;
import com.google.android.gms.nearby.messages.Strategy;
import com.google.android.gms.nearby.messages.SubscribeOptions;
import com.google.sample.libproximitybeacon.Project;

import java.nio.charset.Charset;
import java.util.ArrayList;

import no.nordicsemi.android.nrfbeacon.nearby.common.EddystoneBeaconsAdapter;
import no.nordicsemi.android.nrfbeacon.nearby.MainActivity;
import no.nordicsemi.android.nrfbeacon.nearby.NearbyBackgroundService;
import no.nordicsemi.android.nrfbeacon.nearby.R;
import no.nordicsemi.android.nrfbeacon.nearby.common.BaseFragment;
import no.nordicsemi.android.nrfbeacon.nearby.settings.NearbySettingsActivity;
import no.nordicsemi.android.nrfbeacon.nearby.util.Utils;
import uk.co.deanwild.materialshowcaseview.MaterialShowcaseView;

public class BeaconsFragment extends BaseFragment implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener /*,
        PermissionRationaleDialogFragment.PermissionDialogListener*/ {

    public static final String EXTRA_ADAPTER_POSITION = "no.nordicsemi.android.nrfbeacon.extra.adapter_position";
    public static final String TAG = "BEACON";
    private static final String NEW_MESSAGE_FOUND = "no.nordicsemi.android.nrfbeacon.nearby.NEW_MESSAGE_FOUND";
    private static final String MESSAGE_LOST = "no.nordicsemi.android.nrfbeacon.nearby.MESSAGE_LOST";
    public static final String NEARBY_DEVICE_DATA = "NEARBY_DEVICE_DATA";

    private final static int OPEN_ACTIVITY_REQ = 195; // random
    private static final int REQUEST_NEARBY_SETTINGS = 252;
    private static final int REQUEST_PERMISSION_REQ_CODE = 76; // any 8-bit number
    private static final int REQUEST_ENABLE_BT = 1;
    private static final int REQUEST_RESOLVE_ERROR = 261; //random
    private static final int NOTIFICATION_ID = 1;
    public static final String NEARBY_SETTINGS_HELP = "NEARBY_SETTINGS_HELP";

    private ImageView mNearbyImage;
    private TextView mPermissions;
    private ImageView mNearbySettings;

    private int mSelectedTabPosition = 0;

    private boolean mResolvingError;
    private boolean mScanForNearbyInBackground = false;
    private boolean mNearbyPermissionGranted = false;

    public ArrayList<Message> mNearbyDevicesMessageList;

    private PendingIntent mPendingIntent;
    private Intent mParentIntent;

    private Context mContext;
    private GoogleApiClient mGoogleApiClient = null;
    private NotificationManagerCompat mNotificationManager;
    private EddystoneBeaconsAdapter mEddystoneBeaconsAdapter;
    private Project mProject;

    private final BroadcastReceiver mBackgroundScanReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            final Message message = intent.getParcelableExtra(action);
            switch (action) {
                case NEW_MESSAGE_FOUND:
                    updateBeaconsAdapter(message);
                    break;
                case MESSAGE_LOST:
                    removeLostNearbyMessage(new String(message.getContent()));
                    break;
            }
        }
    };


    @Override
    public void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mSelectedTabPosition = getArguments().getInt("index");
        }

        if(savedInstanceState != null){
            mSelectedTabPosition = savedInstanceState.getInt(EXTRA_ADAPTER_POSITION);
        }

        final MainActivity parent = (MainActivity) mContext;
        parent.setBeaconsFragment(this);
    }

    @Override
    public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
        View rootView =  inflater.inflate(R.layout.fragment_beacons_list, container, false);
        final ListView listView = (ListView) rootView.findViewById(R.id.listNearbyBeacons);
        mNearbyDevicesMessageList = new ArrayList<>();
        mEddystoneBeaconsAdapter = new EddystoneBeaconsAdapter(getActivity(), mNearbyDevicesMessageList);
        listView.setAdapter(mEddystoneBeaconsAdapter);
        mPermissions = (TextView) rootView.findViewById(R.id.ble_permission);
        mNearbyImage = (ImageView) rootView.findViewById(R.id.img_nearby);

        mParentIntent = new Intent(getActivity(), MainActivity.class);
        mNotificationManager = NotificationManagerCompat.from(getActivity());
        mScanForNearbyInBackground = PreferenceManager.getDefaultSharedPreferences(getActivity()).getBoolean(getString(R.string.nearby_settings_key), false);
       /* mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
                .addApi(Nearby.MESSAGES_API, new MessagesOptions.Builder().setPermissions(NearbyPermissions.BLE).build())
                .addConnectionCallbacks(this)
                //.addOnConnectionFailedListener(this)
                .enableAutoManage(getActivity(), this)
                .build();*/

        mPermissions.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                final String message = mPermissions.getText().toString();
                if(message.equals(getString(R.string.enable_ble))){
                    if(!isBleEnabled())
                        enableBle();
                }

            }
        });

        return rootView;
    }

    @Override
    public void onViewCreated(final View view, final Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        setHasOptionsMenu(true);
        getActivity().registerReceiver(mBluetoothStateChange, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
    }
    @Override
    public void onActivityCreated(final Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    }

    @Override
    public void onAttach(final Context context) {
        super.onAttach(context);
        mContext = context;
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.menu_nearby_settings, menu);

        //onOptionsItemSelected is handled here for the tool bar icon
        //because a view target has to be passed in to creating the material show case view
        MenuItem item = menu.findItem(R.id.action_nearby_settings);
        item.setActionView(R.layout.menu_nearby);
        mNearbySettings = (ImageView) item.getActionView();
        mNearbySettings.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent nearby_settings = new Intent(getActivity(), NearbySettingsActivity.class);
                startActivityForResult(nearby_settings, REQUEST_NEARBY_SETTINGS);
            }
        });
    }

    @Override
    public boolean onOptionsItemSelected(final MenuItem item) {
        //handled above
        return false;
    }

    @Override
    public void onStart() {
        super.onStart();
        getMetaData();
    }

    @Override
    public void onStop() {
        super.onStop();
        unsubscribe();
        disconnectFromGoogleApiClient();
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        getActivity().unregisterReceiver(mBluetoothStateChange);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        final MainActivity parent = (MainActivity) mContext;
        parent.setBeaconsFragment(null);

        LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(mBackgroundScanReceiver);

        //deallocating image resources
        mNearbyImage.setImageBitmap(null);
        mNearbyImage.setImageDrawable(null);
        if(mNearbySettings != null) {
            mNearbySettings.setImageBitmap(null);
            mNearbySettings.setImageDrawable(null);
        }
        mPermissions = null;
        mNotificationManager = null;
        mPendingIntent = null;
        mParentIntent = null;
        mNearbyDevicesMessageList = null;
        mEddystoneBeaconsAdapter = null;
    }

    private void getMetaData(){
        String TAG = "Example Meta-Data";
        try {
            ApplicationInfo applicationInfo = getActivity().getPackageManager().getApplicationInfo(getActivity().getPackageName(), PackageManager.GET_META_DATA);
            Bundle bundle = applicationInfo.metaData;
            String nearbyApiKey = bundle.getString("com.google.android.nearby.messages.API_KEY");
            if(!nearbyApiKey.equals(Utils.UTILS_API_KEY)){
                if (checkIfVersionIsMarshmallowOrAbove()) {
                    final String [] permissions = {Manifest.permission.ACCESS_COARSE_LOCATION};
                    boolean flag = ensurePermission(permissions);
                    Log.v("BEACON", "Permission flags: " + flag);
                } else {
                    if (!isBleEnabled()) {
                        final Intent bluetoothEnable = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                        startActivityForResult(bluetoothEnable, REQUEST_ENABLE_BT);
                    } else {
                        updateBlePermissionStatus(true);
                        //connectToGoogleApiClient();
                    }
                }


            } else {
                mPermissions.setText(getString(R.string.nearby_api_message));
            }
        } catch (PackageManager.NameNotFoundException e) {
            Log.e(TAG,
                    "Failed to load meta-data, NameNotFound: " + e.getMessage());
        } catch (NullPointerException e) {
            Log.e(TAG,
                    "Failed to load meta-data, NullPointer: " + e.getMessage());
        }
    }

    private void createShowcaseForNearbySettings(){
        if(((MainActivity)mContext).getTabPosition() == 0)
            new MaterialShowcaseView.Builder(getActivity())
                    .setTarget(mNearbySettings)
                    .setDismissText(getString(R.string.got_it))
                    .setContentText(getString(R.string.nearby_Settings_showcase))
                    .setDelay(1000)
                    .singleUse(NEARBY_SETTINGS_HELP)
                    .show();
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case REQUEST_NEARBY_SETTINGS:
                if (resultCode == Activity.RESULT_OK){
                    final boolean tutorials_enabled = data.getExtras().getBoolean("TUTORIALS_ENABLED", false);
                    if(tutorials_enabled){
                        createShowcaseForNearbySettings();
                    }
                    updateNearbyScanning();
                }
                break;
            case REQUEST_ENABLE_BT:
                if (resultCode == Activity.RESULT_OK) {
                    //connectToGoogleApiClient();
                } else {
                    updateBlePermissionStatus(false);
                }
                break;
            case REQUEST_RESOLVE_ERROR:
                if(resultCode == Activity.RESULT_OK) {
                    //connectToGoogleApiClient();
                }
                else {
                    updateNearbyPermissionStatus(false);
                    Toast.makeText(getActivity(), getString(R.string.grant_location_permission), Toast.LENGTH_SHORT).show();
                }
                break;
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case REQUEST_PERMISSION_REQ_CODE: {
                if(permissions.length > 0)
                    for(int i = 0; i < permissions.length; i++){
                        if(Manifest.permission.ACCESS_COARSE_LOCATION.equals(permissions[i])){
                            if(grantResults[i] == PackageManager.PERMISSION_GRANTED)
                                onPermissionGranted(Manifest.permission.ACCESS_COARSE_LOCATION);
                            else {
                                updateLocationPermissionStatus(false);
                                Toast.makeText(getActivity(), R.string.rationale_permission_denied, Toast.LENGTH_SHORT).show();
                            }
                        }
                    }
                break;
            }
        }
    }

    @Override
    protected void onPermissionGranted(final String permission) {
        // Now, when the permission is granted, we may start scanning for beacons.
        // We bind even if the FAB was clicked.
        if(Manifest.permission.ACCESS_COARSE_LOCATION.equalsIgnoreCase(permission)){
            /*if(!isBleEnabled()){
                enableBle();
            } else {
                updateBlePermissionStatus(true);
                connectToGoogleApiClient();
            }*/
            buildGoogleApiClient();
        } else {
            updateLocationPermissionStatus(false);
        }
    }

    private synchronized void buildGoogleApiClient() {
        if (mGoogleApiClient == null) {
            mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
                    .addApi(Nearby.MESSAGES_API/*, new MessagesOptions.Builder()
                            .setPermissions(NearbyPermissions.BLE)
                            .build()*/)
                    .addConnectionCallbacks(this)
                    .enableAutoManage(getActivity(), this)
                    .build();
        }
    }

    @Override
    public void onCancelRequestPermission() {
        super.onCancelRequestPermission();
        updateLocationPermissionStatus(false);
    }

    public void updateAdapter(boolean clearAdapter){
        if(clearAdapter)
            mEddystoneBeaconsAdapter.clear();
        mEddystoneBeaconsAdapter.notifyDataSetChanged();
    }

    public void updateBlePermissionStatus(boolean flag){
        if(!flag) {
            mPermissions.setText(getString(R.string.enable_ble));
            mPermissions.setVisibility(View.VISIBLE);
        } else {
            if(mNearbyPermissionGranted)
                mPermissions.setVisibility(View.GONE);
            else {
                updateNearbyPermissionStatus(mNearbyPermissionGranted);
            }
        }
    }

    public void updateLocationPermissionStatus(boolean locationPermissions){
        if(!locationPermissions) {
            mPermissions.setText(getString(R.string.grant_location_permission));
            mPermissions.setVisibility(View.VISIBLE);
        } else {
            if(isBleEnabled())
                mPermissions.setVisibility(View.GONE);
            else updateBlePermissionStatus(false);
        }
    }

    public void updateNearbyPermissionStatus(boolean flag){
        mNearbyPermissionGranted = flag;
        if(!flag) {
            mPermissions.setText(getString(R.string.grant_nearby_permission));
            mPermissions.setVisibility(View.VISIBLE);
        } else {
            mPermissions.setVisibility(View.GONE);
        }
    }

    /**
     * Checks whether the Bluetooth adapter is enabled.
     */
    private boolean isBleEnabled() {
        final BluetoothManager bm = (BluetoothManager) getActivity().getSystemService(Context.BLUETOOTH_SERVICE);
        final BluetoothAdapter ba = bm.getAdapter();
        return ba != null && ba.isEnabled();
    }

    /**
     * Tries to start Bluetooth adapter.
     */
    private void enableBle() {
        final Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
    }

    private void connectToGoogleApiClient(){
        checkGoogleApiClientConnectionStateAndSubscribe();
    }

    @Override
    public void onConnected(Bundle bundle) {
        Log.v(TAG, "Connected ");
        updateNearbyPermissionStatus(true);
        subscribe();
        //connectToGoogleApiClient();
    }

    @Override
    public void onConnectionSuspended(int i) {
        Log.v(TAG, "Connection susspended: " + i);
    }

    @Override
    public void onConnectionFailed(ConnectionResult result) {

        Log.v(TAG, "GoogleApiClient failed");
        if (result.hasResolution()) {
            try {
                result.startResolutionForResult(getActivity(), REQUEST_RESOLVE_ERROR);
            } catch (IntentSender.SendIntentException e) {
                e.printStackTrace();
            }
        } else {
            Log.v(TAG, "GoogleApiClient connection failed");
            updateNearbyPermissionStatus(false);
        }
    }


    public void checkGoogleApiClientConnectionStateAndSubscribe(){
        if(mGoogleApiClient != null && !mGoogleApiClient.isConnected()){
            if(!mGoogleApiClient.isConnecting()){
                mGoogleApiClient.connect();
            }
        } else {
            createShowcaseForNearbySettings();
            subscribe();
        }
    }

    private void subscribe() {

        readProjectInformation();
        Log.v(TAG, "Subscribing to beacons with namespace: " + mProject.getProjectNamespace());
        updateNearbyScanning();
        MessageFilter filter = new MessageFilter.Builder()
                //.includeNamespacedType(mProject.getProjectNamespace(), "string")
                .includeAllMyTypes()
                .build();

        if (mGoogleApiClient != null && !mGoogleApiClient.isConnected()) {
            if (!mGoogleApiClient.isConnecting()) {
                mGoogleApiClient.connect();
            }
        } else if (!mScanForNearbyInBackground) {
            SubscribeOptions options = new SubscribeOptions.Builder().setStrategy(Strategy.BLE_ONLY).setFilter(filter).build();
            Nearby.Messages.subscribe(mGoogleApiClient, mMessageListener, options).setResultCallback(new ResultCallback<Status>() {
                @Override
                public void onResult(@NonNull Status status) {
                    if (status.isSuccess()) {
                        Log.v(TAG, "Subscribed successfully for foreground scanning.");
                    } else {
                        Log.v(TAG, "Could not subscribe.");
                        //handleUnsuccessfulNearbyResult(status);
                    }
                }
            });

        } else {
            LocalBroadcastManager.getInstance(getActivity()).registerReceiver(mBackgroundScanReceiver, createIntentFilters());
            SubscribeOptions options = new SubscribeOptions.Builder().setStrategy(Strategy.BLE_ONLY).setFilter(filter).build();
            Nearby.Messages.subscribe(mGoogleApiClient, getPendingIntent(), options)
                    .setResultCallback(new ResultCallback<Status>() {
                        @Override
                        public void onResult(Status status) {
                            if (status.isSuccess()) {
                                Log.v(TAG, "Subscribed successfully for background scanning.");
                            } else {
                                Log.v(TAG, "Could not subscribe.");
                                handleUnsuccessfulNearbyResult(status);
                            }
                        }
                    });
        }
    }

    private void unsubscribe(){
        if(mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
            Nearby.Messages.unsubscribe(mGoogleApiClient, mMessageListener);
        }
    }

    private void disconnectFromGoogleApiClient(){

        /*if(mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
            unsubscribe();
            mGoogleApiClient.disconnect();
            Log.v(TAG, "is connected? " + mGoogleApiClient.isConnected());
        }*/
        mNearbyDevicesMessageList.clear();
        mNotificationManager.cancelAll();

    }

    private PendingIntent getPendingIntent() {
        PendingIntent pendingIntent = PendingIntent.getService(getActivity(), 0,
                getBackgroundSubscribeServiceIntent(), PendingIntent.FLAG_UPDATE_CURRENT);
        return pendingIntent;
    }

    public Intent getBackgroundSubscribeServiceIntent() {
        return new Intent(getActivity(), NearbyBackgroundService.class);
    }

    private void handleUnsuccessfulNearbyResult(Status status) {
        Log.v(TAG, "Processing error, status = " + status);
        if (mResolvingError) {
            // Already attempting to resolve an error.
            return;
        } else if (status.hasResolution()) {
            try {
                mResolvingError = true;
                status.startResolutionForResult(getActivity(),
                        REQUEST_RESOLVE_ERROR);
            } catch (IntentSender.SendIntentException e) {
                mResolvingError = false;
                Log.v(TAG, "Failed to resolve error status.", e);
            }
        } else {
            if (status.getStatusCode() == CommonStatusCodes.NETWORK_ERROR) {
                Toast.makeText(getActivity(),
                        "No connectivity, cannot proceed. Fix in 'Settings' and try again.",
                        Toast.LENGTH_LONG).show();
            } else {
                // To keep things simple, pop a toast for all other error messages.
                Toast.makeText(getActivity(), "Unsuccessful: " +
                        status.getStatusMessage(), Toast.LENGTH_LONG).show();
            }
        }
    }

    private final MessageListener mMessageListener = new MessageListener() {
        @Override
        public void onFound(Message message) {
            String nearbyMessage = new String(message.getContent(), Charset.forName("UTF-8"));
            Log.v(TAG, "Found message: " + message.getNamespace());
            displayNotification(message);
        }

        @Override
        public void onLost(Message message) {
            String nearbyMessage = new String(message.getContent(), Charset.forName("UTF-8"));
            Log.v(TAG, "Lost message: " + nearbyMessage);
            updateNotification(message);
        }
    };

    private void displayNotification(Message message){
        if (!checkIfnearbyDeviceAlreadyExists(new String(message.getContent(), Charset.forName("UTF-8")))) {
            Log.v(TAG, "Adding message");
            mNearbyDevicesMessageList.add(message);
            updateAdapter(false);
            Log.v(TAG, "count after adding: " + mNearbyDevicesMessageList.size());
            createNotification();
        }
    }

    private void createNotification() {

        if(mNearbyDevicesMessageList.size() == 0){
            mNotificationManager.cancelAll();
            return;
        }

        final ArrayList<Message> nearbyMessageList = loadNearbyMessageListForNotification();
        mParentIntent.putExtra(NEARBY_DEVICE_DATA, nearbyMessageList);
        mParentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        mPendingIntent = PendingIntent.getActivities(getActivity(), OPEN_ACTIVITY_REQ, new Intent[]{mParentIntent}, PendingIntent.FLAG_UPDATE_CURRENT);

        NotificationCompat.Builder mBuilder =
                new NotificationCompat.Builder(getActivity())
                        .setSmallIcon(R.drawable.ic_eddystone)
                        .setColor(ContextCompat.getColor(getActivity(), R.color.actionBarColor))
                        .setContentTitle(getString(R.string.app_name))
                        .setContentIntent(mPendingIntent);

        if(mNearbyDevicesMessageList.size() == 1) {
            mBuilder.setContentText(new String(mNearbyDevicesMessageList.get(0).getContent(), Charset.forName("UTF-8")));
        } else {
            NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle();
            inboxStyle.setBigContentTitle(getString(R.string.app_name));
            inboxStyle.setSummaryText(mNearbyDevicesMessageList.size() + " beacons found");
            mBuilder.setContentText(mNearbyDevicesMessageList.size() + " beacons found");
            for (int i = 0; i < mNearbyDevicesMessageList.size(); i++) {
                inboxStyle.addLine(new String(mNearbyDevicesMessageList.get(i).getContent(), Charset.forName("UTF-8")));
            }
            mBuilder.setStyle(inboxStyle);
        }
        mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
    }

    private void updateNotification(Message message){
        if (checkIfnearbyDeviceAlreadyExists(new String(message.getContent(), Charset.forName("UTF-8")))) {
            Log.v(TAG, "removing message: " + message);
            removeLostNearbyMessage(new String(message.getContent(), Charset.forName("UTF-8")));
            Log.v(TAG, "count after removing: " + mNearbyDevicesMessageList.size());
            createNotification();
        }
    }

    private ArrayList<Message> loadNearbyMessageListForNotification(){
        final ArrayList<Message> nearbyMessageList = new ArrayList<>();
        for(int i = 0; i < mNearbyDevicesMessageList.size(); i++){
            nearbyMessageList.add(mNearbyDevicesMessageList.get(i));
        }
        return  nearbyMessageList;
    }

    private boolean checkIfnearbyDeviceAlreadyExists(String nearbyDeviceMessage){
        String message;
        for(int i = 0; i < mNearbyDevicesMessageList.size(); i++){
            message = new String(mNearbyDevicesMessageList.get(i).getContent(), Charset.forName("UTF-8"));
            if(nearbyDeviceMessage.equals(message)){
                return true;
            }
        }
        return false;
    }

    private void updateBeaconsAdapter(Message message){
        if (!checkIfnearbyDeviceAlreadyExists(new String(message.getContent(), Charset.forName("UTF-8")))) {
            Log.v(TAG, "Adding message");
            mNearbyDevicesMessageList.add(message);
            updateAdapter(false);
        }
    }

    private void removeLostNearbyMessage(String nearbyDeviceMessage){
        String message;
        for(int i = 0; i < mNearbyDevicesMessageList.size(); i++){
            message = new String(mNearbyDevicesMessageList.get(i).getContent(), Charset.forName("UTF-8"));
            if(nearbyDeviceMessage.equals(message)){
                mNearbyDevicesMessageList.remove(i);
                updateAdapter(false);
                break;
            }
        }
    }

    public void updateNearbyScanning(){
        boolean flag = PreferenceManager.getDefaultSharedPreferences(getActivity()).getBoolean(getString(R.string.nearby_settings_key), false);
        if(mScanForNearbyInBackground != flag){
            mScanForNearbyInBackground = flag;
            /*unsubscribe();
            disconnectFromGoogleApiClient();*/
            mNotificationManager.cancelAll();
            mNearbyDevicesMessageList.clear();
            updateAdapter(true);
            //connectToGoogleApiClient();
        }
    }

    private IntentFilter createIntentFilters() {
        final IntentFilter filter = new IntentFilter();
        filter.addAction(NEW_MESSAGE_FOUND);
        filter.addAction(MESSAGE_LOST);
        return filter;
    }

    public void readProjectInformation() {
        SharedPreferences sp = getActivity().getSharedPreferences(Utils.PROJECT_INFO, Context.MODE_PRIVATE);
        final String projectName = sp.getString(Utils.PROJECT_NAME, "");
        final String projectId = sp.getString(Utils.PROJECT_ID, "");
        final String projectNamespace = sp.getString(Utils.PROJECT_NAMESPACE, "");
        mProject = new Project(projectName, projectId, projectNamespace);
    }

    private final BroadcastReceiver mBluetoothStateChange = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            // This will be executed only once
            final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF);

            switch (state) {
                case BluetoothAdapter.STATE_TURNING_ON:
                case BluetoothAdapter.STATE_ON:
                    updateBlePermissionStatus(true);
                    break;
                case BluetoothAdapter.STATE_TURNING_OFF:
                case BluetoothAdapter.STATE_OFF:
                    updateBlePermissionStatus(false);
                    break;
            }
        }
    };

    private boolean checkIfVersionIsMarshmallowOrAbove() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
    }
}