package com.example.myapplication;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.hardware.usb.UsbManager;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;
import androidx.constraintlayout.widget.ConstraintSet;

import com.example.myapplication.databinding.ActivityMainBinding;
import com.meridianinno.libsenxor_android.Bobcat;
import com.meridianinno.libsenxor_android.BobcatConstants;
import com.meridianinno.libsenxor_android.Processor;
import com.meridianinno.libsenxor_android.Renderer;
import com.meridianinno.libsenxor_android.SenXorEvkCommand;
import com.meridianinno.libsenxor_android.SenXorFrame;
import com.meridianinno.libsenxor_android.SenXorFrameCBT;
import com.meridianinno.libsenxor_android.TemperatureUnit;
import com.meridianinno.libsenxor_android.Tof;

/**
  *  Example2 is directly driving SenXorDevice Controller.
  *  It gives more flexibility to handle SenXor during the runtime.
  *  However, developer might need to spend some time to understand the library structure, how the data transfer and render.
  *  Also it provides in-app firmware update to 3.2.13 by default
  *
  *  Arthor: Jackson LAU
  *  SDK Version : v3.2.0
 */

public class MainActivity extends AppCompatActivity
{
    private static final String LOG_TAG = "MainActivity";

    private ActivityMainBinding mSdk2MainBinding;
    private Sdk2BroadRec mSdk2BroadRec;
    private IntentFilter mIntentFilter;

    // SenXorLib
    private Bobcat mBobcat;
    private Processor mProcessor;
    private Renderer mRenderer;
    private Bitmap bmp;
    private SenXorFrame mCurrentFrame;
    private Tof mTof;                       // Only works when XPro includes TOF element
    private int mRotatePref = 0;
    private int mRotateVal = 0;
    private double mTempMax = 0;
    private double mTempMin = 0;
    private String mCbtStr;
    private Paint contour_text_paint = new Paint();

    //SenXorDevice
    private String mFWVer;                                                      //Firmware version
    private String mFWSN;                                                       //Firmware serial number
    private String mSenxorType = "Cougar";                                      //SenXor type
    private String mModType;                                                    //Module type
    private int mFWBld = 0;
    /*
        Queue handler
        This handler get message from queue and process the message.
     */
    private final Handler mEvkMsgUiUpdateHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            contour_text_paint.setColor(Color.rgb(255, 255, 255));
            contour_text_paint.setTextSize(20 * getResources().getDisplayMetrics().density);
            SenXorEvkCommand cmd = SenXorEvkCommand.fromIndex(msg.what);
            if (cmd == null) {
                Log.i("mUiUpdateHandler", "Command in message is undefined");
                return;
            }

            switch (cmd) {
                case GFRA:
                    mBobcat.setScale((mSdk2MainBinding.LLTHERM.getWidth() / 80));
                    mCurrentFrame = (SenXorFrame) msg.obj;
                    bmp = mCurrentFrame.getImage();

                    //Iterate each rotations (90, 180, 270)
                    switch (mRotateVal) {
                        //Rotate 90
                        case 90:
                            mSdk2MainBinding.IVSENXOR.setRotation(90);
                            break;
                        //Rotate 180
                        case 180:
                            mSdk2MainBinding.IVSENXOR.setRotation(180);                                                                       //Set rotation to 90
                            break;
                        //Rotate 270
                        case 270:
                            mSdk2MainBinding.IVSENXOR.setRotation(270);                                                                       //Set rotation to 270
                            break;
                        //No rotation
                        default:
                            mSdk2MainBinding.IVSENXOR.setRotation(0);
                            break;
                    }//End switch
                    //End of rotation

                    //If CBT is enabled
                    if (mBobcat.getSenXorFrameCBT().getIsCBTEnabled())
                    {
                        SenXorFrameCBT.Statistics[] mHotSpotStats = mBobcat.getSenXorFrameCBT().getHotSpotStats();

                        int CBT_idx = -1;
                        if (mHotSpotStats != null) {
                            // Criteria
                            float y_pos = BobcatConstants.IMAGE_ROWS;
                            double target_min = TemperatureUnit.convert(30.0, TemperatureUnit.DEGREE_C, mBobcat.getUnitType());
                            double target_max = TemperatureUnit.convert(60.0, TemperatureUnit.DEGREE_C, mBobcat.getUnitType());

                            //Iterate through the number of hotspots
                            for (int i = 0; i < mHotSpotStats.length; i++) {
                                double current_t_core_body = TemperatureUnit.convert(mHotSpotStats[i].t_core_body, TemperatureUnit.DEGREE_C, mBobcat.getUnitType());
                                if (current_t_core_body > target_min && current_t_core_body < target_max && mHotSpotStats[i].centroid_y < y_pos) {
                                    CBT_idx = i;
                                    y_pos = mHotSpotStats[i].centroid_y;
                                }
                            }//End for
                        }

                        if (CBT_idx > -1 && CBT_idx < mHotSpotStats.length) {

                            mCbtStr = "Distance: " + String.format("%.2f m", mHotSpotStats[CBT_idx].estimate_distance) + "\r\n";
                            mCbtStr += "CoreBody: " + String.format("%.1f ", TemperatureUnit.convert(mHotSpotStats[CBT_idx].t_core_body, TemperatureUnit.DEGREE_C, mBobcat.getUnitType())) + TemperatureUnit.getUnitSymbol(mBobcat.getUnitType().ordinal());
                        } else {
                            mCbtStr = "";
                        }


                    }//End if
                    mSdk2MainBinding.TVCBTSTAT.setText(mCbtStr);
                    mSdk2MainBinding.IVSENXOR.setImageBitmap(bmp);
                    mSdk2MainBinding.TVTEMPLOC.setText("(0 , 0)");
                    mSdk2MainBinding.TVTEMPVAL.setText(String.format("%.1f", TemperatureUnit.convert(mCurrentFrame.getDataAt(0,0), TemperatureUnit.KELVIN, mBobcat.getUnitType())) + TemperatureUnit.getUnitSymbol(mBobcat.getUnitType().ordinal()));
                    mTempMax = TemperatureUnit.convert(mBobcat.getProcessControl().getFilteredMax(), TemperatureUnit.KELVIN, TemperatureUnit.DEGREE_C);
                    mTempMin = TemperatureUnit.convert(mBobcat.getProcessControl().getFilteredMin(), TemperatureUnit.KELVIN, TemperatureUnit.DEGREE_C);
                    mSdk2MainBinding.TVTEMPMAXVAL.setText("" + String.format("%.1f ", mTempMax, TemperatureUnit.DEGREE_C, mBobcat.getUnitType()) + TemperatureUnit.getUnitSymbol(mBobcat.getUnitType().ordinal()));
                    mSdk2MainBinding.TVTEMPMINVAL.setText("" + String.format("%.1f ", mTempMin, TemperatureUnit.DEGREE_C, mBobcat.getUnitType()) + TemperatureUnit.getUnitSymbol(mBobcat.getUnitType().ordinal()));
                    break;
                case RRSE:
                    byte[] result = (byte[]) msg.obj;
                    char[] hexDigits = new char[2];
                    hexDigits[0] = (char) result[0];
                    hexDigits[1] = (char) result[1];
                    String reg = new String(hexDigits);

                    switch (reg) {
                        case "B2":

                            hexDigits[0] = (char) result[2];
                            hexDigits[1] = (char) result[3];
                            int majorVer = Integer.parseInt(String.valueOf(hexDigits[0]), 16);
                            int minVer = Integer.parseInt(String.valueOf(hexDigits[1]));

                            mFWVer = majorVer + "." + minVer;
                            hexDigits[0] = (char) result[6];
                            hexDigits[1] = (char) result[7];
                            int buildVer = mFWBld = Integer.parseInt(String.valueOf(hexDigits), 16);
                            mFWVer += "." + buildVer;
                            mSdk2MainBinding.TVDEVFW.setText(String.format("%s %s S/N: %s",getString(R.string.SENXOR_DEV_FW),mFWVer, mFWSN));
                            break;
                        case "E0":
                            mFWSN = "SN";
                            hexDigits[0] = (char) result[2];
                            hexDigits[1] = (char) result[3];
                            mFWSN += new String(hexDigits);
                            hexDigits[0] = (char) result[6];
                            hexDigits[1] = (char) result[7];
                            mFWSN += new String(hexDigits);
                            hexDigits[0] = (char) result[10];
                            hexDigits[1] = (char) result[11];
                            mFWSN += new String(hexDigits);
                            hexDigits[0] = (char) result[14];
                            hexDigits[1] = (char) result[15];
                            mFWSN += new String(hexDigits);
                            hexDigits[0] = (char) result[18];
                            hexDigits[1] = (char) result[19];
                            mFWSN += new String(hexDigits);
                            hexDigits[0] = (char) result[22];
                            hexDigits[1] = (char) result[23];
                            mFWSN += new String(hexDigits);
                            mSdk2MainBinding.TVDEVFW.setText(String.format("%s %s \r\nS/N: %s",getString(R.string.SENXOR_DEV_FW),mFWVer, mFWSN));
                            break;
                        case "BA":

                            hexDigits[0] = (char) result[2];
                            hexDigits[1] = (char) result[3];
                            int type = Integer.parseInt(String.valueOf(hexDigits), 16);
                            switch (type) {
                                case 0:
                                case 1:
                                    mSenxorType = "Bobcat";
                                    mProcessor.setIsFilterEn(true);
                                    mBobcat.writeCmd("20", Integer.parseInt("000",2),0,false);  // Turn off FW STARK
                                    mBobcat.getProcessControl().setIsStarkEn(true);  // Turn on SW STARK
                                break;
                                case 2:
                                case 3:
                                case 4:
                                case 5:
                                    mSenxorType = "Cougar";
                                    mProcessor.setIsFilterEn(true);
                                    mBobcat.writeCmd("20", Integer.parseInt("000",2),0,false);  // Turn off FW STARK
                                    mBobcat.getProcessControl().setIsStarkEn(true);  // Turn on SW STARK

                                break;
                                case 6:
                                case 7:
                                    mSenxorType = "Panther";
                                    mBobcat.getProcessControl().setIsStarkEn(true);
                                break;
                                case 8:
                                    mSenxorType = "Cougar Hi Sens";
                                    mProcessor.setIsFilterEn(true);
                                    mBobcat.writeCmd("20", Integer.parseInt("000",2),0,false);  // Turn off FW STARK
                                    mBobcat.getProcessControl().setIsStarkEn(true);  // Turn on SW STARK
                                    break;
                            }//End switch
                            mBobcat.setFrameSizeByType(type);
                            if (type != 0 || type != 1) {
                                hexDigits[0] = (char) result[6];
                                hexDigits[1] = (char) result[7];
                                type = Integer.parseInt(String.valueOf(hexDigits), 16);
                            }//End if

                            switch (type) {
                                case 13:
                                    mModType = "IR36 Ge NFOV(44)";
                                    //mBobcat.setTemperatureOffset(0);
                                    break;
                                case 14:
                                    mModType = "IR37 GE WFOV(90)";
                                    //mBobcat.setTemperatureOffset(0);
                                    break;
                                case 15:
                                    mModType = "C035-N-2G";
                                    //mBobcat.setTemperatureOffset(0);
                                    break;
                                case 16:
                                    mModType = "C035-W-2";
                                    //mBobcat.setTemperatureOffset(0);
                                    break;
                                case 17:
                                    mModType = "SPO-NFOV";
                                    //mBobcat.setTemperatureOffset(0);
                                    break;
                                case 18:
                                    mModType = "SPO-WFOV";
                                    //mBobcat.setTemperatureOffset(0);
                                    break;
                                case 19:
                                    mModType = "MI08x2M5S (IR40) Si NFOV(44)";
                                    if (mFWBld > 100)  // Custom version
                                    {
                                        mBobcat.setTemperatureOffset(7.5F);
                                    }
                                    break;
                                case 20:
                                    mModType = "MI08x2M6S (IR41) Si WFOV(90)";
                                    if (mFWBld > 100)  // Custom version
                                    {
                                        mBobcat.setTemperatureOffset(11.5F);
                                    }
                                    break;
                                case 21:
                                    mModType = "MI08x2M7G (IR47) Si SFOV(110)";
                                    //mBobcat.setTemperatureOffset(0);
                                    break;
                                case 22:
                                    mModType = "TM-PO35-N03-WFOV";
                                    //mBobcat.setTemperatureOffset(0);
                                    break;
                                case 23:
                                    mModType = "MI0802M-2G NFOV10";
                                    mBobcat.setTemperatureOffset(0);
                                    break;
                                case 40:
                                    mModType = "MI1602 M5S NFOV 56";
                                    mBobcat.setTemperatureOffset(0);
                                    break;
                                case 41:
                                    mModType = "MI1602 M6C WFOV 110";
                                    mBobcat.setTemperatureOffset(0);
                                    break;
                                default:
                                    mModType = "MI0801";
                                    mBobcat.setTemperatureOffset(0);

                                    break;
                            }
                            mSdk2MainBinding.TVDEVTYPE.setText(""+mSenxorType+" - "+mModType);
                        break;
                        default:
                            Log.e("mUiUpdateHandler", R.string.ERR_CMD_NA + cmd.getCmdName() + ".");
                        break;
                    }
            }
        }

    };

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        //Binding setup
        this.mSdk2MainBinding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(this.mSdk2MainBinding.getRoot());

        // Setup broadcast receiver
        this.mSdk2BroadRec = new Sdk2BroadRec();
        this.mIntentFilter = new IntentFilter();
        this.mIntentFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);

        // Setup event handler
        Sdk2ClickListener clickListener = new Sdk2ClickListener();
        this.mSdk2MainBinding.BTNRUN.setOnClickListener(clickListener);
        this.mSdk2MainBinding.BTNROTATE.setOnClickListener(clickListener);
        this.mSdk2MainBinding.BTNDNN.setOnClickListener(clickListener);
        // SenXorEvkDevice
        this.mRotatePref = Integer.parseInt(getString(com.meridianinno.libsenxor_android.R.string.DEFAULT_ROTATE));
        this.mBobcat = new Bobcat(mEvkMsgUiUpdateHandler, this,mRotatePref);              //The 3rd argument defines the orientation of thermal image
        this.mBobcat.setUnitType(TemperatureUnit.DEGREE_C);
        this.mProcessor = this.mBobcat.getProcessControl();
        this.mRenderer = this.mBobcat.getRendererControl();
        this.mRotateVal = 0;
        if(this.mTof == null)
        {
            this.mTof = new Tof();
        }

        // Setup UI

    }

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


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

    //Do after onCreate or user returns to activity
    @Override
    protected void onResume()
    {
        super.onResume();
        //Register receiver
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
        {
            registerReceiver(this.mSdk2BroadRec, this.mIntentFilter, Context.RECEIVER_EXPORTED);
        }
        else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.TIRAMISU)
        {
            registerReceiver(this.mSdk2BroadRec, this.mIntentFilter,RECEIVER_EXPORTED);
        }
        else
        {
            registerReceiver(this.mSdk2BroadRec, this.mIntentFilter);
        }//End if-else

        this.mBobcat.open();
        if(!this.mBobcat.isEmpty())
        {
            this.mSdk2MainBinding.LLMAIN.setVisibility(View.VISIBLE);
            this.mSdk2MainBinding.TVMSG.setVisibility(View.INVISIBLE);
            this.mProcessor.setIsFilterEn(true);
            this.mProcessor.setIsDnnEn(true);

            this.mRenderer.setColorPaletteNum(0);

            this.mRenderer.setColorPaletteScaleMin((short) Math.round(TemperatureUnit.convert(21.0, TemperatureUnit.DEGREE_C, TemperatureUnit.KELVIN) * 10));
            this.mRenderer.setColorPaletteScaleMax((short) Math.round(TemperatureUnit.convert(36.0, TemperatureUnit.DEGREE_C, TemperatureUnit.KELVIN) * 10));

            //this.mBobcat.getSenXorFrameCBT().setIsCBTEnabled(true);
            this.mSdk2MainBinding.BTNRUN.callOnClick();
        }
        else
        {
            this.mSdk2MainBinding.LLMAIN.setVisibility(View.INVISIBLE);
            this.mSdk2MainBinding.TVMSG.setVisibility(View.VISIBLE);
        }
        this.mBobcat.readCmd_FW_VERSION();
        this.mBobcat.readCmd_MODULE_SN();
        this.mBobcat.readCmd_SENXOR_MODULE_TYPE();
    }

    @Override
    protected void onStop()
    {
        super.onStop();
        mBobcat.close();
        mRotateVal = 0;
        this.mSdk2MainBinding.IVSENXOR.setRotation(mRotateVal);
        this.mSdk2MainBinding.BTNROTATE.setText(R.string.btn_rotate_def);
    }


    /**
     * SenxorsdkExample2ClickHandler
     * Inner class defined the event handler of button
     */
    private class Sdk2ClickListener implements View.OnClickListener
    {

        @Override
        public void onClick(View view)
        {
            if(view.getId() == R.id.BTN_DNN)
            {
                if(mBobcat.getProcessControl().getIsDnnEn())
                {
                    mBobcat.getProcessControl().setIsDnnEn(false);
                    mSdk2MainBinding.BTNDNN.setIconResource(R.drawable.icon_aifilter_off);
                    mSdk2MainBinding.BTNDNN.setText(getString(R.string.SENXOR_DNN_OFF));
                }
                else
                {
                    mBobcat.getProcessControl().setIsDnnEn(true);
                    mSdk2MainBinding.BTNDNN.setIconResource(R.drawable.icon_aifilter);
                    mSdk2MainBinding.BTNDNN.setText(getString(R.string.SENXOR_DNN_ON));
                }
            }

            if(view.getId() == R.id.BTN_ROTATE)
            {
                mRotateVal += 90;                               //Change rotation by 90

                switch (mRotateVal)
                {
                    case 90:
                        mSdk2MainBinding.BTNROTATE.setText(R.string.btn_rotate_C);
                    break;
                    case 180:
                        mSdk2MainBinding.BTNROTATE.setText(R.string.btn_rotate_180);
                    break;
                    case 270:
                        mSdk2MainBinding.BTNROTATE.setText(R.string.btn_rotate_270);
                    break;
                    default:
                        mSdk2MainBinding.BTNROTATE.setText(R.string.btn_rotate_def);
                        mRotateVal = 0;
                    break;
                }// End switch
            }// End if

            if(view.getId() == R.id.BTN_RUN)
            {
                if(mBobcat.isEmpty())
                {
                    mSdk2MainBinding.LLMAIN.setVisibility(View.INVISIBLE);
                    mSdk2MainBinding.TVMSG.setVisibility(View.VISIBLE);
                }
                else
                {
                    mSdk2MainBinding.LLMAIN.setVisibility(View.VISIBLE);
                    mSdk2MainBinding.TVMSG.setVisibility(View.INVISIBLE);
                }

                if(!mBobcat.getIsRunning())
                {
                    mSdk2MainBinding.BTNRUN.setIconResource(R.drawable.icon_senxor_stop_light);
                    mBobcat.start();
                    mBobcat.getRendererControl().setMinMaxPtrMode(3);

                }
                else
                {
                    mSdk2MainBinding.BTNRUN.setIconResource(R.drawable.icon_senxor_start_light);
                    mSdk2MainBinding.BTNROTATE.setText(R.string.btn_rotate_def);
                    mBobcat.stop();
                    //Reset Rotation
                    mRotateVal = 0;

                }
            }
        }
    }

    private class Sdk2BroadRec extends BroadcastReceiver
    {

        @Override
        public void onReceive(Context context, Intent intent)
        {
            final String tAction = intent.getAction();
            if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(tAction))
            {

                mSdk2MainBinding.LLMAIN.setVisibility(View.INVISIBLE);
                mSdk2MainBinding.TVMSG.setVisibility(View.VISIBLE);
                mSdk2MainBinding.BTNRUN.setIconResource(R.drawable.icon_senxor_start_light);
                mSdk2MainBinding.BTNROTATE.setText(R.string.btn_rotate_def);
                mBobcat.stop();
                //Reset Rotation
                mRotateVal = 0;
            }//End if-else
        }
    }
}