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.SystemClock;
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 java.util.HashMap;
import java.util.Iterator;

public class UsbTest4Activity extends AppCompatActivity {
    public static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
    private PendingIntent mPermissionIntent;
    private IntentFilter filter;

    private AsyncUsbReader asyncEnrol;
    private AsyncUsbReader asyncMatch;

    private TextView tvStatus=null;
    private ImageView ivImage=null;
    private int iBufferID=1;
    private  int pageid=0;

    private volatile boolean isWorking=false;
    private volatile Boolean bCacel=false;

    private byte[][] tplsit=new byte[100][UsbReader.TP_SIZE_REF];
    private int tpcount=0;

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

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

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

        final Button buttonOpenDevice=(Button)findViewById(R.id.buttonOpenDevice);
        final Button buttonCloseDevice=(Button)findViewById(R.id.buttonCloseDevice);
        final Button buttonEnrolID=(Button)findViewById(R.id.buttonEnrolID);
        final Button buttonSearchID=(Button)findViewById(R.id.buttonSearchID);
        final Button buttonClearID=(Button)findViewById(R.id.buttonClearID);
        tvStatus=(TextView)findViewById(R.id.textView1);
        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));
            }
        });

        buttonEnrolID.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;
                }
            }
        });

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

        buttonClearID.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(isWorking)
                    return;
                if(UseManager.getInstance().IsOpen()) {
                    if(UseManager.getInstance().getUsbReader().FPEmpty(0xFFFFFFFF)==0) {
                        pageid = 0;
                        tvStatus.setText(R.string.clear_ok);
                    }else{
                        tvStatus.setText(R.string.clear_fail);
                    }
                }
            }
        });

        FPInit();
        ResumeRegister();
        requestPermission();
    }

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

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

        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        asyncEnrol.setOnGetImageListener(new OnGetImageListener(){
            @Override
            public void onGetImageSuccess() {
                tvStatus.setText(getString(R.string.txt_liftfinger));
                //Display Image
                asyncEnrol.UpImage();
                //No Display Image
                //vFingerprint.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) {
               Bitmap image = BitmapFactory.decodeByteArray(data, 0, data.length);
               ivImage.setImageBitmap(image);
                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 AsyncUsbReader.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() {
                if(asyncEnrol.getUsbReader().FPStoreChar(0xFFFFFFFF,01,pageid)==0){
                    tvStatus.setText("Store OK:"+String.valueOf(pageid));
                    pageid++;
                    isWorking=false;
                }else{
                    tvStatus.setText("Store Fail");
                    isWorking=false;
                }
            }

            @Override
            public void onRegModelFail() {
                tvStatus.setText("Enrol Fail");
                isWorking=false;
            }
        });

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

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

        asyncMatch.setOnUpImageListener(new OnUpImageListener() {
            @Override
            public void onUpImageSuccess(byte[] data) {
                Bitmap image = BitmapFactory.decodeByteArray(data, 0, data.length);
                ivImage.setImageBitmap(image);
                asyncMatch.GenTemplate(1);
            }
            @Override
            public void onUpImageFail() {
                tvStatus.setText(getString(R.string.txt_generatetemplatefail));
                isWorking=false;
            }
        });

        asyncMatch.setOnGenTemplateListener(new OnGenTemplateListener() {
            @Override
            public void onGenTemplateSuccess(int bufferId) {
                int[] mb=new int[1];
                int[] sc=new int[1];
                if(asyncMatch.getUsbReader().FPSearch(0xFFFFFFFF,bufferId,0,100,mb,sc)==0){
                    tvStatus.setText("Search OK:"+String.valueOf(mb[0]));
                }else{
                    tvStatus.setText("Search Fail");
                }
                isWorking=false;
            }
            @Override
            public void onGenTemplateFail() {
                tvStatus.setText(getString(R.string.txt_generatetemplatefail));
                isWorking=false;
            }
        });

    }

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

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

    @Override
    protected void onDestroy(){
        super.onDestroy();
        StopCurrentWork();
        UseManager.getInstance().CloseDevice();
        PauseUnRegister();
    }

    private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (ACTION_USB_PERMISSION.equals(action)) {
                synchronized (this) {
                    UsbDevice device  = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                        if(device != null){
                            tvStatus.setText(getString(R.string.txt_deviceready));
                        }else{
                            tvStatus.setText(getString(R.string.txt_nofounddevice));
                        }
                    }else{
                        tvStatus.setText(getString(R.string.txt_opendevicefail));
                    }
                }
            } else if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
                //final UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                tvStatus.setText(getString(R.string.txt_usbattached));
                requestPermission();
            } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
                //final UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                tvStatus.setText(getString(R.string.txt_usbdetached));
                //CloseDevice();
            }
        }
    };

    public void requestPermission(){
        UsbManager pmusbManager=(UsbManager)((Activity)this).getSystemService(Context.USB_SERVICE);
        if(pmusbManager==null){
            tvStatus.setText(getString(R.string.txt_opendevicefail));
            return;
        }

        UsbDevice pmusbDevice=null;
        HashMap<String,UsbDevice> devlist=pmusbManager.getDeviceList();
        Iterator<UsbDevice> deviter= devlist.values().iterator();
        while(deviter.hasNext())
        {
            UsbDevice tmpusbdev = deviter.next();
            if((tmpusbdev.getVendorId()==0x0453)&&(tmpusbdev.getProductId()==0x9005))
            {
                pmusbDevice=tmpusbdev;
                break;
            }else if((tmpusbdev.getVendorId()==0x2009)&&(tmpusbdev.getProductId()==0x7638))
            {
                pmusbDevice=tmpusbdev;
                break;
            }else if((tmpusbdev.getVendorId()==0x2109)&&(tmpusbdev.getProductId()==0x7638))
            {
                pmusbDevice=tmpusbdev;
                break;
            }else if((tmpusbdev.getVendorId()==0x0483)&&(tmpusbdev.getProductId()==0x5720))
            {
                pmusbDevice=tmpusbdev;
                break;
            }
        }

        if(pmusbDevice!=null){
            if(!pmusbManager.hasPermission(pmusbDevice)){
                //synchronized (mUsbReceiver) {
                pmusbManager.requestPermission(pmusbDevice, mPermissionIntent);
                //}
            }else{
                //OpenDevice();
                tvStatus.setText(getString(R.string.txt_deviceready));
            }
        }

    }

    @SuppressLint({"UnspecifiedRegisterReceiverFlag", "UnspecifiedImmutableFlag"})
    public void ResumeRegister(){
        if(Build.VERSION.SDK_INT>=31)
            mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE);
        else
            mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
        filter = new IntentFilter(ACTION_USB_PERMISSION);

        filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
        filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);

        if(Build.VERSION.SDK_INT>=34)
            registerReceiver(mUsbReceiver,filter,RECEIVER_NOT_EXPORTED);	//RECEIVER_NOT_EXPORTED	//RECEIVER_EXPORTED
        else
            registerReceiver(mUsbReceiver, filter);
    }

    public void PauseUnRegister(){
        if(mUsbReceiver!=null){
            unregisterReceiver(mUsbReceiver);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_usb_test4, 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;
        }else if(id==R.id.action_load){
            if(isWorking)
                return false;

            if(UseManager.getInstance().IsOpen()) {
                int[] imbnum=new int[1];
                int[] tpsize=new int[1];
                byte[] tpdat=new byte[512];
                tpcount=0;
                if(UseManager.getInstance().getUsbReader().FPTemplateNum(0xFFFFFFFF,imbnum)==0){
                    for(int i=0;i<imbnum[0];i++){
                        if(UseManager.getInstance().getUsbReader().FPLoadChar(0xFFFFFFFF,0x01,i)==0){
                            if(UseManager.getInstance().getUsbReader().FPUpChar(0xFFFFFFFF,0x01,tpdat,tpsize)==0){
                                //Save tpdat to file
                                tvStatus.setText("Size："+String.valueOf(tpsize[0])+"   Count:"+String.valueOf(i));
                                System.arraycopy(tpdat,0,tplsit[tpcount],0,tpsize[0]);
                                tpcount++;
                            }
                        }
                    }
                }
            }
        }else if(id==R.id.action_save){
            if(UseManager.getInstance().IsOpen()) {
                //if(vFingerprint.usbReader.FPEmpty(0xFFFFFFFF)==0) {
                for(int i=0;i<tpcount;i++){
                    if(UseManager.getInstance().getUsbReader().FPDownChar(0xFFFFFFFF,0x01,tplsit[i],512)==0){
                        if(UseManager.getInstance().getUsbReader().FPStoreChar(0xFFFFFFFF,0x01,i)==0){
                            //Save OK
                            tvStatus.setText("Save OK:"+String.valueOf(i));
                        }else{
                            tvStatus.setText("Store Fail");
                            break;
                        }
                    }else{
                        tvStatus.setText("Down Fail");
                        break;
                    }
                }
                //}else{
                //    tvStatus.setText("Clear Fail");
                //}
            }
        }else if(id==R.id.action_led){
            if(UseManager.getInstance().IsOpen()) {
                UseManager.getInstance().getUsbReader().FPLedControl(0xFFFFFFFF,0,0);
                SystemClock.sleep(300);
                UseManager.getInstance().getUsbReader().FPLedControl(0xFFFFFFFF,0,1);
                SystemClock.sleep(300);
                UseManager.getInstance().getUsbReader().FPLedControl(0xFFFFFFFF,1,1);
                SystemClock.sleep(300);
                UseManager.getInstance().getUsbReader().FPLedControl(0xFFFFFFFF,3,1);
                SystemClock.sleep(300);
                UseManager.getInstance().getUsbReader().FPLedControl(0xFFFFFFFF,2,1);
            }
        }
        return super.onOptionsItemSelected(item);
    }

    private int ImageBlockAverage(byte[] data,int offset,int width){
        int ptr = offset ;
        int sum = 0x00;
        for(int j=0; j<30; j++){
            for(int i=0; i<30; i++){
                sum = sum + (data[ptr] & 0xff);
                ptr = ptr + 1;
            }
            ptr = ptr+width-30 ;
        }
        return (sum/(30*30));
    }

    private int ImageDetectFinger(byte[] data,int offset,int width,int height){
        int tmp1 = ImageBlockAverage(data,offset+(8*width+40),width);
        int tmp2 = ImageBlockAverage(data,offset+(8*width+(width-40-30)),width);
        int tmp3 = ImageBlockAverage(data,offset+((height-20-30)*width+40),width);
        int tmp4 = ImageBlockAverage(data,offset+((height-20-30)*width+(width-40-30)),width);
        int tmp5 = ImageBlockAverage(data,offset+(70*width+60),width);
        int tmp6 = ImageBlockAverage(data,offset+(70*width+(256-60-30)),width);
        int tmp7 = ImageBlockAverage(data,offset+((height-70-30)*width+60),width);
        int tmp8 = ImageBlockAverage(data,offset+((height-70-30)*width+(width-60-30)),width);
        int block_average =(tmp1+tmp2+tmp3+tmp4+tmp5+tmp6+tmp7+tmp8);
        return  (block_average/8);
    }
}
