//================================================================================================================================
//
// Copyright (c) 2015-2022 VisionStar Information Technology (Shanghai) Co., Ltd. All Rights Reserved.
// EasyAR is the registered trademark or trademark of VisionStar Information Technology (Shanghai) Co., Ltd in China
// and other countries for the augmented reality technology developed by VisionStar Information Technology (Shanghai) Co., Ltd.
//
//================================================================================================================================

package cn.easyar.samples.helloarmotiontracking;

import android.Manifest;
import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.app.Activity;
import android.view.ContextThemeWrapper;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.util.Log;
import android.widget.Toast;

import java.util.HashMap;
import java.util.Locale;

import cn.easyar.ARCoreCameraDevice;
import cn.easyar.ARCoreDeviceListDownloadStatus;
import cn.easyar.ARCoreDeviceListDownloader;
import cn.easyar.CalibrationDownloadStatus;
import cn.easyar.CalibrationDownloader;
import cn.easyar.Engine;
import cn.easyar.FunctorOfVoidFromARCoreDeviceListDownloadStatusAndOptionalOfString;
import cn.easyar.FunctorOfVoidFromCalibrationDownloadStatusAndOptionalOfString;
import cn.easyar.ImmediateCallbackScheduler;
import cn.easyar.MotionTrackerCameraDevice;

public class ARActivity extends Activity
{
    /*
    * Steps to create the key for this sample:
    *  1. login www.easyar.com
    *  2. create app with
    *      Name: HelloARMotionTracking
    *      Package Name: cn.easyar.samples.helloarmotiontracking
    *  3. find the created item in the list and show key
    *  4. set key string bellow
    */
    private static String key = "===PLEASE ENTER YOUR KEY HERE===";
    private GLView glView;
    private CalibrationDownloader calibrationDownloader;
    private ARCoreDeviceListDownloader arcoreDeviceListDownloader;

    static
    {
        System.loadLibrary("arcore_sdk_c");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ar);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        if (!Engine.initialize(this, key)) {
            Log.e("HelloAR", "Initialization Failed.");
            Toast.makeText(ARActivity.this, Engine.errorMessage(), Toast.LENGTH_LONG).show();
            return;
        }

        arcoreDeviceListDownloader = new ARCoreDeviceListDownloader();
        arcoreDeviceListDownloader.download(10000, ImmediateCallbackScheduler.getDefault(), new FunctorOfVoidFromARCoreDeviceListDownloadStatusAndOptionalOfString() {
            @Override
            public void invoke(int status, String error) {
                //following code runs on a non-GUI thread
                if (status == ARCoreDeviceListDownloadStatus.Successful) {
                    Log.i("HelloAR", "Calibration file download successful.");
                } else if (status == ARCoreDeviceListDownloadStatus.NotModified) {
                    Log.i("HelloAR", "Calibration file is latest.");
                } else if (status == ARCoreDeviceListDownloadStatus.ConnectionError) {
                    Log.i("HelloAR", "Calibration file download connection error: " + error);
                } else if (status == ARCoreDeviceListDownloadStatus.UnexpectedError) {
                    Log.i("HelloAR", "Calibration file download unexpected error: " + error);
                } else {
                    Log.i("HelloAR", "Calibration file download failed.");
                }
                ARActivity.this.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        if (arcoreDeviceListDownloader != null) {
                            arcoreDeviceListDownloader.dispose();
                            arcoreDeviceListDownloader = null;
                        }

                        if (isFinishing()) {
                            return;
                        }

                        calibrationDownloader = new CalibrationDownloader();
                        calibrationDownloader.download(10000, ImmediateCallbackScheduler.getDefault(), new FunctorOfVoidFromCalibrationDownloadStatusAndOptionalOfString() {
                            @Override
                            public void invoke(int status, String error) {
                                //following code runs on a non-GUI thread
                                if (status == CalibrationDownloadStatus.Successful) {
                                    Log.i("HelloAR", "Calibration file download successful.");
                                } else if (status == CalibrationDownloadStatus.NotModified) {
                                    Log.i("HelloAR", "Calibration file is latest.");
                                } else if (status == CalibrationDownloadStatus.ConnectionError) {
                                    Log.i("HelloAR", "Calibration file download connection error: " + error);
                                } else if (status == CalibrationDownloadStatus.UnexpectedError) {
                                    Log.i("HelloAR", "Calibration file download unexpected error: " + error);
                                } else {
                                    Log.i("HelloAR", "Calibration file download failed.");
                                }
                                ARActivity.this.runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        if (calibrationDownloader != null) {
                                            calibrationDownloader.dispose();
                                            calibrationDownloader = null;
                                        }

                                        if (isFinishing()) {
                                            return;
                                        }

                                        final Function<Integer, Void> onEnter = new Function<Integer, Void>() {
                                            @Override
                                            public Void apply(Integer motionTrackingCameraDeviceType) {
                                                if (motionTrackingCameraDeviceType == HelloAR.MotionTrackingCameraDeviceType.ARCore) {
                                                    if (!ARCoreCameraDevice.isAvailable()) {
                                                        Toast.makeText(ARActivity.this, "ARCoreCameraDevice not available.", Toast.LENGTH_LONG).show();
                                                        return null;
                                                    }
                                                    Toast.makeText(ARActivity.this, "ARCoreCameraDevice used.", Toast.LENGTH_LONG).show();
                                                } else if (motionTrackingCameraDeviceType == HelloAR.MotionTrackingCameraDeviceType.EasyARMotionTracker) {
                                                    Toast.makeText(ARActivity.this, "MotionTrackerCameraDevice used.", Toast.LENGTH_LONG).show();
                                                } else {
                                                    return null;
                                                }

                                                glView = new GLView(ARActivity.this, motionTrackingCameraDeviceType);
                                                glView.onResume();

                                                requestCameraPermission(new PermissionCallback() {
                                                    @Override
                                                    public void onSuccess() {
                                                        ViewGroup preview = ((ViewGroup) findViewById(R.id.preview));
                                                        preview.addView(glView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
                                                    }

                                                    @Override
                                                    public void onFailure() {
                                                    }
                                                });
                                                return null;
                                            }
                                        };

                                        if (ARCoreInstaller.isInstalled(ARActivity.this)) {
                                            ARCoreInstaller.tryInstallOrUpdate(ARActivity.this, "1.3.180604066", "1.31.221020223", new ARCoreInstaller.InstallCallback() {
                                                @Override
                                                public void invoke(boolean isInstalledAndSupportedVersion, boolean needContinue) {
                                                    if (isInstalledAndSupportedVersion && needContinue) {
                                                        onEnter.apply(HelloAR.MotionTrackingCameraDeviceType.ARCore);
                                                    } else {
                                                        if (MotionTrackerCameraDevice.isAvailable()) {
                                                            onEnter.apply(HelloAR.MotionTrackingCameraDeviceType.EasyARMotionTracker);
                                                            return;
                                                        }
                                                        ARActivity.this.finish();
                                                    }
                                                }
                                            });
                                            return;
                                        }

                                        if (ARCoreCameraDevice.isDeviceSupported()) {
                                            ARCoreInstaller.tryInstallOrUpdate(ARActivity.this, "1.3.180604066", "1.31.221020223", new ARCoreInstaller.InstallCallback() {
                                                @Override
                                                public void invoke(boolean isInstalledAndSupportedVersion, boolean needContinue) {
                                                    if (isInstalledAndSupportedVersion && needContinue) {
                                                        onEnter.apply(HelloAR.MotionTrackingCameraDeviceType.ARCore);
                                                    } else {
                                                        if (MotionTrackerCameraDevice.isAvailable()) {
                                                            onEnter.apply(HelloAR.MotionTrackingCameraDeviceType.EasyARMotionTracker);
                                                            return;
                                                        }
                                                        ARActivity.this.finish();
                                                    }
                                                }
                                            });
                                            return;
                                        }

                                        if (MotionTrackerCameraDevice.isAvailable()) {
                                            onEnter.apply(HelloAR.MotionTrackingCameraDeviceType.EasyARMotionTracker);
                                            return;
                                        }

                                        boolean isZh = Locale.getDefault().getLanguage() == "zh";
                                        int DialogStyle = Build.VERSION.SDK_INT >= 22 ? android.R.style.Theme_DeviceDefault_Dialog_Alert : android.R.style.Theme_Dialog;
                                        AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(ARActivity.this, DialogStyle));
                                        builder.setTitle(isZh ? "设备不支持ARCore和EasyAR Motion Tracking，无法使用当前功能" : "Your device does not support ARCore and EasyAR Motion Tracking, so this functionality is not available.");
                                        builder.setPositiveButton(isZh ? "确定" : "OK", new DialogInterface.OnClickListener() {
                                            @Override
                                            public void onClick(DialogInterface dialog, int which) {
                                                ARActivity.this.finish();
                                            }
                                        });
                                        AlertDialog dialog = builder.create();
                                        dialog.show();
                                    }
                                });
                            }
                        });
                    }
                });
            }
        });
    }

    private interface PermissionCallback
    {
        void onSuccess();
        void onFailure();
    }
    private HashMap<Integer, PermissionCallback> permissionCallbacks = new HashMap<Integer, PermissionCallback>();
    private int permissionRequestCodeSerial = 0;
    @TargetApi(23)
    private void requestCameraPermission(PermissionCallback callback)
    {
        if (Build.VERSION.SDK_INT >= 23) {
            if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                int requestCode = permissionRequestCodeSerial;
                permissionRequestCodeSerial += 1;
                permissionCallbacks.put(requestCode, callback);
                requestPermissions(new String[]{Manifest.permission.CAMERA}, requestCode);
            } else {
                callback.onSuccess();
            }
        } else {
            callback.onSuccess();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
    {
        if (permissionCallbacks.containsKey(requestCode)) {
            PermissionCallback callback = permissionCallbacks.get(requestCode);
            permissionCallbacks.remove(requestCode);
            boolean executed = false;
            for (int result : grantResults) {
                if (result != PackageManager.PERMISSION_GRANTED) {
                    executed = true;
                    callback.onFailure();
                }
            }
            if (!executed) {
                callback.onSuccess();
            }
        }
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

    @Override
    protected void onResume()
    {
        super.onResume();
        if (glView != null) { glView.onResume(); }
    }

    @Override
    protected void onPause()
    {
        if (glView != null) { glView.onPause(); }
        super.onPause();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (arcoreDeviceListDownloader != null) {
            arcoreDeviceListDownloader.dispose();
            arcoreDeviceListDownloader = null;
        }
        if (calibrationDownloader != null) {
            calibrationDownloader.dispose();
            calibrationDownloader = null;
        }
    }
}
