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 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 = zkfv.Init()))
            {
                txtResult.Text = "Init failed! retcode=" + ret.ToString();
                return;
            }
            int nCount = zkfv.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;
            bnInit.Enabled = false;
            bnFree.Enabled = true;
            bnOpen.Enabled = true;
            txtResult.Text = "Init succ!";
        }

        private void bnFree_Click(object sender, EventArgs e)
        {
            CloseDevice();
            zkfv.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 = zkfv.OpenDevice(cmbDevList.SelectedIndex);
            if (IntPtr.Zero == mDevHandle)
            {
                txtResult.Text = "Open device failed!";
                return;
            }
            mDBHandle = zkfv.DBInit();
            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 size = 4;
            int ret = 0;
            ret = zkfv.GetParameters(mDevHandle, 5001, retParam, ref size);
            zkfv.ByteArray2Int(retParam, ref mfvWidth);
            size = 4;
            ret = zkfv.GetParameters(mDevHandle, 5002, retParam, ref size);
            zkfv.ByteArray2Int(retParam, ref mfvHeight);
            size = 4;
            ret = zkfv.GetParameters(mDevHandle, 5004, retParam, ref size);
            zkfv.ByteArray2Int(retParam, ref mfpWidth);
            size = 4;
            ret = zkfv.GetParameters(mDevHandle, 5005, retParam, ref size);
            zkfv.ByteArray2Int(retParam, ref mfpHeight);

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

            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)
            {
                zkfv.DBFree(mDBHandle);
                mDBHandle = IntPtr.Zero;
            }
            if (IntPtr.Zero != mDevHandle)
            {
                zkfv.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 nCount = zkfv.DBCount(mDBHandle);
            if (nCount > 0)
            {
                txtResult.Text = nCount + "fingers have registered!";
            }
            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()
        {
            while (!mbStop)
            {
                mfpTempLen = mfpTemp.Length;
                mfvTempLen = mfvTemp.Length;
                int ret = zkfv.AcquireFingerVein(mDevHandle, mfpImg, mfvImg, 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 (mbRegister)
                        {
                            if (mEnrollIdx > 0)
                            {
                                int nR1 = zkfv.DBMatchFP(mDBHandle, mfpTemp, mPreRegFPRegTemps[mEnrollIdx - 1]);
                                int nR2 = zkfv.DBMatchFV(mDBHandle, mfvTemp, mPreRegFVRegTemps[mEnrollIdx-1]);
                                if ( nR1<= 0 || nR2 <= 0)
                                {
                                    txtResult.Text = "Please press the same finger while registering!";
                                    return;
                                }
                            }
                            Array.Copy(mfpTemp, mPreRegFPRegTemps[mEnrollIdx], mfpTempLen);
                            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;
                                if (zkfverrdef.ZKFV_ERR_OK != zkfv.DBMergeFP(mDBHandle, mPreRegFPRegTemps, temp, ref nTempLen) || nTempLen <= 0)
                                {
                                    txtResult.Text = "Enroll failed, because merge fingerprint failed!";
                                    return;
                                }

                                int nRet = zkfv.DBAddEx(mDBHandle, mFingerID, mPreRegFVRegTemps, temp);
                                if (zkfverrdef.ZKFV_ERR_OK != nRet)
                                {
                                    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)
                                ret = zkfv.DBNormalHybridIdentify(mDBHandle, mfpTemp, mfvTemp, ref nFingerId, ref nScore);
                                if (zkfverrdef.ZKFV_ERR_OK != ret)
                                {
                                    txtResult.Text = "Identify failed! ";
                                }
                                else
                                {
                                    txtResult.Text = "Identify succ, fingerid = " + nFingerId + ", score = " + nScore;
                                }
                            }
                            else
                            {
                                int fpScore = 0;
                                int fvScore = 0;
                                int nTemp = 0;
                                fpScore = zkfv.DBMatchFP(mDBHandle, mRegFPRegTemp, mfpTemp);
                                for (int i = 0; i < mEnrollCnt; i++)
                                {
                                    nTemp = zkfv.DBMatchFV(mDBHandle, mRegFVRegTemps[i], mfvTemp);
                                    if (nTemp > fvScore) fvScore = nTemp;
                                }
                                txtResult.Text = "Match fingerprint score=" + fpScore + ", match fingervein score = " + fvScore;
                            }
                        }
                    }
                    break;

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


}
