/**
 * GPSActivity - Java Class for Android
 * Created by G.Capelli (BasicAirData) on 5/5/2016
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 */

package eu.basicairdata.graziano.gpslogger;

import android.Manifest;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomSheetBehavior;
import android.support.design.widget.TabLayout;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.preference.PreferenceManager;
import android.support.v7.view.ActionMode;
import android.support.v7.view.ContextThemeWrapper;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.widget.Toast;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class GPSActivity extends AppCompatActivity {

    private static final int REQUEST_ID_MULTIPLE_PERMISSIONS = 1;

    private final GPSApplication GPSApp = GPSApplication.getInstance();

    private Toolbar toolbar;
    private TabLayout tabLayout;
    private ViewPager viewPager;
    private ActionMode actionMode;
    private View bottomSheet;
    private MenuItem menutrackfinished = null;
    private int activeTab = 1;
    final Context context = this;

    private boolean prefKeepScreenOn = true;
    private boolean show_toast_grant_storage_permission = false;
    private int theme;

    private BottomSheetBehavior mBottomSheetBehavior;

    Toast ToastClickAgain;


    @Override
    public void onRestart(){
        Log.w("myApp", "[#] " + this + " - onRestart()");

        if (Integer.valueOf(PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getString("prefColorTheme", "2")) != theme) {
            Log.w("myApp", "[#] GPSActivity.java - it needs to be recreated (Theme changed)");
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                // Normal behaviour for Android 5 +
                this.recreate();
            } else {
                // Workaround to a bug on Android 4.4.X platform (google won't fix because Android 4.4 is obsolete)
                // Android 4.4.X: taskAffinity & launchmode='singleTask' violating Activity's lifecycle
                // https://issuetracker.google.com/issues/36998700
                finish();
                startActivity(new Intent(this, getClass()));
            }
            overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
        }
        super.onRestart();
    }


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.w("myApp", "[#] " + this + " - onCreate()");

        setTheme(R.style.MyMaterialTheme);
        theme = Integer.valueOf(PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getString("prefColorTheme", "2"));

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_gps);
        toolbar = findViewById(R.id.id_toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(false);
        viewPager = findViewById(R.id.id_viewpager);
        viewPager.setOffscreenPageLimit(3);

        setupViewPager(viewPager);

        tabLayout = findViewById(R.id.id_tablayout);
        tabLayout.setTabMode(TabLayout.MODE_FIXED);
        tabLayout.setupWithViewPager(viewPager);

        tabLayout.addOnTabSelectedListener(
                new TabLayout.ViewPagerOnTabSelectedListener(viewPager) {
                    @Override
                    public void onTabSelected(TabLayout.Tab tab) {
                        super.onTabSelected(tab);
                        activeTab = tab.getPosition();
                        GPSApp.setGPSActivity_activeTab(activeTab);
                        updateBottomSheetPosition();
                        ActivateActionModeIfNeeded();
                    }
                });

        bottomSheet = findViewById( R.id.id_bottomsheet );

        mBottomSheetBehavior = BottomSheetBehavior.from(bottomSheet);
        mBottomSheetBehavior.setHideable (false);

        ToastClickAgain = Toast.makeText(this, getString(R.string.toast_track_finished_click_again), Toast.LENGTH_SHORT);
    }


    @Override
    public void onStart() {
        Log.w("myApp", "[#] " + this + " - onStart()");
        super.onStart();
        activeTab = tabLayout.getSelectedTabPosition();
        GPSApp.setGPSActivity_activeTab(activeTab);
    }


    @Override
    public void onStop() {
        Log.w("myApp", "[#] " + this + " - onStop()");
        super.onStop();
    }


    @Override
    public void onResume() {
        Log.w("myApp", "[#] " + this + " - onResume()");
        super.onResume();

        // Workaround for Nokia Devices, Android 9
        // https://github.com/BasicAirData/GPSLogger/issues/77
        if (EventBus.getDefault().isRegistered(this)) {
            //Log.w("myApp", "[#] GPSActivity.java - EventBus: GPSActivity already registered");
            EventBus.getDefault().unregister(this);
        }

        EventBus.getDefault().register(this);
        LoadPreferences();
        EventBus.getDefault().post(EventBusMSG.APP_RESUME);
        if (menutrackfinished != null) menutrackfinished.setVisible(!GPSApp.getCurrentTrack().getName().equals(""));

        // Check for Location runtime Permissions (for Android 23+)
        if (!GPSApp.isLocationPermissionChecked()) {
            CheckLocationPermission();
            GPSApp.setLocationPermissionChecked(true);
        }

        ActivateActionModeIfNeeded();

        if (GPSApp.FlagExists(GPSApp.FLAG_RECORDING) && !GPSApp.getRecording()) {
            // The app is crashed in background
            Log.w("myApp", "[#] GPSActivity.java - THE APP HAS BEEN KILLED IN BACKGROUND DURING A RECORDING !!!");
            GPSApp.FlagRemove(GPSApp.FLAG_RECORDING);

            AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(this, R.style.StyledDialog));
            if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                builder.setMessage(getResources().getString(R.string.dlg_app_killed) + "\n\n" + getResources().getString(R.string.dlg_app_killed_description));
                builder.setNeutralButton(R.string.open_android_app_settings, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        Intent intent = new Intent();
                        intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                        Uri uri = Uri.fromParts("package", getPackageName(), null);
                        intent.setData(uri);
                        try {
                            startActivity(intent);
                        } catch (Exception e) {
                            //Log.w("myApp", "[#] GPSActivity.java - Unable to open the settings screen");
                        }
                        dialog.dismiss();
                    }
                });
            }
            else builder.setMessage(getResources().getString(R.string.dlg_app_killed));
            builder.setIcon(android.R.drawable.ic_menu_info_details);
            builder.setPositiveButton(R.string.about_ok, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int id) {
                    dialog.dismiss();
                }
            });

            AlertDialog dialog = builder.create();
            dialog.show();
        }

        if (GPSApp.isJustStarted() && (GPSApp.getCurrentTrack().getNumberOfLocations() + GPSApp.getCurrentTrack().getNumberOfPlacemarks() > 0)) {
            Toast.makeText(this.context, getString(R.string.toast_active_track_not_empty), Toast.LENGTH_LONG).show();
            GPSApp.setJustStarted(false);
        } else GPSApp.setJustStarted(false);

        if (show_toast_grant_storage_permission) {
            Toast.makeText(this.context, getString(R.string.please_grant_storage_permission), Toast.LENGTH_LONG).show();
            show_toast_grant_storage_permission = false;
        }
    }


    @Override
    public void onPause() {
        Log.w("myApp", "[#] " + this + " - onPause()");
        EventBus.getDefault().post(EventBusMSG.APP_PAUSE);
        EventBus.getDefault().unregister(this);
        super.onPause();
    }


    @Override
    public void onBackPressed() {
        ShutdownApp();
    }


    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        updateBottomSheetPosition();
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main_menu, menu);
        return true;
    }


    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        menutrackfinished = menu.findItem(R.id.action_track_finished);
        menutrackfinished.setVisible(!GPSApp.getCurrentTrack().getName().equals(""));
        return true;
    }


    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();

        if (id == R.id.action_settings) {
            GPSApp.setHandlerTimer(60000);
            Intent intent = new Intent(this, SettingsActivity.class);
            startActivity(intent);
            return true;
        }
        if (id == R.id.action_track_finished) {
            if (GPSApp.getNewTrackFlag()) {
                // This is the second click
                GPSApp.setNewTrackFlag(false);
                GPSApp.setRecording(false);
                EventBus.getDefault().post(EventBusMSG.NEW_TRACK);
                ToastClickAgain.cancel();
                Toast.makeText(this, getString(R.string.toast_track_saved_into_tracklist), Toast.LENGTH_SHORT).show();
            } else {
                // This is the first click
                GPSApp.setNewTrackFlag(true); // Start the timer
                ToastClickAgain.show();
            }
            return true;
        }
        if (id == R.id.action_about) {
            // Show About Dialog
            FragmentManager fm = getSupportFragmentManager();
            FragmentAboutDialog aboutDialog = new FragmentAboutDialog();
            aboutDialog.show(fm, "");
            return true;
        }
        if (id == R.id.action_shutdown) {
            ShutdownApp();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }


    private void updateBottomSheetPosition() {
        activeTab = tabLayout.getSelectedTabPosition();
        if (activeTab != 2) {
            mBottomSheetBehavior.setPeekHeight(1);
            mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
            //Log.w("myApp", "[#] GPSActivity.java - mBottomSheetBehavior.setPeekHeight(" + bottomSheet.getHeight() +");");
            mBottomSheetBehavior.setPeekHeight(bottomSheet.getHeight());
        } else {
            mBottomSheetBehavior.setPeekHeight(1);
            mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED) ;
        }
    }


    private void setupViewPager(ViewPager viewPager) {
        ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
        adapter.addFragment(new FragmentGPSFix(), getString(R.string.tab_gpsfix));
        adapter.addFragment(new FragmentTrack(), getString(R.string.tab_track));
        adapter.addFragment(new FragmentTracklist(), getString(R.string.tab_tracklist));
        viewPager.setAdapter(adapter);
    }

    class ViewPagerAdapter extends FragmentPagerAdapter {
        private final List<Fragment> mFragmentList = new ArrayList<>();
        private final List<String> mFragmentTitleList = new ArrayList<>();

        public ViewPagerAdapter(FragmentManager manager) {
            super(manager);
        }

        @Override
        public Fragment getItem(int position) {
            return mFragmentList.get(position);
        }

        @Override
        public int getCount() {
            return mFragmentList.size();
        }

        public void addFragment(Fragment fragment, String title) {
            mFragmentList.add(fragment);
            mFragmentTitleList.add(title);
        }

        @Override
        public CharSequence getPageTitle(int position) {
            return mFragmentTitleList.get(position);
        }
    }

    @Subscribe
    public void onEvent(EventBusMSGNormal msg) {
        switch (msg.MSGType) {
            case EventBusMSG.TRACKLIST_SELECT:
            case EventBusMSG.TRACKLIST_DESELECT:
                ActivateActionModeIfNeeded();
        }
    }

    @Subscribe
    public void onEvent(Short msg) {
        switch (msg) {
            case EventBusMSG.REQUEST_ADD_PLACEMARK:
                // Show Placemark Dialog
                FragmentManager fm = getSupportFragmentManager();
                FragmentPlacemarkDialog placemarkDialog = new FragmentPlacemarkDialog();
                placemarkDialog.show(fm, "");
                break;
            case EventBusMSG.UPDATE_TRACKLIST:
            case EventBusMSG.NOTIFY_TRACKS_DELETED:
                ActivateActionModeIfNeeded();
                break;
            case EventBusMSG.APPLY_SETTINGS:
                LoadPreferences();
                break;

            case EventBusMSG.UPDATE_TRACK:
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        if (menutrackfinished != null)
                            menutrackfinished.setVisible(!GPSApp.getCurrentTrack().getName().equals(""));
                    }
                });
                break;
            case EventBusMSG.TOAST_TRACK_EXPORTED:
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(context, getString(R.string.toast_track_exported), Toast.LENGTH_LONG).show();
                    }
                });
                break;
            case EventBusMSG.TOAST_STORAGE_PERMISSION_REQUIRED:
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(context, getString(R.string.please_grant_storage_permission), Toast.LENGTH_LONG).show();
                    }
                });
                break;
            case EventBusMSG.TOAST_UNABLE_TO_WRITE_THE_FILE:
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(context, getString(R.string.export_unable_to_write_file), Toast.LENGTH_LONG).show();
                    }
                });
        }
    }

    private void LoadPreferences() {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
        prefKeepScreenOn = preferences.getBoolean("prefKeepScreenOn", true);
        if (prefKeepScreenOn) getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        else getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    }

    private void ShutdownApp()
    {
        if ((GPSApp.getCurrentTrack().getNumberOfLocations() > 0)
                || (GPSApp.getCurrentTrack().getNumberOfPlacemarks() > 0)
                || (GPSApp.getRecording())
                || (GPSApp.getPlacemarkRequest())) {

            AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(this, R.style.StyledDialog));
            builder.setMessage(getResources().getString(R.string.message_exit_finalizing));
            builder.setIcon(android.R.drawable.ic_menu_info_details);
            builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int id) {
                    GPSApp.setRecording(false);
                    GPSApp.setPlacemarkRequest(false);
                    EventBus.getDefault().post(EventBusMSG.NEW_TRACK);
                    GPSApp.StopAndUnbindGPSService();
                    GPSApp.setLocationPermissionChecked(false);

                    dialog.dismiss();
                    GPSApp.setJustStarted(true);
                    finish();
                }
            });
            builder.setNeutralButton(R.string.cancel, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int id) {
                    dialog.dismiss();
                }
            });
            builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int id) {
                    GPSApp.setRecording(false);
                    GPSApp.setPlacemarkRequest(false);
                    GPSApp.StopAndUnbindGPSService();
                    GPSApp.setLocationPermissionChecked(false);

                    dialog.dismiss();
                    GPSApp.setJustStarted(true);
                    finish();
                }
            });
            AlertDialog dialog = builder.create();
            dialog.show();
        } else {
            GPSApp.setRecording(false);
            GPSApp.setPlacemarkRequest(false);
            GPSApp.StopAndUnbindGPSService();
            GPSApp.setLocationPermissionChecked(false);

            finish();
        }
    }

    private void ActivateActionModeIfNeeded() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if ((GPSApp.getNumberOfSelectedTracks() > 0) && (activeTab == 2)) {
                    if (actionMode == null)
                        actionMode = (startSupportActionMode(new ToolbarActionMode()));
                    actionMode.setTitle(GPSApp.getNumberOfSelectedTracks() > 1 ? String.valueOf(GPSApp.getNumberOfSelectedTracks()) : "");
                } else if (actionMode != null) {
                    actionMode.finish();
                    actionMode = null;
                }
            }
        });
    }


    public boolean CheckLocationPermission() {
        Log.w("myApp", "[#] GPSActivity.java - Check Location Permission...");
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            Log.w("myApp", "[#] GPSActivity.java - Location Permission granted");
            return true;    // Permission Granted
        } else {
            Log.w("myApp", "[#] GPSActivity.java - Location Permission denied");
            boolean showRationale = ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION);
            if (showRationale || !GPSApp.isLocationPermissionChecked()) {
                Log.w("myApp", "[#] GPSActivity.java - Location Permission denied, need new check");
                List<String> listPermissionsNeeded = new ArrayList<>();
                listPermissionsNeeded.add(Manifest.permission.ACCESS_FINE_LOCATION);
                ActivityCompat.requestPermissions(this, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]) , REQUEST_ID_MULTIPLE_PERMISSIONS);
            }
            return false;
        }
    }


    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
        switch (requestCode) {
            case REQUEST_ID_MULTIPLE_PERMISSIONS: {
                Map<String, Integer> perms = new HashMap<>();

                if (grantResults.length > 0) {
                    // Fill with actual results from user
                    for (int i = 0; i < permissions.length; i++) perms.put(permissions[i], grantResults[i]);
                    // Check for permissions
                    if (perms.containsKey(Manifest.permission.ACCESS_FINE_LOCATION)) {
                        if (perms.get(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                            Log.w("myApp", "[#] GPSActivity.java - ACCESS_FINE_LOCATION = PERMISSION_GRANTED; setGPSLocationUpdates!");
                            GPSApp.setGPSLocationUpdates(false);
                            GPSApp.setGPSLocationUpdates(true);
                            GPSApp.updateGPSLocationFrequency();
                        } else {
                            Log.w("myApp", "[#] GPSActivity.java - ACCESS_FINE_LOCATION = PERMISSION_DENIED");
                        }
                    }

                    if (perms.containsKey(Manifest.permission.INTERNET)) {
                        if (perms.get(Manifest.permission.INTERNET) == PackageManager.PERMISSION_GRANTED) {
                            Log.w("myApp", "[#] GPSActivity.java - INTERNET = PERMISSION_GRANTED");
                        } else {
                            Log.w("myApp", "[#] GPSActivity.java - INTERNET = PERMISSION_DENIED");
                        }
                    }

                    if (perms.containsKey(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                        if (perms.get(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
                            Log.w("myApp", "[#] GPSActivity.java - WRITE_EXTERNAL_STORAGE = PERMISSION_GRANTED");
                            // ---------------------------------------------------- Create the Directories if not exist
                            File sd = new File(Environment.getExternalStorageDirectory() + "/GPSLogger");
                            if (!sd.exists()) {
                                sd.mkdir();
                            }
                            sd = new File(Environment.getExternalStorageDirectory() + "/GPSLogger/AppData");
                            if (!sd.exists()) {
                                sd.mkdir();
                            }
                            sd = new File(getApplicationContext().getFilesDir() + "/Thumbnails");
                            if (!sd.exists()) {
                                sd.mkdir();
                            }
                            EGM96 egm96 = EGM96.getInstance();
                            if (egm96 != null) {
                                if (!egm96.isEGMGridLoaded()) {
                                    //Log.w("myApp", "[#] GPSApplication.java - Loading EGM Grid...");
                                    egm96.LoadGridFromFile(Environment.getExternalStorageDirectory() + "/GPSLogger/AppData/WW15MGH.DAC", getApplicationContext().getFilesDir() + "/WW15MGH.DAC");
                                }
                            }

                            if (GPSApp.getJobsPending() > 0) GPSApp.ExecuteJob();

                        } else {
                            Log.w("myApp", "[#] GPSActivity.java - WRITE_EXTERNAL_STORAGE = PERMISSION_DENIED");
                            if (GPSApp.getJobsPending() > 0) {
                                // Shows toast "Unable to write the file"
                                show_toast_grant_storage_permission = true;
                                EventBus.getDefault().post(EventBusMSG.TOAST_STORAGE_PERMISSION_REQUIRED);
                                GPSApp.setJobsPending(0);
                            }
                        }
                    }
                }
                break;
            }
            default: {
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            }
        }
    }
}