package com.app.simplitend.apputils;

import static com.app.simplitend.articles.ArticleShowerActivity.ARTICLE_TITLE;
import static com.app.simplitend.articles.ArticleShowerActivity.ARTICLE_URL_KEY;
import static com.app.simplitend.callwhitelisting.CallService.CONTACT_WHITE_LISTING_TAG;
import static com.app.simplitend.patientgeofencing.GeoFenceHelper.GEOFENCE_ID;
import static com.app.simplitend.patientgeofencing.GeoFenceHelper.GEOFENCE_TAG;

import android.Manifest;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.InsetDrawable;
import android.location.Address;
import android.location.Geocoder;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;

import androidx.annotation.NonNull;
import androidx.annotation.RawRes;

import com.app.simplitend.R;
import com.app.simplitend.appblocking.TopAppDetectionService;
import com.app.simplitend.articles.ArticleShowerActivity;
import com.app.simplitend.databinding.AlertDialogBinding;
import com.app.simplitend.databinding.DecisionBottomsheetBinding;
import com.app.simplitend.databinding.DoneBottomsheetBinding;
import com.app.simplitend.locationupdates.LocationService;
import com.app.simplitend.welcome.welcomepatient.fragments.contacts.mvvm.models.ContactData;
import com.app.simplitend.welcome.welcomepatient.mvvm.models.PatientData;
import com.bumptech.glide.Glide;
import com.google.android.gms.location.GeofencingClient;
import com.google.android.gms.location.LocationServices;
import com.google.android.material.bottomsheet.BottomSheetDialog;

import org.json.JSONArray;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.TimeZone;

public abstract class AppUtil {

    private static final String TAG = "AppUtil";

    public static final String NOTIFICATION_ACTION = "com.simplitend.NOTIFICATION_ACTION";

    // fields
    public static final String PATIENT_DETAILS = "user_details";
    public static final String CAREGIVER_DETAILS = "caregiver_details";

    public static final String PATIENT_TOKEN = "user_token";
    public static final String CAREGIVER_TOKEN = "caregiver_token";

    public static final String CG_APP_SECURITY = "cg_app_security";

    public static final int NOT_ASKED_CG_SECURITY = 2;
    public static final int CG_NO_SECURITY_NEEDED = 3;
    public static final int CG_SECURITY_NEEDED = 4;

    public static final String CG_REGISTRATION_COMPLETE = "cg_registration_complete";

    public static final String PATIENT_UID = "patient_uid";

    public static final String IS_PATIENT_LOGGED_IN = "patient_logged_in";

    public static final String WHITE_LISTED_CONTACTS = "white_listed_contacts";

    // util functions

    // closes keyboard
    public static void closeKeyboard(Activity activity) {
        if (activity != null) {
            View view = activity.getCurrentFocus();
            if (view != null) {
                InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
            }
        }
    }

    // show decision dialog
    public static void showSOSDecision(@NonNull Context context,
                                       @NonNull String decisionText,
                                       @NonNull String positiveText, @NonNull String negativeText,
                                       View.OnClickListener positiveClickListener,
                                       View.OnClickListener negativeClickListener) {

        DecisionBottomsheetBinding binding = DecisionBottomsheetBinding.inflate(LayoutInflater.from(context));

        BottomSheetDialog bsd = new BottomSheetDialog(context, R.style.BottomSheetDialog);
        bsd.setContentView(binding.getRoot());
        bsd.setCancelable(true);

        binding.text.setText(decisionText);

        binding.positiveBtn.setText(positiveText);
        binding.negativeBtn.setText(negativeText);

        binding.negativeBtn.setOnClickListener(v -> {
            bsd.dismiss();
            negativeClickListener.onClick(v);
        });

        binding.positiveBtn.setOnClickListener(v -> {
            bsd.dismiss();
            positiveClickListener.onClick(v);
        });

        bsd.show();

    }

    public static void showAnimateDBS(@NonNull Context context,
                                      @NonNull String title,
                                      @RawRes int rawRes, long doneInterval,
                                      @NonNull View.OnClickListener doneListener) {
        DoneBottomsheetBinding binding = DoneBottomsheetBinding.inflate(LayoutInflater.from(context));

        BottomSheetDialog bsd = new BottomSheetDialog(context, R.style.BottomSheetDialog);
        bsd.setContentView(binding.getRoot());
        bsd.setCancelable(false);

        binding.text.setText(title);

        Glide.with(context)
                .asGif()
                .load(rawRes)
                .into(binding.doneAnim);

        bsd.show();

        new Handler().postDelayed(() -> {

            bsd.dismiss();
            doneListener.onClick(null);

        }, doneInterval);
    }

    // Show alert dialog
    public static synchronized void showAlert(@NonNull Context context,
                                              @NonNull String title, @NonNull String message,
                                              @NonNull String positiveText, @NonNull DialogInterface.OnClickListener positiveClickListener,
                                              String negativeText, DialogInterface.OnClickListener negativeClickListener) {

        AlertDialogBinding binding = AlertDialogBinding.inflate(LayoutInflater.from(context));
        Dialog dialog = new Dialog(context);
        dialog.setContentView(binding.getRoot());

        try {
            ColorDrawable back = new ColorDrawable(Color.TRANSPARENT);
            InsetDrawable inset = new InsetDrawable(back, 30);
            dialog.getWindow().setBackgroundDrawable(inset);
        } catch (Exception e) {
            // do nothing
        }

        try {
            WindowManager.LayoutParams layoutParams = dialog.getWindow().getAttributes();
            layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
            layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
            dialog.getWindow().setAttributes(layoutParams);
        }catch (Exception e){
            // do nothing
        }

        final DialogInterface DIALOG_INTERFACE = new DialogInterface() {
            @Override
            public void cancel() {
                dialog.dismiss();
            }

            @Override
            public void dismiss() {
                dialog.dismiss();
            }
        };

        binding.title.setText(title);
        binding.susbTitle.setText(message);
        binding.positiveBtn.setText(positiveText);
        binding.positiveBtn.setOnClickListener(v -> {
            dialog.dismiss();
            positiveClickListener.onClick(DIALOG_INTERFACE, 0);
        });

        if (negativeText != null){
            binding.negativeBtn.setVisibility(View.VISIBLE);
            binding.negativeBtn.setText(negativeText);
            binding.negativeBtn.setOnClickListener(v -> {
                dialog.dismiss();
                if (negativeClickListener != null){
                    negativeClickListener.onClick(DIALOG_INTERFACE, 0);
                }
            });
        }

        dialog.show();

//        AlertDialog.Builder alertBuilder = new AlertDialog.Builder(context);
//
//        alertBuilder.setTitle(title);
//        alertBuilder.setMessage(message);
//
//        alertBuilder.setPositiveButton(positiveText, positiveClickListener /* Call back*/);
//
//        if (negativeText != null && negativeClickListener != null) {
//            // Negative button
//            alertBuilder.setNegativeButton(negativeText, negativeClickListener);
//        }
//
//        alertBuilder.create().show(); // Showing alert dialog
    }

    // fetches the country codes from the JSON file in raw directory
    public static ArrayList<String> loadCountryCodeDropDown(Context context) {

        ArrayList<String> countryCodeList = new ArrayList<>();

        try {

            String countryCodeStr = readCountryCodes(context);
            JSONArray jsonArray = new JSONArray(countryCodeStr);

            for (int i = 0; i < jsonArray.length(); i++) {

                JSONObject code = jsonArray.getJSONObject(i);

                countryCodeList.add(code.getString("dial_code"));

            }

        } catch (Exception e) {

            // if cannot load all country codes showing only india's dial code
            countryCodeList.add("+91");
            countryCodeList.add("+1");

            Log.e(TAG, "loadCountryCodeDropDown: ", e);
        }

        return countryCodeList;
    }

    public static String readCountryCodes(Context context) throws IOException {
        StringBuilder returnString = new StringBuilder();

        InputStream fIn = context.getResources().openRawResource(R.raw.country_code);
        InputStreamReader isr = new InputStreamReader(fIn);
        BufferedReader input = new BufferedReader(isr);

        String line = "";

        while ((line = input.readLine()) != null) {
            returnString.append(line);
        }

        try {
            isr.close();

            if (fIn != null) fIn.close();

            input.close();

        } catch (Exception e) {
            Log.e(TAG, "readCountryCodes: ", e);
        }

        return returnString.toString();
    }

    public static String formatDate(@NonNull String fromFormat, // mm-dd-yyyy
                                    @NonNull String toFormat, // yyyy-mm-dd
                                    String fromDate){ // 09-02-2001

        try {
            SimpleDateFormat fromSdf = new SimpleDateFormat(fromFormat, Locale.getDefault());
            SimpleDateFormat toSdf = new SimpleDateFormat(toFormat, Locale.getDefault());

            Date date = fromSdf.parse(fromDate);
            return toSdf.format(date);
        }catch (Exception e){
            return null;
        }
    }

    @NonNull
    public static String getTimeZone(){
        TimeZone timeZone = TimeZone.getDefault();
        // Getting the GMT offset in milliseconds
        int gmtOffsetMillis = timeZone.getOffset(Calendar.getInstance().getTimeInMillis());
        // Converting milliseconds to hours and minutes
        int hours = gmtOffsetMillis / 3600000;
        int minutes = (gmtOffsetMillis % 3600000) / 60000;

        return "GMT" + (gmtOffsetMillis >= 0 ? "+" : "") + hours + ":" + String.format(Locale.getDefault(), "%02d", minutes);
    }

    public static void callPhone(Activity activity, String phone_number){
        if (activity.checkSelfPermission(Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED){
            Intent intent = new Intent(Intent.ACTION_CALL, Uri.fromParts("tel",
                    phone_number, null));
            activity.startActivity(intent);
        }else{
            dialPhone(activity, phone_number);
        }
    }

    public static void dialPhone(Context activity, String phone_number) {
        Intent intent = new Intent(Intent.ACTION_DIAL, Uri.fromParts("tel",
                phone_number, null));
        if (activity != null) activity.startActivity(intent);
    }

    public static void messageNumber(Context activity, String phone_number) {
        Uri uri = Uri.parse("smsto:" + phone_number);
        Intent intent = new Intent(Intent.ACTION_SENDTO, uri);
//            intent.putExtra("sms_body", "The SMS text");
        if (activity != null) activity.startActivity(intent);
    }

    public static String getCompleteAddress(Context context, double LATITUDE, double LONGITUDE) {
        String strAdd = null;
        Geocoder geocoder = new Geocoder(context, Locale.getDefault());
        try {
            List<Address> addresses = geocoder.getFromLocation(LATITUDE, LONGITUDE, 1);
            if (addresses != null) {
                Address returnedAddress = addresses.get(0);
                StringBuilder strReturnedAddress = new StringBuilder("");

                for (int i = 0; i <= returnedAddress.getMaxAddressLineIndex(); i++) {
                    strReturnedAddress.append(returnedAddress.getAddressLine(i)).append("\n");
                }
                strAdd = strReturnedAddress.toString();
            }
        } catch (Exception e) {
            // do nothing
        }

        return strAdd;
    }

    public static void openLink(Activity activity,
                                @NonNull String link, @NonNull String title){
        try {
            Intent intent = new Intent(activity, ArticleShowerActivity.class);
            intent.putExtra(ARTICLE_URL_KEY, link);
            intent.putExtra(ARTICLE_TITLE, title);
            activity.startActivity(intent);
        } catch (Exception e) {
            // do nothing
        }
    }


    // ********************* USER DATA UTILS ******************************************

    public static void savePatientData(String token, int patient_uid, Context context, boolean isLoggedIn) {
        SharedPreferences sp = context.getSharedPreferences(PATIENT_DETAILS, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();

        editor.putString(PATIENT_TOKEN, token);
        editor.putInt(PATIENT_UID, patient_uid);
        editor.putBoolean(IS_PATIENT_LOGGED_IN, isLoggedIn);

        editor.apply();

        Log.d(TAG, "saveToken: user token saved successful");

    }

    public static String getPatientToken(Context context) {
        SharedPreferences sp = context.getSharedPreferences(PATIENT_DETAILS, Context.MODE_PRIVATE);
        return sp.getString(PATIENT_TOKEN, "");
    }

    public static int getPatientUid(Context context) {
        SharedPreferences sp = context.getSharedPreferences(PATIENT_DETAILS, Context.MODE_PRIVATE);
        return sp.getInt(PATIENT_UID, -1);
    }

    public static boolean isPatientLoggedIn(Context context) {
        SharedPreferences sp = context.getSharedPreferences(PATIENT_DETAILS, Context.MODE_PRIVATE);
        return sp.getBoolean(IS_PATIENT_LOGGED_IN, false);
    }

    public static void patientSignOut(Context context) {
        AppUtil.savePatientData(null, -1, context, false);

        PatientDataCache.setPatientData(null);
        PatientDataCache.setContactList(null);

        // turning off app_blocking accessibility permission
        Intent stop_accessibility_intent = new Intent(context, TopAppDetectionService.class);
        stop_accessibility_intent.setAction(TopAppDetectionService.STOP_ACCESSIBILITY_SERVICE);
        context.startService(stop_accessibility_intent);

        setShouldShowFuaDialog(context, true);

        // removing contact listing
        setWhiteListedContacts(context, null);

        // geofence details clear
        updatePatientGeofence(context, null, null, null, null, null);
        updatePatientGeofenceChatsCred(context, -1, -1, -1);

        // removing geofence of same tag
        removeGeofence(context);

        // clearing location updates
        Intent intent = new Intent(context, LocationService.class);
        intent.setAction(LocationService.ACTION_STOP_LOCATION_UPDATES);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            context.startForegroundService(intent);
        }else {
            context.startService(intent);
        }
    }

    public static void removeGeofence(Context context) {
        Log.d(GEOFENCE_TAG, "REMOVING GEOFENCE ID: " + GEOFENCE_ID);
        GeofencingClient geofencingClient = LocationServices.getGeofencingClient(context);
        geofencingClient.removeGeofences(Collections.singletonList(GEOFENCE_ID)).addOnSuccessListener(v -> {
            Log.d(GEOFENCE_TAG, "patientSignOut: GEOFENCE REMOVED");
        }).addOnFailureListener(v -> {
            Log.d(GEOFENCE_TAG, "patientSignOut: GEOFENCE COULDN'T BE REMOVE " + v);
        });
    }

    public static void saveCgData(String token, int patient_id, Context context) {
        SharedPreferences sp = context.getSharedPreferences(CAREGIVER_DETAILS, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();

        editor.putString(CAREGIVER_TOKEN, token);

        editor.apply();

        // now saving patient data
        // This is important as there are instances where patient data such as patient id and patient_token is required
        savePatientData(token, patient_id, context, false);

        Log.d(TAG, "saveToken: caregiver token saved successful");

    }

    public static String getCgToken(Context context) {
        SharedPreferences sp = context.getSharedPreferences(CAREGIVER_DETAILS, Context.MODE_PRIVATE);
        return sp.getString(CAREGIVER_TOKEN, null);
    }

    public static void setWantSecurityFlag(Context context, int watSecurity) {
        SharedPreferences sp = context.getSharedPreferences(CAREGIVER_DETAILS, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();

        editor.putInt(CG_APP_SECURITY, watSecurity);

        editor.apply();
    }

    public static int getWantSecurityFlag(Context context) {
        SharedPreferences sp = context.getSharedPreferences(CAREGIVER_DETAILS, Context.MODE_PRIVATE);
        return sp.getInt(CG_APP_SECURITY, NOT_ASKED_CG_SECURITY);
    }

    public static boolean isRegistrationComplete(Context context){
        SharedPreferences sp = context.getSharedPreferences(CAREGIVER_DETAILS, Context.MODE_PRIVATE);
        return sp.getBoolean(CG_REGISTRATION_COMPLETE, false);
    }

    public static void setCgRegistrationComplete(Context context, boolean registrationComplete){
        SharedPreferences sp = context.getSharedPreferences(CAREGIVER_DETAILS, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();

        editor.putBoolean(CG_REGISTRATION_COMPLETE, registrationComplete);

        editor.apply();
    }

    public static void cgSignOut(Context context) {
        saveCgData(null, -1, context);
        setWantSecurityFlag(context, NOT_ASKED_CG_SECURITY);

        CaregiverDataCache.setCareGiverData(null);

        // setting up notification prefs default to yes
        setCgNotificationPref(context, MEDICATIONS_NOTIFICATIONS, true);
        setCgNotificationPref(context, MEDICATION_REFILL_NOTIFICATIONS, true);
        setCgNotificationPref(context, ACTIVITY_NOTIFICATIONS, true);
        setCgNotificationPref(context, SOS_NOTIFICATIONS, true);
        setCgNotificationPref(context, DIRECTIONS_NOTIFICATIONS, true);
        setCgNotificationPref(context, GEOFENCE_NOTIFICATIONS, true);
    }

    // caregiver notification preference
    public static final String MEDICATIONS_NOTIFICATIONS = "medications_notifications";
    public static final String MEDICATION_REFILL_NOTIFICATIONS = "MEDICATION_REFILL_notifications";
    public static final String ACTIVITY_NOTIFICATIONS = "ACTIVITY_notifications";
    public static final String GEOFENCE_NOTIFICATIONS = "GEOFENCE_notifications";
    public static final String SOS_NOTIFICATIONS = "SOS_notifications";
    public static final String DIRECTIONS_NOTIFICATIONS = "DIRECTIONS_notifications";

    public static void setCgNotificationPref(Context context,
                                               String notification,
                                               boolean check){
        SharedPreferences sp = context.getSharedPreferences(CAREGIVER_DETAILS, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();

        editor.putBoolean(notification, check);

        editor.apply();
    }

    public static boolean getCgNotificationPref(Context context,
                                                String notification){
        SharedPreferences sp = context.getSharedPreferences(CAREGIVER_DETAILS, Context.MODE_PRIVATE);
        return sp.getBoolean(notification, true);
    }

    private static final String FUA_DIALOG = "FUA_dialog";

    public static void setShouldShowFuaDialog(Context context, boolean b){
        SharedPreferences sp = context.getSharedPreferences(CAREGIVER_DETAILS, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.putBoolean(FUA_DIALOG, b);
        editor.apply();
    }
    public static boolean shouldShowFUADialog(Context context){
        SharedPreferences sp = context.getSharedPreferences(CAREGIVER_DETAILS, Context.MODE_PRIVATE);
        return sp.getBoolean(FUA_DIALOG, true);
    }

    // patient geofencing
    private static final String PATIENT_GEOFENCE_RADIUS = "patient_geofence_radius";
    private static final String PATIENT_GEOFENCE_RADIUS_UNIT = "patient_geofence_radius_unit";
    private static final String PATIENT_GEOFENCE_LATITUDE = "patient_geofence_latitude";
    private static final String PATIENT_GEOFENCE_LONGITUDE = "patient_geofence_longitude";
    private static final String PATIENT_GEOFENCE_MESSAGE = "patient_geofence_message";

    private static final String PATIENT_GEOFENCE_CG_ID = "pg_cg_uid";
    private static final String PATIENT_GEOFENCE_CHANNEL_ID = "pg_channel_uid";
    private static final String PATIENT_GEOFENCE_PATIENT_PRINCIPLE_ID = "pg_patient_geofence_uid";

    public static void updatePatientGeofenceChatsCred(Context context,
                                             int cg_id,
                                             int channel_id, int patient_principal_id){
        SharedPreferences sp = context.getSharedPreferences(PATIENT_DETAILS, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();

        editor.putInt(PATIENT_GEOFENCE_CG_ID, cg_id);
        editor.putInt(PATIENT_GEOFENCE_CHANNEL_ID, channel_id);
        editor.putInt(PATIENT_GEOFENCE_PATIENT_PRINCIPLE_ID, patient_principal_id);

        editor.apply();
    }

    // return array of size 3
    // index            content
    //   0       ->     patient_id
    //   1       ->     caregiver_id
    //   2       ->     channel_id
    //   3       ->     patient_principal_id
    @NonNull
    public static int[] getPatientGeofenceChatCred(Context context){
        SharedPreferences sp = context.getSharedPreferences(PATIENT_DETAILS, Context.MODE_PRIVATE);
        return new int[]{sp.getInt(PATIENT_UID, -1),
                sp.getInt(PATIENT_GEOFENCE_CG_ID, -1),
                sp.getInt(PATIENT_GEOFENCE_CHANNEL_ID, -1),
                sp.getInt(PATIENT_GEOFENCE_PATIENT_PRINCIPLE_ID, -1)};
    }

    public static void updatePatientGeofence(Context context,
                                             String lat,
                                             String lng,
                                             String radius,
                                             String radius_unit,
                                             String message) {
        SharedPreferences sp = context.getSharedPreferences(PATIENT_DETAILS, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();

        editor.putString(PATIENT_GEOFENCE_LATITUDE, lat);
        editor.putString(PATIENT_GEOFENCE_LONGITUDE, lng);
        editor.putString(PATIENT_GEOFENCE_RADIUS, radius);
        editor.putString(PATIENT_GEOFENCE_RADIUS_UNIT, radius_unit);
        editor.putString(PATIENT_GEOFENCE_MESSAGE, message);

        editor.apply();
        Log.d(GEOFENCE_TAG, "updatePatientGeofence: UPDATED");
    }

    public static String[] getPatientLatLng(Context context) {
        SharedPreferences sp = context.getSharedPreferences(PATIENT_DETAILS, Context.MODE_PRIVATE);
        return new String[]{sp.getString(PATIENT_GEOFENCE_LATITUDE, null), sp.getString(PATIENT_GEOFENCE_LONGITUDE, null)};
    }

    public static String getPatientGeofenceRadius(Context context) {
        SharedPreferences sp = context.getSharedPreferences(PATIENT_DETAILS, Context.MODE_PRIVATE);
        return sp.getString(PATIENT_GEOFENCE_RADIUS, null);
    }

    public static String getPatientGeofenceRadiusUnit(Context context) {
        SharedPreferences sp = context.getSharedPreferences(PATIENT_DETAILS, Context.MODE_PRIVATE);
        return sp.getString(PATIENT_GEOFENCE_RADIUS_UNIT, null);
    }

     public static String getPatientGeofenceMessage(Context context) {
        SharedPreferences sp = context.getSharedPreferences(PATIENT_DETAILS, Context.MODE_PRIVATE);
        return sp.getString(PATIENT_GEOFENCE_MESSAGE, null);
    }

    public static void setWhiteListedContacts(Context context, List<ContactData> contactList){
        Set<String> contactSet;

        if (contactList != null) {
            contactSet = new HashSet<>();
            for (ContactData contactData: contactList){
                contactSet.add(contactData.phone_number);

                if (contactData.extra_phone_numbers != null){
                    String[] extra_phone_numbers = contactData.extra_phone_numbers.split(",");
                    contactSet.addAll(Arrays.asList(extra_phone_numbers));
                }
            }
        } else {
            contactSet = null;
        }

        SharedPreferences sp = context.getSharedPreferences(PATIENT_DETAILS, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();

        editor.putStringSet(WHITE_LISTED_CONTACTS, contactSet);

        editor.apply();

        Log.d(CONTACT_WHITE_LISTING_TAG, "CONTACT_LIST_UPDATED : " + contactSet);
    }

    public static Set<String> getWhiteListedContacts(Context context){
        SharedPreferences sp = context.getSharedPreferences(PATIENT_DETAILS, Context.MODE_PRIVATE);
        return sp.getStringSet(WHITE_LISTED_CONTACTS, null);
    }

    public static boolean shouldAddPatientGeofence(@NonNull Context context,
                                                   @NonNull String remote_radius,
                                                   @NonNull String remote_radius_unit,
                                                   @NonNull PatientData data) {

        String local_radius = getPatientGeofenceRadius(context);

        if (local_radius != null) {
            try {
                float local_radius_f = Float.parseFloat(local_radius);
                float remote_radius_f = Float.parseFloat(remote_radius);

                if (local_radius_f != remote_radius_f) {
                    // radius' are different
                    // thus, should add geofence
                    return true;
                }
            } catch (Exception e) {
                // do nothing
            }
        }

        // radius is equal thus, checking for unit of the radius
        String local_radius_unit = getPatientGeofenceRadiusUnit(context);
        if (!remote_radius_unit.equals(local_radius_unit)) {
            // remote radius units are different
            // thus, should add geofence
            return true;
        }

        // checking for lat lng
        String[] local_lat_lng = getPatientLatLng(context);
        if (data.lat != null && data.lng != null) {
            if (!data.lat.equals(local_lat_lng[0]) || !data.lng.equals(local_lat_lng[1])) {
                // remote lat lng has changed
                return true;
            }
        }

        return false;
    }
}
