/*
 * Copyright (c) 2015,2016 Oracle and/or its affiliates.  All rights reserved.
 *
 * This software is dual-licensed to you under the MIT License (MIT) and
 * the Universal Permissive License (UPL).  See the LICENSE file in the root
 * directory for license terms.  You may choose either license, or both.
 */

package com.oracle.iot.sample;

import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
import android.provider.Settings;
import android.text.Html;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.widget.*;

public class MainActivity extends Activity {
    /**
     * The primary interface we will be calling on the DCD sample service.
     */
    IDirectlyConnectedDeviceSampleService dcdService = null;
    /**
     * Another interface we use on the DCD sample service.
     */
    IDirectlyConnectedDeviceSampleServiceSecondary dcdSecondaryService = null;
    TextView mCallbackText;
    TextView sensorInfoText;
    private boolean mIsBound = false;
    private int pid;
    private int dcdwv_max_threshold;
    private int last_dcdwv_max_threshold = 0;
    Intent dcdServiceIntent;

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button resetButton = (Button) findViewById(R.id.resetButton);
        Button exitButton = (Button)findViewById(R.id.exitButton);
        final SharedPreferences sharedPref = getApplicationContext().getSharedPreferences(
                getString(R.string.preference_file_key), Context.MODE_PRIVATE);
        if(sharedPref.getBoolean(getString(R.string.use_provided_bks), false)){
            resetButton.setVisibility(View.GONE);
        }
        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        int currentapiVersion = android.os.Build.VERSION.SDK_INT;
        if (currentapiVersion >= 23){ // using 23 since definition for marshmallow is not available in current sdk
            // only applies to marshmallow and above versions
            Intent intent = new Intent();
            String packageName = this.getPackageName();
            if(pm.isIgnoringBatteryOptimizations(getPackageName())) {
                intent.setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
            }else{
                intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
                intent.setData(Uri.parse("package:" + packageName));
            }
            startActivity(intent);
        }

        resetButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){
                    resetApp();
                } else {
                    AlertDialog dialog;
                    AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                    builder  = builder.setMessage("Application provisioining information will be lost and cannot be recovered. Continue?");
                    builder = builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            // User clicked Try again button
                            dialog.dismiss();
                            resetApp();
                        }
                    });
                    builder = builder.setNegativeButton("No", new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            // User cancelled the dialog
                            dialog.dismiss();
                        }
                    });
                    dialog = builder.create();
                    dialog.show();
                }
            }
        });

        exitButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                stopDcdService();
                Intent anIntent = new Intent(MainActivity.this, SelectProvisioningActivity.class);
                anIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                anIntent.putExtra("EXIT", true);
                startActivity(anIntent);
                finish();
            }
        });
        dcdServiceIntent = new Intent(MainActivity.this, DirectlyConnectedDeviceSampleService.class);
        startService(dcdServiceIntent);
        dcdServiceIntent.setAction(IDirectlyConnectedDeviceSampleService.class.getName());
        bindService(dcdServiceIntent, dcdServiceConnection, Context.BIND_AUTO_CREATE);
        dcdServiceIntent.setAction(IDirectlyConnectedDeviceSampleServiceSecondary.class.getName());
        bindService(dcdServiceIntent, dcdServiceSecondaryConnection, Context.BIND_AUTO_CREATE);
        mIsBound = true;
        // Configure text views
        mCallbackText = (TextView) findViewById(R.id.Output);
        sensorInfoText= (TextView) findViewById(R.id.sensorinfo);
    }

    void stopDcdService() {
        unbindService(dcdServiceConnection);
        unbindService(dcdServiceSecondaryConnection);
        stopService(dcdServiceIntent);
    }

    void resetApp(){
        stopDcdService();
        SharedPreferences sharedPref = getApplicationContext().getSharedPreferences(
                getString(R.string.preference_file_key), Context.MODE_PRIVATE);
        SharedPreferences.Editor prefsEditor = sharedPref.edit();
        prefsEditor.remove(getString(R.string.ta_file_path));
        prefsEditor.apply();
        deleteFile(getString(R.string.last_known));
        Intent anIntent = new Intent(MainActivity.this, SelectProvisioningActivity.class);
        anIntent.putExtra("RESET", true);
        startActivity(anIntent);
        finish();
    }


    /**
     * Class for interacting with the main interface of the DCD Sample service.
     */
    private ServiceConnection dcdServiceConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className,
                                       IBinder service) {
            // This is called when the connection with the service has been
            // established, giving us the service object we can use to
            // interact with the service.  We are communicating with our
            // service through an IDL interface, so get a client-side
            // representation of that from the raw service object.
            dcdService = IDirectlyConnectedDeviceSampleService.Stub.asInterface(service);
            // We want to monitor the service for as long as we are
            // connected to it.
            try {
                dcdService.registerCallback(dcdCallback);
            } catch (RemoteException e) {
                // In this case the service has crashed before we could even
                // do anything with it; we can count on soon being
                // disconnected (and then reconnected if it can be restarted)
                // so there is no need to do anything here.
            }

            // As part of the sample, tell the user what happened.
            Toast.makeText(MainActivity.this, R.string.dcd_service_connected,
                    Toast.LENGTH_SHORT).show();
        }

        public void onServiceDisconnected(ComponentName className) {
            // This is called when the connection with the service has been
            // unexpectedly disconnected -- that is, its process crashed.
            dcdService = null;
            // As part of the sample, tell the user what happened.
            Toast.makeText(MainActivity.this, R.string.dcd_service_disconnected,
                    Toast.LENGTH_SHORT).show();
        }
    };
    /**
     * Class for interacting with the secondary interface of the DCD Sample service.
     */
    private ServiceConnection dcdServiceSecondaryConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className,
                                       IBinder service) {
            // Connecting to a secondary interface is the same as any
            // other interface.
            dcdSecondaryService = IDirectlyConnectedDeviceSampleServiceSecondary.Stub.asInterface(service);
        }

        public void onServiceDisconnected(ComponentName className) {
            dcdSecondaryService = null;
        }
    };

    /**
     * Check if a certain service is already running so I can bind/unbind to it and stop it.
     */
    private boolean isServiceRunning(Class<?> serviceClass) {
        ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
            if (serviceClass.getName().equals(service.service.getClassName())) {
                return true;
            }
        }
        return false;
    }

    /**
     * This implementation is used to receive callbacks from the DCD sample
     * service.
     */
    private IDirectlyConnectedDeviceSampleServiceCallback dcdCallback =
            new IDirectlyConnectedDeviceSampleServiceCallback.Stub() {
                /**
                 * This is called by the remote service regularly to tell us about
                 * new values.
                 */
                public void valueChanged(String value) {
                    mHandler.sendMessage(mHandler.obtainMessage(BUMP_MSG, value));
                }

                /**
                 * This is called by the remote service in order to tell us the
                 * hygrometer max threshold value when it has been asked for.
                 */
                public void maxHygro(String value) {
                    mHandler.sendMessage(mHandler.obtainMessage(DCD_MAX_HYGRO_MSG, value));
                }
                /**
                 * This is called by the remote service to display error messages.
                 */
                public void errorMessage(String value) {
                    mHandler.sendMessage(mHandler.obtainMessage(ERROR_MSG, value));
                }

            };


    private static final int BUMP_MSG = 1;
    private static final int DCD_MAX_HYGRO_MSG = 3;
    private static final int ERROR_MSG = 4;

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case BUMP_MSG:
                    mCallbackText
                            .append(msg.obj+"\n");
                    sensorInfoText.setText(Html.fromHtml(parseSensorInfo(msg.obj.toString())));
                    break;
                case DCD_MAX_HYGRO_MSG:
                    String dcdHygroToBeShown = msg.obj.toString();
                    dcdwv_max_threshold = Integer.parseInt(dcdHygroToBeShown);
                    if (last_dcdwv_max_threshold == 0) {
                        // this is our first received max threshold value
                        // during this binding
                        last_dcdwv_max_threshold = dcdwv_max_threshold;
                    } else {
                        // otherwise alter the content of the EditText
                        // only in case the value has changed
                        if (last_dcdwv_max_threshold != dcdwv_max_threshold) {
                            last_dcdwv_max_threshold = dcdwv_max_threshold;
                        }
                    }
                    break;
                case ERROR_MSG:
                    // As part of the sample, tell the user what happened.
                    String errorMsg = msg.obj.toString();
                    mCallbackText
                            .append("\nERROR: " +  errorMsg);
                    break;
                default:
                    super.handleMessage(msg);
            }
        }

        private String parseSensorInfo(String s){
            String[] result = s.split(":");
            String info="<b>Humidity Sensor "+result[3]+"</b><br>";
            info+="Current Value "+result[5].split("=")[1]+"%<br>";
            info+="Max Threshold "+last_dcdwv_max_threshold+"%";
            return info;
        }

    };

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

    }

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