package mfulton.drivedata;

import android.app.Dialog;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentSender;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.View;
import android.widget.CheckedTextView;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.location.LocationSettingsResult;
import com.google.android.gms.location.LocationSettingsStates;
import com.google.android.gms.location.LocationSettingsStatusCodes;

public class MainMenu extends FragmentActivity
        implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
    /*
        OBJECT VARIABLES
            These values hold information required by the activity.
    */
    private GoogleApiClient googleApiClient; //The connection client for the Google API.
    private boolean criteriaPassed; //The status of testing of the Google Location API.

    private boolean resolvingError;//Is the Activity currently resolving an error?

    //Constants
    private static final int REQUEST_RESULT_ERROR = 1001; //Request code for errors.
    private static final int REQUEST_CHECK_SETTINGS = 0x1; //Check settings requet.
    private static final String DIALOG_ERROR = "dialog_error"; //Tag for the error dialog fragment.
    private static final String STATE_RESOLVING_ERROR = "resolving_error"; // Tag for the state resolving state.
    private static final String STATE_CRITERIA_MET = "criteria_met"; //Tag for the criteria met state.

    /*
       ACTIVITY LIFECYCLE FUNCTIONS
           These overriden functions are crucial to maintaining the proper lifecycle of the Activity.
    */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_menu);

        //Connect Google API Client.
        if (googleApiClient == null) {
            googleApiClient = new GoogleApiClient.Builder(this)
                    .addApi(LocationServices.API)
                    .addConnectionCallbacks(this)
                    .addOnConnectionFailedListener(this)
                    .build();
        }

        //Get all saved instance variables.
        criteriaPassed = savedInstanceState != null && savedInstanceState.getBoolean(STATE_CRITERIA_MET, false);
        resolvingError = savedInstanceState != null && savedInstanceState.getBoolean(STATE_RESOLVING_ERROR, false);

        //Get TextView for system readiness.
        View view = findViewById(android.R.id.content);
        final CheckedTextView systemReadyText =(CheckedTextView) view.findViewById(R.id.system_preperation_indicator);

        //Thread which updates the readiness text as needed.
        Thread t = new Thread(){
            @Override
            public void run(){
                try{
                    while(!isInterrupted()){
                        Thread.sleep(1000);
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                if(criteriaPassed){
                                    systemReadyText.setText("SYSTEM READY ");
                                    systemReadyText.setTextColor(getResources().getColor(R.color.green));
                                    systemReadyText.setChecked(true);
                                }
                                else
                                    return;
                            }
                        });
                    }
                }catch(InterruptedException e){

                }
            }
        };
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

    @Override
    protected void onStart() {
        googleApiClient.connect();
        super.onStart();
    }

    @Override
    protected void onStop() {
        googleApiClient.disconnect();
        super.onStop();
    }

    @Override
    protected void onPause(){
        super.onPause();
    }

    @Override
    protected void onResume(){
        super.onResume();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putBoolean(STATE_RESOLVING_ERROR, resolvingError);
        outState.putBoolean(STATE_CRITERIA_MET, criteriaPassed);
    }
/*
    HANDLERS FOR UI INTERACTIONS
        The following functions handle button presses and other interaction.
 */

    // Handler for the button to start the capture.
    public void startCapture(View view) {
        //Acquire the entered capture name.
        View parent = view.getRootView();
        TextView logEntry = (TextView) parent.findViewById(R.id.logNameEntry);
        CharSequence logName = logEntry.getText();
        String logString = logName.toString();

        Context context = getApplicationContext();
        int toast_duration = Toast.LENGTH_LONG;

        if (logString.isEmpty()) {
            logEntry.setError("This field cannot be empty");
            logEntry.setError("Must have a capture name!");
            CharSequence text = "You must enter a capture name.";
            Toast toast = Toast.makeText(context, text, toast_duration);
            toast.show();
            return;
        }

        if (!criteriaPassed){
            CharSequence text = "Google Location Services is still configuring, please wait.";
            Toast toast = Toast.makeText(context, text, toast_duration);
            toast.show();
            return;
        }

        //Start the capture activity.
        Log.i("MainMenu", "Log Name is " + logString);
        Intent intent = new Intent(this, CaptureActivity.class);
        SharedPreferences.Editor edit = PreferenceManager.getDefaultSharedPreferences(this).edit();
        edit.putString("log_name", logString);
        edit.commit();
        startActivity(intent);
    }

    //Test the location services to see if they are adequate.
    public void checkCriteria(){
        //Set up test location reuest.
        LocationRequest request = new LocationRequest();
        request.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
                .setInterval(5000);

        //Set up the SettingsRequest framework.
        LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
                .addLocationRequest(request);
        PendingResult<LocationSettingsResult> result = LocationServices.SettingsApi.
                checkLocationSettings(googleApiClient, builder.build());

        //Run the actual test.
        result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
            @Override
            public void onResult(@NonNull LocationSettingsResult result) {
                final Status status = result.getStatus();
                final LocationSettingsStates states = result.getLocationSettingsStates();
                switch (status.getStatusCode()) {
                    case LocationSettingsStatusCodes.SUCCESS:
                        //All location settings are good!
                        criteriaPassed = true;
                        break;
                    case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                        //There are some issues.
                        try {
                            status.startResolutionForResult(
                                    MainMenu.this,
                                    REQUEST_CHECK_SETTINGS);
                        } catch (IntentSender.SendIntentException e) {
                            Log.e("DriveData", e.toString());
                        }
                        break;
                    case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                        //Location settings are wrong, but cannot be resolved.
                        criteriaPassed = false;
                        break;
                }
            }
        });
    }

/*
    CONNECTION HANDLERS FOR GOOGLE API
 */

    @Override
    public void onConnected(Bundle connectionHint) {
        checkCriteria();
    }

    @Override
    public void onConnectionSuspended(int cause) {
    }

    //Deal with connection failure cases.
    @Override
    public void onConnectionFailed(@NonNull ConnectionResult result) {
        if (resolvingError) {
            return; //An error is being resolved.  We need to wait.
        } else if (result.hasResolution()) { //There is a resolution available.
            try {
                resolvingError = true;
                result.startResolutionForResult(this, REQUEST_RESULT_ERROR);
            } catch (IntentSender.SendIntentException e) {
                //There was an error attempting to resolve.  Let's try again.
                googleApiClient.connect();
            }
        } else {
            //Show error dialog
            resolvingError = true;
            showErrorDialog(result.getErrorCode());

        }
    }

    //The following functions and inline classes are defined to help resolve connection issues.
    public void showErrorDialog(int errorCode) {
        //Create a new fragment.
        ErrorDialogFragment dialogFragment = new ErrorDialogFragment();
        //Pass in the error that must be displayed.
        Bundle args = new Bundle();
        args.putInt(DIALOG_ERROR, errorCode);
        dialogFragment.setArguments(args);
        dialogFragment.show(getSupportFragmentManager(), "errordialog");
    }

    // Called once the ErrorDialogFragment is done.
    public void onDialogDismissed() {
        resolvingError = false;
    }

    //Class used to select the correct dialog
    public static class ErrorDialogFragment extends DialogFragment {
        public ErrorDialogFragment() {
        }

        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            //Get the error code
            int errorCode = this.getArguments().getInt(DIALOG_ERROR);
            return GoogleApiAvailability.getInstance().getErrorDialog(
                    this.getActivity(), errorCode, REQUEST_RESULT_ERROR
            );
        }

        @Override
        public void onDismiss(DialogInterface dialog) {
            ((MainMenu) getActivity()).onDialogDismissed();
        }
    }

    //Once the error resolution completes, this callback is needed
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_RESULT_ERROR) {
            resolvingError = false;
            if (resultCode == RESULT_OK){
                if(!criteriaPassed){
                    checkCriteria();
                }
                if (!googleApiClient.isConnecting() &&
                        !googleApiClient.isConnected()) {
                    googleApiClient.connect();
                }
            }
        }
    }
}