package com.fingerprint.reader.test;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.fpreader.fpdevice.BluetoothReader;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;

public class BluetoothDeviceTest1Activity extends AppCompatActivity {

    private BluetoothAdapter mBluetoothAdapter = null;
    private BluetoothReader mBluetoothReader =null;

    private String btAddress="";
    private boolean bAutoLink=false;
    private Timer linkTimer;
    private TimerTask linkTask;
    private Handler linkHandler;

    private TextView mTitle;
    private ListView mConversationView;
    private ImageView fingerprintImage;
    private String mConnectedDeviceName = null;
    private ArrayAdapter<String> mConversationArrayAdapter;

    public  int worktype=0;

    public byte mRefData[][]=new byte[1024][BluetoothReader.TP_SIZE_REF];
    public int mRefSize=0;
    public int mRefCount=0;
    public byte mMatData[]=new byte[BluetoothReader.TP_SIZE_REF];
    public int mMatSize=0;

    public byte mBat[]=new byte[2];
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_bluetooth_test1);

        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.test1), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });

        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (mBluetoothAdapter == null) {
            Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show();
            finish();
            return;
        }

        SharedPreferences sp;
        sp = PreferenceManager.getDefaultSharedPreferences(this);
        btAddress =sp.getString("device","");
    }

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

        if (!mBluetoothAdapter.isEnabled()) {
            Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                return;
            }
            startActivityForResult(enableIntent, BluetoothDeviceListActivity.REQUEST_ENABLE_BT);
        }else{
            if(mBluetoothReader==null){
                InitViews();
                mBluetoothReader = new BluetoothReader(this, mHandler);
                mBluetoothReader.InitMatch();
                //mBluetoothReader.SetOldDevice(true);
                AddStatusList(btAddress);
                if(bAutoLink){
                    LinkStart();
                }
            }
        }
    }

    @Override
    public synchronized void onResume() {
        super.onResume();
        if (mBluetoothReader != null) {
            if (mBluetoothReader.getState() == mBluetoothReader.STATE_NONE) {
                mBluetoothReader.start();
            }
        }
    }

    @Override
    public synchronized void onPause() {
        super.onPause();
    }

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

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mBluetoothReader != null)
            mBluetoothReader.stop();
    }

    @SuppressLint("HandlerLeak")
    public void LinkStart(){
        linkTimer = new Timer();
        linkHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                linkStop();

                if(btAddress.length()>=12){
                    BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(btAddress);
                    mBluetoothReader.connect(device);
                }

                super.handleMessage(msg);
            }
        };
        linkTask = new TimerTask() {
            @Override
            public void run() {
                Message message = new Message();
                message.what = 1;
                linkHandler.sendMessage(message);
            }
        };
        linkTimer.schedule(linkTask, 1000, 1000);
    }

    public void linkStop(){
        if (linkTimer!=null){
            linkTimer.cancel();
            linkTimer = null;
            linkTask.cancel();
            linkTask=null;
        }
    }

    private void InitViews(){
        mConversationArrayAdapter = new ArrayAdapter<String>(this, R.layout.message);
        mConversationView = (ListView) findViewById(R.id.in);
        mConversationView.setAdapter(mConversationArrayAdapter);

        fingerprintImage=(ImageView)findViewById(R.id.imageView1);
        mTitle=(TextView)findViewById(R.id.textView1);

        final Button btnEnrolNoImage = (Button) findViewById(R.id.btnEnrolNoImage);
        btnEnrolNoImage.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                if(mBluetoothReader.getState()==BluetoothReader.STATE_CONNECTED) {
                    AddStatusList(getString(R.string.txt_placefinger2));
                    mBluetoothReader.EnrolToHost();
                }
            }
        });

        final Button btnCaptureNoImage = (Button) findViewById(R.id.btnCaptureNoImage);
        btnCaptureNoImage.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                if(mBluetoothReader.getState()==BluetoothReader.STATE_CONNECTED) {
                    AddStatusList(getString(R.string.txt_placefinger1));
                    mBluetoothReader.CaptureToHost();
                }
            }
        });

        final Button btnEnrolWithImage = (Button) findViewById(R.id.btnEnrolWithImage);
        btnEnrolWithImage.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                if(mBluetoothReader.getState()==BluetoothReader.STATE_CONNECTED) {
                    worktype = 0;
                    AddStatusList(getString(R.string.txt_placefinger1));
                    mBluetoothReader.GetImageAndDate();
                }
            }
        });

        final Button btnCaptureWithImage = (Button) findViewById(R.id.btnCaptureWithImage);
        btnCaptureWithImage.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                if(mBluetoothReader.getState()==BluetoothReader.STATE_CONNECTED) {
                    worktype = 1;
                    AddStatusList(getString(R.string.txt_placefinger1));
                    mBluetoothReader.GetImageAndDate();
                }
            }
        });

        final Button btnGetSN = (Button) findViewById(R.id.btnGetSN);
        btnGetSN.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                if(mBluetoothReader.getState()==BluetoothReader.STATE_CONNECTED) {
                    mBluetoothReader.GetDeviceSn();
                }
            }
        });

        final Button btnGetBatVal = (Button) findViewById(R.id.btnGetBatVal);
        btnGetBatVal.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                if(mBluetoothReader.getState()==BluetoothReader.STATE_CONNECTED) {
                    mBluetoothReader.GetBatVal();
                }
            }
        });

        final Button btnCloseDevice = (Button) findViewById(R.id.btnCloseDevice);
        btnCloseDevice.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                if(mBluetoothReader.getState()==BluetoothReader.STATE_CONNECTED) {
                    mBluetoothReader.CloseDevvice();
                }
            }
        });

    }

    private void AddStatusList(String text) {
        mConversationArrayAdapter.add(text);
    }

    private void AddStatusListHex(byte[] data,int size) {
        String text="";
        for(int i=0;i<size;i++) {
            text=text+","+Integer.toHexString(data[i]&0xFF).toUpperCase();
        }
        mConversationArrayAdapter.add(text);
    }

    private void ShowDataHex(byte[] data,int size) {
        /*
        String text="";
        for(int i=0;i<size;i++) {
            text=text+","+Integer.toHexString(data[i]&0xFF).toUpperCase();
        }
        View layout = LayoutInflater.from(this).inflate(R.layout.toast, null);
        TextView textView1 = (TextView) layout.findViewById(R.id.toast_text1);
        TextView textView2 = (TextView) layout.findViewById(R.id.toast_text2);
        textView1.setText(String.valueOf(size));
        textView2.setText(text);
        Toast toast = new Toast(this);
        toast.setGravity(Gravity.CENTER, 0, 0);
        toast.setDuration(Toast.LENGTH_LONG);
        toast.setView(layout);
        toast.show();
        */
    }

    @SuppressLint("HandlerLeak")
    private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case BluetoothReader.MESSAGE_STATE_CHANGE:
                    switch (msg.arg1) {
                        case BluetoothReader.STATE_CONNECTED:
                            mTitle.setText(R.string.title_connected_to);
                            mTitle.append(mConnectedDeviceName);
                            mConversationArrayAdapter.clear();
                            break;
                        case BluetoothReader.STATE_CONNECTING:
                            mTitle.setText(R.string.title_connecting);
                            break;
                        case BluetoothReader.STATE_LISTEN:
                        case BluetoothReader.STATE_NONE:
                            mTitle.setText(R.string.title_not_connected);
                            break;
                    }
                    break;
                case BluetoothReader.MESSAGE_WRITE:
                    break;
                case BluetoothReader.MESSAGE_READ:
                    break;
                case BluetoothReader.MESSAGE_DEVICE_NAME:
                    mConnectedDeviceName = msg.getData().getString(BluetoothReader.DEVICE_NAME);
                    Toast.makeText(getApplicationContext(), getString(R.string.txt_connectedto) + mConnectedDeviceName, Toast.LENGTH_SHORT).show();
                    break;
                case BluetoothReader.MESSAGE_TOAST:
                    //Toast.makeText(getApplicationContext(), msg.getData().getString(BluetoothReader.TOAST),Toast.LENGTH_SHORT).show();
                    switch(msg.getData().getInt(BluetoothReader.MSGVAL)) {
                        case BluetoothReader.MSG_UNABLE:
                            Toast.makeText(getApplicationContext(),getString(R.string.title_unable_connected),Toast.LENGTH_SHORT).show();
                            break;
                        case BluetoothReader.MSG_LOST:
                            Toast.makeText(getApplicationContext(), getString(R.string.title_lost_connected),Toast.LENGTH_SHORT).show();
                            break;
                    }
                    break;
                case BluetoothReader.CMD_GETDEVTYPE:
                    if(msg.arg1==1){
                        AddStatusList(getString(R.string.txt_devicetype)+String.format("%08X",msg.arg2));
                    }else
                        AddStatusList(getString(R.string.txt_getdevicefail));
                    break;
                case BluetoothReader.CMD_GETDEVINFO:
                    if(msg.arg1==1){
                        AddStatusList(getString(R.string.txt_devicetype)+String.format("%08X",mBluetoothReader.mDeviceInfo.DeviceType));

                        //String sn=new String(mBluetoothReader.mDeviceInfo.DeviceSN);
                        //AddStatusList(getString(R.string.txt_devicesn)+sn);
                        String sn = "";
                        for(int i=0;i<8;i++)
                            sn=sn+String.format("%02X",mBluetoothReader.mDeviceInfo.DeviceSN[i]);
                        AddStatusList(getString(R.string.txt_devicesn)+sn);

                        AddStatusList(getString(R.string.txt_devicever)+String.valueOf(mBluetoothReader.mDeviceInfo.Version));
                        AddStatusList(getString(R.string.txt_devicesensor)+String.valueOf(mBluetoothReader.mDeviceInfo.SensorType));

                    }else
                        AddStatusList(getString(R.string.txt_getdevicefail));
                    break;

                case BluetoothReader.CMD_GETSTDIMAGE:
                    if(msg.arg1==1){
                        byte[] bmpdata = null;
                        bmpdata=mBluetoothReader.getFingerprintImage((byte[]) msg.obj,256,288,0);

                        //32Bit
                        Bitmap bitmap = mBluetoothReader.Image8toBitmap32(bmpdata,256,288);//
                        //8Bit
                        //Bitmap bitmap = BitmapFactory.decodeByteArray(bmpdata, 0,bmpdata.length);

                        fingerprintImage.setImageBitmap(bitmap);

                        //SaveImage(bitmap);

                        AddStatusList(getString(R.string.txt_getimageok));
                    }else{
                        AddStatusList(getString(R.string.txt_getimagefail));
                    }
                    break;
                case BluetoothReader.CMD_GETRESIMAGE:
                    if(msg.arg1==1){
                        byte[] bmpdata = null;
                        int bmpwidth=0,bmpheight=0;
                        switch(msg.arg2){
                            case BluetoothReader.IMAGESIZE_152_200:
                                bmpdata=mBluetoothReader.getFingerprintImage((byte[]) msg.obj,152,200,0);
                                bmpwidth=152;
                                bmpheight=200;
                                break;
                            case BluetoothReader.IMAGESIZE_256_288:
                                bmpdata=mBluetoothReader.getFingerprintImage((byte[]) msg.obj,256,288,0);
                                bmpwidth=256;
                                bmpheight=288;
                                break;
                            case BluetoothReader.IMAGESIZE_256_360:
                                bmpdata=mBluetoothReader.getFingerprintImage((byte[]) msg.obj,256,360,0);
                                bmpwidth=256;
                                bmpheight=360;
                                break;
                        }

                        //32Bit
                        Bitmap bitmap = mBluetoothReader.Image8toBitmap32(bmpdata,bmpwidth,bmpheight);//
                        //8Bit
                        //Bitmap bitmap = BitmapFactory.decodeByteArray(bmpdata, 0,bmpdata.length);

                        fingerprintImage.setImageBitmap(bitmap);

                        //SaveImage(bitmap);

                        AddStatusList(getString(R.string.txt_getimageok));
                    }else{
                        AddStatusList(getString(R.string.txt_getimagefail));
                    }
                    break;
                case BluetoothReader.CMD_GETSTDCHAR:
                case BluetoothReader.CMD_GETRESCHAR:
                    if(msg.arg1==1){
                        if(worktype==1){
                            mBluetoothReader.memcpy(mMatData,0,(byte[]) msg.obj,0,msg.arg2);
                            mMatSize=msg.arg2;
                            ShowDataHex(mMatData,mMatSize);
                            AddStatusList(getString(R.string.txt_captureok));

                            if(mRefCount>0) {
                                boolean bfind=false;
                                for(int i=0;i<mRefCount;i++) {
                                    int score = mBluetoothReader.MatchTemplate(mRefData[i], mMatData);
                                    if(score>=60) {
                                        bfind=true;
                                        AddStatusList(getString(R.string.txt_matchscore) + String.valueOf(score)+" "+getString(R.string.txt_matchindex)+String.valueOf(i));
                                        break;
                                    }
                                }
                                if(!bfind) {
                                   AddStatusList(getString(R.string.txt_matchfail));
                                }
                            }

                        }else{
                            mBluetoothReader.memcpy(mRefData[mRefCount],0,(byte[]) msg.obj,0,msg.arg2);
                            mRefSize=msg.arg2;
                            ShowDataHex(mRefData[mRefCount],mRefSize);
                            AddStatusList(getString(R.string.txt_enrolok)+" "+String.valueOf(mRefCount));
                            mRefCount++;
                        }

                    }else {
                        if(worktype==1){
                            AddStatusList(getString(R.string.txt_capturefail));
                        }else{
                            AddStatusList(getString(R.string.txt_enrolfail));
                        }
                    }
                    break;
                case BluetoothReader.CMD_ENROLHOST:
                    if(msg.arg1==1){
                        mRefSize=msg.arg2;
                        mBluetoothReader.memcpy(mRefData[mRefCount],0, (byte[])msg.obj,0,msg.arg2);
                        AddStatusList(getString(R.string.txt_enrolok)+" "+String.valueOf(mRefCount));
                        ShowDataHex(mRefData[mRefCount],mRefSize);
                        mRefCount++;
                    }else
                        AddStatusList(getString(R.string.txt_enrolfail));
                    break;
                case BluetoothReader.CMD_CAPTUREHOST:
                    if(msg.arg1==1){
                        mMatSize=msg.arg2;
                        mBluetoothReader.memcpy(mMatData,0, (byte[]) msg.obj,0,msg.arg2);
                        ShowDataHex(mMatData,mMatSize);
                        AddStatusList(getString(R.string.txt_captureok));

                        if(mRefCount>0) {
                            boolean bfind=false;
                            for(int i=0;i<mRefCount;i++) {
                                int score = mBluetoothReader.MatchTemplate(mRefData[i], mMatData);
                                if(score>=60) {
                                    bfind=true;
                                    AddStatusList(getString(R.string.txt_matchscore) + String.valueOf(score)+" "+getString(R.string.txt_matchindex)+String.valueOf(i));
                                    break;
                                }
                            }
                            if(!bfind) {
                                AddStatusList(getString(R.string.txt_matchfail));
                            }
                        }
                    }else
                        AddStatusList(getString(R.string.txt_capturefail));
                    break;
                case BluetoothReader.CMD_GETSN:
                    if(msg.arg1==1){
                        String sn=new String(mBluetoothReader.mDeviceInfo.DeviceSN);
                        AddStatusList(getString(R.string.txt_devicesn)+sn);
                    }else
                        AddStatusList(getString(R.string.txt_getsnfail));
                    break;
                case BluetoothReader.CMD_GETBAT:
                    if(msg.arg1==1){
                        mBluetoothReader.memcpy(mBat,0,(byte[]) msg.obj,0,msg.arg2);
                        AddStatusList(getString(R.string.txt_batval)+Integer.toString(mBat[0]/10)+"."+Integer.toString(mBat[0]%10)+"V");
                    }else
                        AddStatusList(getString(R.string.txt_getbatvalfail));
                    break;
                case BluetoothReader.CMD_SHUTDOWNDEVICE: {
                    if(msg.arg1==1){
                        AddStatusList(getString(R.string.txt_closeok));
                    } else
                        AddStatusList(getString(R.string.txt_closefail));
                }
                break;
            }
        }
    };

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_bluetooth_test, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if(id==R.id.action_linkdevice){
            LinkBluetoothReader();
            return true;
        }else if(id==android.R.id.home){
            this.finish();
        }
        return super.onOptionsItemSelected(item);
    }

    public void LinkBluetoothReader(){
        Intent serverIntent = new Intent(BluetoothDeviceTest1Activity.this, BluetoothDeviceListActivity.class);
        startActivityForResult(serverIntent, BluetoothDeviceListActivity.REQUEST_CONNECT_DEVICE);
    }

    @SuppressLint("MissingSuperCall")
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case BluetoothDeviceListActivity.REQUEST_CONNECT_DEVICE:
                if (resultCode == Activity.RESULT_OK) {

                    mBluetoothReader.stop();

                    String address = data.getExtras().getString(BluetoothDeviceListActivity.EXTRA_DEVICE_ADDRESS);
                    BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
                    mBluetoothReader.connect(device);

                    btAddress = address;

                    SharedPreferences sp;
                    sp = PreferenceManager.getDefaultSharedPreferences(this);
                    SharedPreferences.Editor edit=sp.edit();
                    edit.putString("device",btAddress);
                    edit.commit();
                }
                break;
            case BluetoothDeviceListActivity.REQUEST_ENABLE_BT:
                if (resultCode == Activity.RESULT_OK) {
                    if(mBluetoothReader==null)
                        InitViews();
                    mBluetoothReader = new BluetoothReader(this, mHandler);
                    mBluetoothReader.InitMatch();
                    //mBluetoothReader.SetOldDevice(true);

                    if(bAutoLink){
                        if(btAddress.length()>=12){
                            BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(btAddress);
                            mBluetoothReader.connect(device);
                        }
                    }
                }else{
                    Toast.makeText(this, R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show();
                    finish();
                }
                break;
        }
    }

    private void SaveImage(Bitmap image){
        String storageDir = Environment.getExternalStorageDirectory().toString();
        String curPath=storageDir+"/Pictures/Fingerprint";

        File file = new File(curPath);
        if (!file.exists()) {
            file.mkdirs();
        }

        File f = new File(curPath+"/fp.png");
        if (f.exists()) {
            f.delete();
        }
        try {
            FileOutputStream out = new FileOutputStream(f);
            image.compress(Bitmap.CompressFormat.PNG, 100, out);
            out.flush();
            out.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}