using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using zkfvcsharp;
using System.Threading;
using System.Runtime.InteropServices;
using System.IO;
using Sample;

namespace csdemo
{
    public partial class Form1 : Form
    {
        //Device Handle
        private IntPtr mDevHandle = IntPtr.Zero;
        //DB Handle
        private IntPtr mDBHandle = IntPtr.Zero;
        //Last reg-fingerprint template
        private byte[] mRegFPRegTemp = null;
        //Last reg-fingerprint template length
        private int mRegFPRegTempLen = 0;
        //Last reg-fingervein templates(3 fingervein temlates)
        private byte[][] mRegFVRegTemps = new byte[3][];
        //the length of reg-fingervein template
        private int[] mRegFVTempLen = null;
        //stop thread
        private bool mbStop = true;
        //Enroll
        private bool mbRegister = false;
        //Identify(!Verify)
        private bool mbIdentify = false;
        //Enroll count
        private static int mEnrollCnt = 3;
        //Enroll index
        private int mEnrollIdx = 0;
        //register finger id(must > 0)
        private int mFingerID = 1;
        //Max template length
        private static int mMaxTempLen = 1024;

        private static int mMaxFpTempLen = 2048;

        //From handle
        IntPtr FormHandle = IntPtr.Zero;

        //Acquire info form sdk begin
        private byte[] mfpImg = null;
        private byte[] mfvImg = null;
        private int mcbFpImg = 0;
        private int mcbFvImg = 0;
        private int mfpWidth = 0;
        private int mfpHeight = 0;
        private int mfvWidth = 0;
        private int mfvHeight = 0;
        private byte[] mfpTemp = null;
        private byte[] mfvTemp = null;
        private int mfpTempLen = 0;
        private int mfvTempLen = 0;
        //prereg-fingerprint templates
        private byte[][] mPreRegFPRegTemps = new byte[3][];
        //the length of reg-fingervein template
        private int[] mPreRegFPTempLen = null;
        //Last reg-fingervein templates(3 fingervein temlates)
        private byte[][] mPreRegFVRegTemps = new byte[3][];
        //the length of reg-fingervein template
        private int[] mPreRegFVTempLen = null;
        //Acquire info form sdk end


        const int MESSAGE_CAPTURED_OK = 0x0400 + 6;

        [DllImport("user32.dll", EntryPoint = "SendMessageA")]
        public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

        public Form1()
        {
            InitializeComponent();
            mRegFVTempLen = new int[mEnrollCnt];
            mPreRegFPTempLen = new int[mEnrollCnt];
            mPreRegFVTempLen = new int[mEnrollCnt];
            mfpTemp = new byte[mMaxFpTempLen];
            mfvTemp = new byte[mMaxTempLen];
            mRegFPRegTemp = new byte[mMaxFpTempLen];
            mRegFPRegTempLen = 0;
            for (int i = 0; i < mEnrollCnt; i++)
            {
                mRegFVRegTemps[i] = new byte[mMaxTempLen];
                mPreRegFPRegTemps[i] = new byte[mMaxFpTempLen];
                mPreRegFVRegTemps[i] = new byte[mMaxTempLen];
                mRegFVTempLen[i] = 0;
                mPreRegFPTempLen[i] = 0;
                mPreRegFVTempLen[i] = 0;
            }
        }

        private void bnInit_Click(object sender, EventArgs e)
        {
            int ret = zkfverrdef.ZKFV_ERR_OK;
            cmbDevList.Items.Clear();
            mFingerID = 1;
            if (zkfverrdef.ZKFV_ERR_OK != (ret = zkfingervein.Init()))
            {
                txtResult.Text = "Init failed! retcode=" + ret.ToString();
                return;
            }
            int nCount = zkfingervein.GetDeviceCount();
            if (nCount <= 0)
            {
                txtResult.Text = "No device connected!";
                zkfv.Terminate();
                return;
            }
            for (int i = 0; i < nCount; i++)
            {
                cmbDevList.Items.Add(i.ToString());
            }
            cmbDevList.SelectedIndex = 0;

            cmbDevList_EnrollMode.Items.Add("指纹+静脉");
            cmbDevList_EnrollMode.Items.Add("单指纹");
            cmbDevList_EnrollMode.Items.Add("单静脉");
            cmbDevList_EnrollMode.SelectedIndex = 0;

            bnInit.Enabled = false;
            bnFree.Enabled = true;
            bnOpen.Enabled = true;
            txtResult.Text = "Init succ!";
        }

        private void bnFree_Click(object sender, EventArgs e)
        {
            zkfingervein.CloseDevice(mDevHandle);
            zkfingervein.Terminate();
            bnInit.Enabled = true;
            bnFree.Enabled = false;
            bnOpen.Enabled = false;
            bnClose.Enabled = false;
            bnEnroll.Enabled = false;
            bnCount.Enabled = false;
            bnVerify.Enabled = false;
            bnIdentify.Enabled = false;
            cmbDevList.Items.Clear();
            txtResult.Text = "Free succ!";
        }

        private void bnOpen_Click(object sender, EventArgs e)
        {
            if (IntPtr.Zero != mDevHandle)
            {
                txtResult.Text = "Please close device first!";
                return;
            }
            if (cmbDevList.SelectedIndex == -1)
            {
                txtResult.Text = "Please select a device first!";
                return;
            }
            mDevHandle = zkfingervein.OpenDevice(cmbDevList.SelectedIndex);
            if (IntPtr.Zero == mDevHandle)
            {
                txtResult.Text = "Open device failed!";
                return;
            }
            mDBHandle = zkfingervein.DBInit(mDevHandle);
            if (IntPtr.Zero == mDevHandle)
            {
                txtResult.Text = "Init DB failed!";
                zkfv.CloseDevice(mDevHandle);
                mDevHandle = IntPtr.Zero;
                return;
            }
            bnOpen.Enabled = false;
            bnClose.Enabled = true;
            bnEnroll.Enabled = true;
            bnCount.Enabled = true;
            bnVerify.Enabled = true;
            bnIdentify.Enabled = true;

            byte[] retParam = new byte[4];
            int retSize = 4;
            int ret = 0;


            byte[] nFullWidth = new byte[4];
            byte[] nFullHeight = new byte[4];
            zkfingervein.GetParameters(mDevHandle, 1, nFullWidth, ref retSize);
            retSize = 4;
            zkfingervein.GetParameters(mDevHandle, 2, nFullHeight, ref retSize);

            int nFullWidth1 = System.BitConverter.ToInt32(nFullWidth,0);
            int nFullHeight1 = System.BitConverter.ToInt32(nFullHeight, 0);

            mfpWidth = nFullWidth1 & 0xFFFF;
            mfpHeight = nFullHeight1 & 0xFFFF;
            mfvWidth = (nFullWidth1 >> 16) & 0xFFFF;
            mfvHeight = (nFullHeight1 >> 16) & 0xFFFF;




            //ret = zkfingervein.GetParameters(mDevHandle, 5001, retParam, ref size);
            //zkfv.ByteArray2Int(retParam, ref mfvWidth);
            //size = 4;
            //ret = zkfingervein.GetParameters(mDevHandle, 5002, retParam, ref size);
            //zkfv.ByteArray2Int(retParam, ref mfvHeight);
            //size = 4;
            //ret = zkfingervein.GetParameters(mDevHandle, 5004, retParam, ref size);
            //zkfv.ByteArray2Int(retParam, ref mfpWidth); 
            //size = 4;
            //ret = zkfingervein.GetParameters(mDevHandle, 5005, retParam, ref size);
            //zkfv.ByteArray2Int(retParam, ref mfpHeight);

            mfvImg = new byte[mfvWidth * mfvHeight];
            mfpImg = new byte[mfpWidth * mfpHeight];
            mcbFpImg = mfpWidth * mfpHeight;
            mcbFvImg = mfvWidth * mfvHeight;

            mbStop = false;
            Thread captureThread = new Thread(new ThreadStart(DoCapture));
            captureThread.IsBackground = true;
            captureThread.Start();
            txtResult.Text = "Open succ!";
        }
        private void CloseDevice()
        {
            if (!mbStop)
            {
                mbStop = true;
                Thread.Sleep(1000);
            }
            if (IntPtr.Zero != mDBHandle)
            {
                zkfingervein.DBFree(mDBHandle);
                mDBHandle = IntPtr.Zero;
            }
            if (IntPtr.Zero != mDevHandle)
            {
                zkfingervein.CloseDevice(mDevHandle);
                mDevHandle = IntPtr.Zero;
            }
            mRegFPRegTempLen = 0;
        }

        private void bnClose_Click(object sender, EventArgs e)
        {
            CloseDevice();
            bnOpen.Enabled = true;
            bnClose.Enabled = false;
            bnEnroll.Enabled = false;
            bnCount.Enabled = false;
            bnVerify.Enabled = false;
            bnIdentify.Enabled = false;
            txtResult.Text = "Close succ!";
        }

        private void bnEnroll_Click(object sender, EventArgs e)
        {
            if (IntPtr.Zero == mDevHandle)
            {
                return;
            }
            if (mbRegister)
            {
                txtResult.Text = "It's registering!";
                return;
            }
            txtResult.Text = "Please press a same finger 3 times!";
            mbRegister = true;
        }

        private void bnCount_Click(object sender, EventArgs e)
        {
            if (IntPtr.Zero == mDBHandle)
            {
                txtResult.Text = "DB not inited!";
                return;
            }
            int nFpCount = zkfingervein.DBCount(mDBHandle, 0);
            int nFvCount = zkfingervein.DBCount(mDBHandle, 1);
            if (nFpCount > 0 || nFvCount > 0)
            {
                txtResult.Text = nFpCount + "fingers," + nFvCount + " fingerveins";
            }
            else
            {
                txtResult.Text = "no finger have registered!";
            }
        }

        private void bnVerify_Click(object sender, EventArgs e)
        {
            if (IntPtr.Zero == mDevHandle)
            {
                return;
            }
            mbIdentify = false;
            if (mbRegister)
            {
                mEnrollIdx = 0;
                mbRegister = false;
            }

        }

        private void bnIdentify_Click(object sender, EventArgs e)
        {
            mbIdentify = true;
            if (mbRegister)
            {
                mEnrollIdx = 0;
                mbRegister = false;
            }
        }

        private void DoCapture()
        {
            int fpImageSize = 0;
            int fvImageSize = 0;
            while (!mbStop)
            {
                mfpTempLen = mfpTemp.Length;
                mfvTempLen = mfvTemp.Length;
                fpImageSize = mcbFpImg;
                fvImageSize = mcbFvImg;
                int ret = zkfingervein.CaptureFingerVeinImageAndTemplate(mDevHandle, mfpImg, ref fpImageSize, mfvImg, ref fvImageSize, mfpTemp, ref mfpTempLen, mfvTemp, ref mfvTempLen);
                if (ret == zkfverrdef.ZKFV_ERR_OK)
                {
                    if (mfpTempLen > 0 && mfvTempLen > 0)
                    {
                        SendMessage(FormHandle, MESSAGE_CAPTURED_OK, IntPtr.Zero, IntPtr.Zero);
                    }
                }
                Thread.Sleep(200);
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            FormHandle = this.Handle;
        }


        protected override void DefWndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case MESSAGE_CAPTURED_OK:
                    {
                        MemoryStream msFP = new MemoryStream();
                        BitmapFormat.GetBitmap(mfpImg, mfpWidth, mfpHeight, ref msFP);
                        Bitmap bmpfp = new Bitmap(msFP);
                        this.picFP.Image = bmpfp;

                        MemoryStream msFV = new MemoryStream();
                        BitmapFormat.GetBitmap(mfvImg, mfvWidth, mfvHeight, ref msFV);
                        Bitmap bmpfv = new Bitmap(msFV);
                        this.picFV.Image = bmpfv;

                        if (checkBox_IsSaveImage.Checked == true)
                        {
                            BitmapFormat.WriteBitmap(mfvImg, mfvWidth, mfvHeight);
                        }

                        if (mbRegister)
                        {
                            if (mEnrollIdx > 0)
                            {
                                int nR1 = zkfingervein.Verify(mDevHandle, 0, mfpTemp, mfpTempLen, mPreRegFPRegTemps[mEnrollIdx - 1], mPreRegFPTempLen[mEnrollIdx - 1]);
                                int nR2 = zkfingervein.Verify(mDevHandle, 1, mfvTemp, mfvTempLen, mPreRegFVRegTemps[mEnrollIdx - 1], mPreRegFVTempLen[mEnrollIdx - 1]);

                                if (this.cmbDevList_EnrollMode.SelectedIndex == 1)
                                {
                                    if (nR1 <= 0)
                                    {
                                        txtResult.Text = "Please press the same finger while registering!";
                                        return;
                                    }
                                }
                                else if (this.cmbDevList_EnrollMode.SelectedIndex == 2)
                                {
                                    if (nR2 <= 0)
                                    {
                                        txtResult.Text = "Please press the same finger while registering!";
                                        return;
                                    }
                                }
                                else
                                {
                                    if (nR1 <= 0 || nR2 <= 0)
                                    {
                                        txtResult.Text = "Please press the same finger while registering!";
                                        return;
                                    }
                                }
                            }

                            if (mfpTempLen > 0)
                            {
                                Array.Copy(mfpTemp, mPreRegFPRegTemps[mEnrollIdx], mfpTempLen);
                            }
                            if (mfpTempLen > 0)
                            {
                                Array.Copy(mfvTemp, mPreRegFVRegTemps[mEnrollIdx], mfvTempLen);
                            }

                            mPreRegFPTempLen[mEnrollIdx] = mfpTempLen;
                            mPreRegFVTempLen[mEnrollIdx] = mfvTempLen;
                            mEnrollIdx++;
                            if (mEnrollIdx >= 3)
                            {
                                mEnrollIdx = 0;
                                mbRegister = false;
                                byte[] temp = new byte[mMaxFpTempLen];
                                int nTempLen = mMaxFpTempLen;
                                int nnRet = zkfingervein.MergeFPEx(mDevHandle, mPreRegFPRegTemps[0], mPreRegFPRegTemps[1], mPreRegFPRegTemps[2], 3, temp, ref nTempLen);
                                if (zkfverrdef.ZKFV_ERR_OK != nnRet)
                                {
                                    txtResult.Text = "Enroll failed, because merge fingerprint failed!";
                                    return;
                                }

                                byte[] a = { 1 };
                                byte[] b = { 2 };
                                int nFpRet = zkfingervein.DBAddEx(mDBHandle, 0, System.BitConverter.GetBytes(mFingerID), mPreRegFPRegTemps[0], mPreRegFPRegTemps[1], mPreRegFPRegTemps[2], 3);
                                int nFvRet = zkfingervein.DBAddEx(mDBHandle, 1, System.BitConverter.GetBytes(mFingerID), mPreRegFVRegTemps[0], mPreRegFVRegTemps[1], mPreRegFVRegTemps[2], 3);
                                if (zkfverrdef.ZKFV_ERR_OK != nFpRet && zkfverrdef.ZKFV_ERR_OK != nFvRet)
                                {
                                    txtResult.Text = "Enroll failed, DBAddEx failed!";
                                    return;
                                }

                                Array.Copy(temp, mRegFPRegTemp, nTempLen);
                                mRegFPRegTempLen = nTempLen;
                                for (int i = 0; i < mEnrollCnt; i++)
                                {
                                    Array.Copy(mPreRegFVRegTemps[i], mRegFVRegTemps[i], mPreRegFVTempLen[i]);
                                    mRegFVTempLen[i] = mPreRegFVTempLen[i];
                                }
                                mFingerID++;
                                txtResult.Text = "Enroll succ!";
                            }
                            else
                            {
                                txtResult.Text = "You need to press the " + (mEnrollCnt - mEnrollIdx) + " times finger";
                            }
                        }
                        else
                        {
                            if (mRegFPRegTempLen <= 0)
                            {
                                txtResult.Text = "Identify failed, no finger have registered! ";
                                return;
                            }
                            if (mbIdentify)
                            {
                                int nFingerId = 0;
                                int nScore = 0;
                                int ret = 0;
                                //zkfv.DBSecurityHybridIdentify
                                //zkfv.DBFakeHybridIdentify
                                //zkfv.DBIdentifyFV(mDBHandle, mfvTemp, ref nFingerId, ref nScore)
                                //zkfv.DBIdentifyFP(mDBHandle, mfpTemp, ref nFingerId, ref nScore)
                                byte[] uID = new byte[4];
                                ret = zkfingervein.DBHybridIdentify(mDBHandle, 0, mfpTemp, mfpTempLen, mfvTemp, mfvTempLen, uID, ref nScore);

                                //ret = zkfv.DBNormalHybridIdentify(mDBHandle, mfpTemp, mfvTemp, ref nFingerId, ref nScore);
                                if (zkfverrdef.ZKFV_ERR_OK != ret)
                                {
                                    txtResult.Text = "Identify failed! ";
                                }
                                else
                                {
                                    //System.Text.Encoding.Default.GetString(byteArray);
                                    txtResult.Text = "Identify succ, fingerid = " + System.BitConverter.ToInt32(uID, 0) + ", score = " + nScore;
                                }
                            }
                            else
                            {
                                int fpScore = 0;
                                int fvScore = 0;
                                int nTemp = 0;
                                fpScore = zkfingervein.Verify(mDBHandle, 0, mRegFPRegTemp, mRegFPRegTempLen, mfpTemp, mfpTempLen);
                                for (int i = 0; i < mEnrollCnt; i++)
                                {
                                    nTemp = zkfingervein.Verify(mDBHandle, 1, mRegFVRegTemps[i], mRegFVTempLen[i], mfvTemp, mfvTempLen);
                                    if (nTemp > fvScore) fvScore = nTemp;
                                }
                                txtResult.Text = "Match fingerprint score=" + fpScore + ", match fingervein score = " + fvScore;
                            }
                        }
                    }
                    break;

                default:
                    base.DefWndProc(ref m);
                    break;
            }
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            CloseDevice();
            zkfingervein.Terminate();
            //if (captureThread != null)
            //    captureThread.Abort();
        }
    }


}
