/*
 * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
 * All rights reserved.
 * Confidential and Proprietary - Qualcomm Technologies, Inc.
 */

package com.qualcomm.snapdragon.spaces.splashscreen;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.provider.Settings;
import android.util.Log;
import android.view.Gravity;
import android.view.Window;
import android.view.WindowManager;

import com.qualcomm.snapdragon.spaces.helpers.*;
import com.qualcomm.snapdragon.spaces.R;
import com.qualcomm.qti.device.access.*;

public class SplashScreenActivity extends Activity implements PermissionHelper.PermissionHandler, GlassListener {

    private LaunchHelper _spacesHelper;

    private PermissionHelper _permissionHelper;

    private CheckSpacesServicesHelper _checkServicesHelper;

    private static boolean mHasSplashBeenShown = false;

    private static final String TAG = "Spaces-SplashScreen";

    private static SplashScreenActivity _instance;

    private static DeviceAccessManager _deviceAccessMgr;

    private static boolean _isConnected = false;

    private static AlertDialog alertDialog;

    private final Object _uiThreadWait = new Object();

    private HandlerThread _startupStateHandlerThread;

    private Handler _startupStateHandler;

    private static int _currentStartupState = StartupStateHandler.MSG_CHECK_RUNTIME;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        _instance = this;
        Log.v(TAG, "Application was started with intent flags: " + getIntent().getFlags());
        try {
            _spacesHelper = new LaunchHelper(this, false);
            if (_deviceAccessMgr == null) {
                _deviceAccessMgr = new DeviceAccessManager(null);
            }
            _deviceAccessMgr.addGlassListener(_instance);
            _permissionHelper = new PermissionHelper(this, this);
            _checkServicesHelper = new CheckSpacesServicesHelper(this);
            Log.d(TAG, "should show splash: "+_spacesHelper.ShouldShowSplashScreen());
            Log.d(TAG, "splash has been shown: "+ mHasSplashBeenShown);
            if(!_spacesHelper.ShouldShowSplashScreen()) {
                setTheme(android.R.style.Theme_Translucent_NoTitleBar_Fullscreen);
            }
            if (_spacesHelper.ShouldShowSplashScreen() && !mHasSplashBeenShown) {
                setContentView(R.layout.spaces_handset_splash_screen);
                mHasSplashBeenShown = true;
            } else if (mHasSplashBeenShown) {
                if ((_deviceAccessMgr.getDeviceType() != DeviceType.UNKNOWN || _isConnected) &&
                    (_currentStartupState == StartupStateHandler.MSG_APP_STARTED)) {
                    LaunchHelper.tryStartControllerActivity(this);
                    return;
                }
                // Appears to be an issue where on a resume the dialog is thought to be shown according to Android when it is not
                // Hide so that it can then be shown
                setContentView(R.layout.spaces_handset_splash_screen);
                hideWaitingConnectDialog();
                _currentStartupState = StartupStateHandler.MSG_CHECK_RUNTIME;
            }
        } catch(Exception e) {
            e.printStackTrace();
        }

        if (_startupStateHandlerThread == null) {
            _startupStateHandlerThread = new HandlerThread("StartupStateThread");
            _startupStateHandlerThread.start();
            _startupStateHandler = new StartupStateHandler(_startupStateHandlerThread.getLooper());
        }
        Log.d(TAG, "_currentStartupState: "+ _currentStartupState);
        _startupStateHandler.sendEmptyMessage(_currentStartupState);

    }

    @Override
    protected void onDestroy() {
        Log.v(TAG, "Splash Screen Activity is being destroyed");
        if(_deviceAccessMgr != null) {
            _deviceAccessMgr.removeGlassListener(this);
        }
        hideWaitingConnectDialog();
        if (_startupStateHandlerThread != null && _startupStateHandlerThread.isAlive()) {
            _startupStateHandlerThread.quit();
            _startupStateHandlerThread = null;
            _startupStateHandler = null;
        }
        super.onDestroy();
    }

    private class StartupStateHandler extends Handler {
        public static final int MSG_CHECK_RUNTIME = 0;
        public static final int MSG_CHECK_RUNTIME_COMPATIBLE = 1;
        public static final int MSG_CHECK_PERMISSIONS = 2;
        public static final int MSG_CHECK_CONNECTED = 3;
        public static final int MSG_START_APP = 4;
        public static final int MSG_APP_STARTED = 5;

        StartupStateHandler(Looper looper) { super(looper); }

        @Override
        public void handleMessage(android.os.Message msg) {
            Log.d(TAG, "handleMessage: "+msg.what);
            if (msg.what == MSG_START_APP && _currentStartupState < MSG_CHECK_CONNECTED) {
                Log.d(TAG, "Dropping START_APP msg due to ongoing checks for runtime/permissions");
                return;
            }
            switch(msg.what) {
                case MSG_CHECK_RUNTIME:
                    if (_checkServicesHelper.CheckSpacesServicesInstalled()) {
                        _startupStateHandler.sendEmptyMessage(StartupStateHandler.MSG_CHECK_RUNTIME_COMPATIBLE);
                    }
                    break;
                case MSG_CHECK_RUNTIME_COMPATIBLE:
                    if (_checkServicesHelper.CheckSpacesServicesCompatible()){
                        _startupStateHandler.sendEmptyMessage(StartupStateHandler.MSG_CHECK_PERMISSIONS);
                    }
                    break;
                case MSG_CHECK_PERMISSIONS:
                    if (!_spacesHelper.SkipPermissionCheck()) {
                        if (!_permissionHelper.CheckSpacesServicePermissions()) {
                            _permissionHelper.CheckApplicationPermissions(false);
                        } else {
                            Log.v(TAG, "Showed Spaces Service Permission prompt, let the two buttons handle the startup flow.");
                        }
                    } else {
                        Log.d(TAG, "Skip permission check and move to CHECK_CONNECTED");
                        _startupStateHandler.sendEmptyMessage(StartupStateHandler.MSG_CHECK_CONNECTED);
                    }
                    break;
                case MSG_CHECK_CONNECTED:
                    Log.d(TAG, "CheckConnection device type is: "+_deviceAccessMgr.getDeviceType() + " callbackConnected: " + _isConnected);
                    _deviceAccessMgr.addGlassListener(_instance); //Just to make sure we have a listener active
                    // We check if we have a device type, or in the case of something going wrong with DeviceType here we can fallback with _isConnected due to
                    // the deviceAccess callbacks so that we can at least start the app and determine device type later if needed, since device type is just a
                    // check to ensure we have a device connected
                    if (_deviceAccessMgr != null && (_deviceAccessMgr.getDeviceType() != DeviceType.UNKNOWN || _isConnected)) {
                        hideWaitingConnectDialog();
                        _startupStateHandler.sendEmptyMessage(StartupStateHandler.MSG_START_APP);
                        break;
                    }
                    if (alertDialog != null && alertDialog.isShowing() && !_instance.isFinishing()) {
                        Log.i(TAG, "Awaiting connection dialog showing, wait for callback to proceed.");
                    } else {
                        showWaitingConnectDialog();
                    }
                    break;
                case MSG_START_APP:
                    if(_deviceAccessMgr != null) {
                        _deviceAccessMgr.removeGlassListener(_instance);
                    }
                    hideWaitingConnectDialog();
                    if (_spacesHelper.StartGameEngineActivity()) {
                        _startupStateHandler.sendEmptyMessage(StartupStateHandler.MSG_APP_STARTED);
                    } else {
                        Log.e(TAG, "Trouble starting game engine activity, going to restart state machine.");
                        _startupStateHandler.sendEmptyMessage(StartupStateHandler.MSG_CHECK_RUNTIME);
                    }
                    break;
                case MSG_APP_STARTED:
                    break;
            }
            _currentStartupState = msg.what;
        }
    }

    private void showWaitingConnectDialog() {
        synchronized(_uiThreadWait) {
            if (alertDialog == null) {
                runOnUiThread(new Runnable() {
                    public void run() {
                        synchronized(_uiThreadWait) {
                            AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(_instance);
                            alertDialogBuilder.setTitle("Waiting...");
                            alertDialogBuilder.setMessage("Please Connect XR Device").setCancelable(false);
                            alertDialog = alertDialogBuilder.create();
                            WindowManager.LayoutParams params = alertDialog.getWindow().getAttributes();
                            params.gravity = Gravity.BOTTOM | Gravity.CENTER;
                            alertDialog.show();
                            _uiThreadWait.notifyAll();
                        }
                    }
                });
            } else if ( !alertDialog.isShowing()) {
                runOnUiThread(new Runnable() {
                    public void run() {
                        synchronized(_uiThreadWait) {
                            alertDialog.show();
                            _uiThreadWait.notifyAll();
                        }
                    }
                });
            }
            try {
                _uiThreadWait.wait();
            } catch(Exception e) { e.printStackTrace(); }
        }
    }

    private void hideWaitingConnectDialog() {
        try {
            if (alertDialog != null && alertDialog.isShowing()){// && !_instance.isFinishing()) {
                alertDialog.dismiss();
                alertDialog = null;
                Log.d(TAG, "Should have closed alertDialog");
            } else {
                Log.d(TAG, "Attemped to hide dialog, but check failed: showing (" +
                    (alertDialog == null ? "null" : alertDialog.isShowing()) +
                    ") !finishing(" + !_instance.isFinishing() + ")");
            }
        } catch (Exception e) {e.printStackTrace(); }
    }

    @Override
    public void GlassConnected() {
        Log.d(TAG, "GlassConnected, going to begin app start process");
        _isConnected = true;
        hideWaitingConnectDialog();
        _startupStateHandler.sendEmptyMessage(StartupStateHandler.MSG_START_APP);
    }

    @Override
    public void GlassDisconnected() {
        _isConnected = false;
        if ((alertDialog == null || !alertDialog.isShowing()) && _currentStartupState > StartupStateHandler.MSG_CHECK_PERMISSIONS) {
            Log.d(TAG, "GlassDisconnected, show dialog");
            showWaitingConnectDialog();
        } else {
            Log.d(TAG, "GlassDisconnected, already showing dialog or ignored because of startupState");
        }
    }

    @Override
    public void GlassIdle() {
    }

    @Override
    public void GlassActive() {
    }

    @Override
    public void handleSpacesServicePermissionContinue() {
        _startupStateHandler.sendEmptyMessage(StartupStateHandler.MSG_CHECK_CONNECTED);
    }

    @Override
    public void handleSpacesServicePermissionConfigure() {
        // Unset if the splash screen has been shown so we will see it and do checks when we start the app back up
        mHasSplashBeenShown = false;
        // Make and send intent to invoke the Spaces Service application to allow user to interact and set settings
        Intent intent = getPackageManager().getLaunchIntentForPackage("com.qualcomm.qti.spaces.services");
        if(intent != null){
            startActivity(intent);
        }
        // Finish called as an example so the user needs to re-launch the app after setting Spaces Service permissions
        finish();
    }

    @Override
    public void handleSpacesServicePermissionExit(){
        // Unset if the splash screen has been shown so we will see it and do checks when we start the app back up
        mHasSplashBeenShown = false;
        finish();
    }

    @Override
    public void handlePermissionsDenied() {
        // For flexibility we have a callback here as a reference to where the user has twice denied permissions
        // One could take action here to alert the user and deny access to the app
        // as an example we will just forward over to the accepted flow and not handling deny of permissions
        handlePermissionsAccepted();
    }

    @Override
    public void handlePermissionsAccepted() {
        // Here is where you would send an intent to the next activity like a TOS, EULA, How to use app, Login, etc.
        // As an example we start the game engine main activity on remote display or handset depending on the selection of "Launch on glass" in the editors
        _startupStateHandler.sendEmptyMessage(StartupStateHandler.MSG_CHECK_CONNECTED);
    }

    @Override
    public void handlePermissionsChecksCompleted(boolean anyPermissionsDenied) {
        //We can optionally take action here to deny access to the main app or show screens alerting that the user must grant permissions
        // or we can ignore entirely as we will show here in this reference example
        handlePermissionsAccepted();
    }

    //This is required to handle the permission prompt request made in _permissionHelper
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        _permissionHelper.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

    public static void finishSplashScreenActivity() {
        if (_instance != null && !LaunchHelper.HasCustomController()) {
            if(_instance == null) {
                Log.w(TAG, "The SplashScreenActivity instance has not been initialized. This might come from starting the game/application activity directly and is not the recommended start-up procedure. The SplashScreenActivity includes the launcher intent and should be used as the entry activity of the application.");
            }
            else {
                _instance.finishAffinity();
            }
        }
    }
}
