package com.fingerprint.reader.test;

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

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.text.format.Time;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

import com.fpreader.fpdevice.AsyncUsbReader;
import com.fpreader.fpdevice.UsbReader;
import com.fpreader.fpdevice.UseManager;
import com.fpreader.fpdevice.AsyncUsbReader.OnGetImageListener;
import com.fpreader.fpdevice.AsyncUsbReader.OnUpImageListener;
import com.fpreader.fpdevice.AsyncUsbReader.OnGenTemplateListener;
import com.fpreader.fpdevice.AsyncUsbReader.OnRegModelListener;
import com.fpreader.fpdevice.AsyncUsbReader.OnUpTemplateListener;
import com.fpreader.fpdevice.AsyncUsbReader.OnCheckFingerListener;
import com.fpreader.fpdevice.AsyncUsbReader.OnDeviceStatusListener;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;

public class UsbTest2Activity extends AppCompatActivity {

    private AsyncUsbReader asyncDevice;
    private AsyncUsbReader asyncEnrol;
    private AsyncUsbReader asyncMatch;
    private boolean isAutoCap=false;
    private TextView tvStatus=null;
    private TextView tvResult=null;
    private ImageView ivImage=null;
    private volatile boolean isWorking=false;
    private volatile Boolean bCacel=false;

    private int iBufferID=1;
    private Bitmap fpimage=null;
    private Button buttonOpenDevice,buttonCloseDevice,buttonEnrol,buttonMatch,buttonSaveImage;
    private byte refdata[][]=new byte[1024][UsbReader.TP_SIZE_REF];
    private int refcount=0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_usb_test2);

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

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

        buttonOpenDevice=(Button)findViewById(R.id.buttonOpenDevice);
        buttonCloseDevice=(Button)findViewById(R.id.buttonCloseDevice);
        buttonEnrol=(Button)findViewById(R.id.buttonEnrol);
        buttonMatch=(Button)findViewById(R.id.buttonMatch);
        buttonSaveImage=(Button)findViewById(R.id.buttonSaveImage);
        tvStatus=(TextView)findViewById(R.id.textView1);
        tvResult=(TextView)findViewById(R.id.textView2);
        ivImage=(ImageView)findViewById(R.id.imageView1);


        buttonOpenDevice.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                if(UseManager.getInstance().OpenDevice()==0){
                    tvStatus.setText(getString(R.string.txt_opendeviceok));
                }else{
                    tvStatus.setText(getString(R.string.txt_opendevicefail));
                }
            }
        });

        buttonCloseDevice.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                StopCurrentWork();
                UseManager.getInstance().CloseDevice();
                tvStatus.setText(getString(R.string.txt_closedevice));
            }
        });

        buttonEnrol.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(isWorking)
                    return;
                if(UseManager.getInstance().IsOpen()) {
                    iBufferID = 1;
                    tvStatus.setText(getString(R.string.txt_placfinger));
                    asyncEnrol.GetImage();
                    isWorking=true;
                }
            }
        });

        buttonMatch.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(UseManager.getInstance().IsOpen()) {
                    if(isAutoCap){
                        bCacel=true;
                        isAutoCap=false;
                        SetButtonsStatus(true);
                        tvStatus.setText(R.string.txt_status);
                    }else {
                        if(isWorking)
                            return;
                        isAutoCap=true;
                        SetButtonsStatus(false);
                        tvStatus.setText(getString(R.string.txt_placfinger));
                        asyncMatch.GetImage();
                        isWorking=true;
                    }
                }
            }
        });

        buttonSaveImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(fpimage!=null)
                    SaveImage(fpimage);
            }
        });

        FPDeviceInit();
        FPEnrolInit();
        FPMatchInit();
        //ResumeRegister();
        //requestPermission();
    }

    private void StopCurrentWork(){
        if(isWorking) {
            bCacel = true;
            //SystemClock.sleep(500);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

        /*
        if(isWorking) {
            bCacel=true;
            do {
                SystemClock.sleep(100);
            } while (isWorking);
        }
        */
    }

    private void SetButtonsStatus(boolean enable){
        if(enable){
            buttonOpenDevice.setEnabled(true);
            buttonCloseDevice.setEnabled(true);
            buttonEnrol.setEnabled(true);
            buttonMatch.setEnabled(true);
            buttonMatch.setText(R.string.txt_MatchTemplate);
        }
        else{
            buttonOpenDevice.setEnabled(false);
            buttonCloseDevice.setEnabled(false);
            buttonEnrol.setEnabled(false);
            buttonMatch.setEnabled(true);
            buttonMatch.setText(R.string.txt_StopCapture);
        }
    }

    private void FPDeviceInit(){
        asyncDevice=UseManager.getInstance().getAsyncUsbReader(this);
        asyncDevice.setOnDeviceStatusListener(new OnDeviceStatusListener() {
            @Override
            public void onReady() {
                tvStatus.setText(getString(R.string.txt_deviceready));
                if(UseManager.getInstance().OpenDevice()==0){
                    tvStatus.setText(getString(R.string.txt_opendeviceok));
                }else{
                    tvStatus.setText(getString(R.string.txt_opendevicefail));
                }
            }

            @Override
            public void onNoFound() {
                tvStatus.setText(getString(R.string.txt_nofounddevice));
            }

            @Override
            public void onNoPermission() {
                tvStatus.setText(getString(R.string.txt_requestpermission));
            }

            @Override
            public void onAttached() {
                tvStatus.setText(getString(R.string.txt_usbattached));
                asyncDevice.RequestPermission(UsbTest2Activity.this);
            }

            @Override
            public void onDetached() {
                tvStatus.setText(getString(R.string.txt_usbdetached));
                UseManager.getInstance().CloseDevice();
            }

            @Override
            public void onError() {
                tvStatus.setText("Error!");
            }
        });
        asyncDevice.ResumeRegister(this);
        asyncDevice.RequestPermission(this);
    }

    private void FPDeviceDeInit(){
        asyncDevice.PauseUnRegister(this);
        UseManager.getInstance().CloseDevice();
    }

    private void FPEnrolInit(){
        asyncEnrol= UseManager.getInstance().getAsyncUsbReader(this);

        asyncEnrol.setOnGetImageListener(new OnGetImageListener(){
            @Override
            public void onGetImageSuccess() {
                //Display Image
                tvStatus.setText(getString(R.string.txt_liftfinger));
                asyncEnrol.UpImage();
                //No Display Image
                //aysncEnrol.GenTemplate(1);
            }

            @Override
            public void onGetImageFail() {
                if(bCacel){
                    bCacel=false;
                    isWorking=false;
                    tvStatus.setText(getString(R.string.txt_cancl));
                }else {
                    asyncEnrol.GetImage();
                }
            }
        });

        asyncEnrol.setOnUpImageListener(new OnUpImageListener() {
            @Override
            public void onUpImageSuccess(byte[] data) {
                //8Bit
                fpimage = BitmapFactory.decodeByteArray(data, 0, data.length);
                //32Bit
                //fpimage= asyncEnrol.getUsbReader().Bitmap8toBitmap32(data,asyncEnrol.getUsbReader().ImageWidth,asyncEnrol.getUsbReader().ImageHeight);
                ivImage.setImageBitmap(fpimage);
                asyncEnrol.GenTemplate(iBufferID);
            }

            @Override
            public void onUpImageFail() {
                tvStatus.setText(getString(R.string.txt_generatetemplatefail));
                isWorking=false;
            }
        });

        asyncEnrol.setOnGenTemplateListener(new OnGenTemplateListener() {
            @Override
            public void onGenTemplateSuccess(int bufferId) {
                if(bufferId==1){
                    iBufferID=2;
                    asyncEnrol.CheckFinger();
                }else {
                    asyncEnrol.RegModel();
                }
            }

            @Override
            public void onGenTemplateFail() {
                tvStatus.setText(getString(R.string.txt_generatetemplatefail));
                isWorking=false;
            }
        });

        asyncEnrol.setOnCheckFingerListener(new OnCheckFingerListener() {
            @Override
            public void onFingerSuccess() {
                asyncEnrol.CheckFinger();
            }

            @Override
            public void onFingerFail() {
                tvStatus.setText(getString(R.string.txt_placfinger));
                asyncEnrol.GetImage();
            }
        });


        asyncEnrol.setOnRegModelListener(new OnRegModelListener() {
            @Override
            public void onRegModelSuccess() {
                asyncEnrol.UpTemplate();
            }

            @Override
            public void onRegModelFail() {
                tvStatus.setText(getString(R.string.txt_generatetemplatefail));
                isWorking=false;
            }
        });

        asyncEnrol.setOnUpTemplateListener(new OnUpTemplateListener() {
            @Override
            public void onUpTemplateSuccess(byte[] model) {

                tvStatus.setText(getString(R.string.txt_enroltemplateok));
                //Enrol
                System.arraycopy(model,0,refdata[refcount],0,UsbReader.TP_SIZE_REF);
                tvStatus.setText(getString(R.string.txt_enroltemplateok)+" "+String.valueOf(refcount));
                refcount++;

                isWorking=false;
            }

            @Override
            public void onUpTemplateFail() {
                tvStatus.setText(getString(R.string.txt_generatetemplatefail));
                isWorking=false;
            }
        });
    }

    private void FPMatchInit(){
        asyncMatch= UseManager.getInstance().getAsyncUsbReader(this);

        asyncMatch.setOnGetImageListener(new OnGetImageListener(){
            @Override
            public void onGetImageSuccess() {
                //Display Image
                tvStatus.setText(getString(R.string.txt_liftfinger));
                asyncMatch.UpImage();
                //No Display Image
                //vFingerprint.GenTemplate(1);
            }

            @Override
            public void onGetImageFail() {
                if(bCacel){
                    bCacel=false;
                    isWorking=false;
                    isAutoCap=false;
                    tvStatus.setText(getString(R.string.txt_cancl));
                    SetButtonsStatus(true);
                }else {
                    asyncMatch.GetImage();
                }
            }
        });

        asyncMatch.setOnUpImageListener(new OnUpImageListener() {
            @Override
            public void onUpImageSuccess(byte[] data) {
                //8Bit
                fpimage = BitmapFactory.decodeByteArray(data, 0, data.length);
                //32Bit
                //fpimage= vFingerprint.usbReader.Bitmap8toBitmap32(data,vFingerprint.usbReader.ImageWidth,vFingerprint.usbReader.ImageHeight);
                ivImage.setImageBitmap(fpimage);
                asyncMatch.GenTemplate(1);
            }

            @Override
            public void onUpImageFail() {
                tvStatus.setText(getString(R.string.txt_generatetemplatefail));
                SetButtonsStatus(true);
                isWorking=false;
                isAutoCap=false;
            }
        });

        asyncMatch.setOnGenTemplateListener(new OnGenTemplateListener() {
            @Override
            public void onGenTemplateSuccess(int bufferId) {
                asyncMatch.UpTemplate();
            }

            @Override
            public void onGenTemplateFail() {
                tvStatus.setText(getString(R.string.txt_generatetemplatefail));
                SetButtonsStatus(true);
                isWorking=false;
                isAutoCap=false;
            }
        });

        asyncMatch.setOnUpTemplateListener(new OnUpTemplateListener() {
            @Override
            public void onUpTemplateSuccess(byte[] model) {

                tvStatus.setText(getString(R.string.txt_generatetemplateok));

                if(refcount>0) {
                    boolean bfind = false;
                    for (int i = 0; i < refcount; i++) {
                        int sc = asyncMatch.MatchTemplate(refdata[i], model);
                        if(sc>=60) {
                            bfind=true;
                            tvResult.setText(String.format(getString(R.string.txt_matchok), i));
                            break;
                        }
                    }
                    if(!bfind){
                        tvResult.setText(getString(R.string.txt_matchfail));
                    }
                    if(isAutoCap) {
                        asyncMatch.GetImage();
                        tvStatus.setText(getString(R.string.txt_placfinger));
                    }
                }else{
                    SetButtonsStatus(true);
                    isWorking=false;
                    isAutoCap=false;
                }
            }

            @Override
            public void onUpTemplateFail() {
                tvStatus.setText(getString(R.string.txt_generatetemplatefail));
                SetButtonsStatus(true);
                isWorking=false;
                isAutoCap=false;
            }
        });
    }

    @Override
    protected void onPause() {
        //PauseUnRegister();
        super.onPause();
    }

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

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

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        return true;
    }

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

    private void SaveImage(Bitmap image){
        String storageDir = Environment.getExternalStorageDirectory().getPath().toString();
        //String curPath=storageDir+"/Fingerprint";
        String curPath=storageDir+"/FPS";
        File file = new File(curPath);
        if (!file.exists()) {
            curPath=storageDir+"/"+Environment.DIRECTORY_PICTURES;
        }

        //Toast.makeText(this, curPath+"/"+getDataTimeForID()+".png", Toast.LENGTH_LONG).show();

        File f = new File(curPath+"/"+getDataTimeForID()+".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();
        }

        //*
        f = new File(curPath+"/"+getDataTimeForID()+".jpg");
        if (f.exists()) {
            f.delete();
        }
        try {
            FileOutputStream out = new FileOutputStream(f);
            image.compress(Bitmap.CompressFormat.JPEG, 90, out);
            out.flush();
            out.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
       // */
    }

    public static String getDataTimeForID(){
        Time t=new Time();
        t.setToNow();
        int year = t.year;
        int month = t.month+1;
        int date = t.monthDay;
        int hour = t.hour;
        int minute = t.minute;
        int second = t.second;
        return String.format("%d%02d%02d%02d%02d%02d",year,month,date,hour,minute,second);
    }

}
