// BioAPI20_DemoDlg.cpp : implementation file
//

#include "stdafx.h"
#include "BioAPI20_Demo.h"
#include "BioAPI20_DemoDlg.h"
#include "BioAPI20_Util.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CBioAPI20_DemoDlg dialog

CBioAPI20_DemoDlg::CBioAPI20_DemoDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CBioAPI20_DemoDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CBioAPI20_DemoDlg)
   m_szPayload = _T("");
   m_szFormat = _T("");
   m_szDefaultCaptureTimeout = _T("");
   m_szDefaultEnrollTimeout = _T("");
   m_szDefaultIdentifyTimeout = _T("");
   m_szDefaultVerifyTimeout = _T("");
   m_szDescription = _T("");
   m_szNumFormat = _T("");
   m_szFactorMask = _T("");
   m_szMaxDBSize = _T("");
   m_szMaxIdentify = _T("");
   m_szMaxPayload = _T("");
   m_szModuleID = _T("");
   m_szOperations = _T("");
   m_szOptions = _T("");
   m_szPath = _T("");
   m_szPayloadPolicy = _T("");
   m_szProductVersion = _T("");
   m_szSpecVersion = _T("");
   m_szVendor = _T("");
	m_szUserID = _T("");
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

   m_pBSPs = NULL;
   m_nBSPsInstalled = 0;
   m_bIsBSPLoaded = FALSE;
   m_nCurIndex = -1;
   m_hAttachedSession = BioAPI_INVALID_HANDLE;
   m_bIsAttach = TRUE;
   m_nEventCnt = 1;

   m_bIsDirtyArray = FALSE;
   memset(&m_birArray, 0, sizeof(BioAPI_BIR_ARRAY_POPULATION));
}

void CBioAPI20_DemoDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CBioAPI20_DemoDlg)
	DDX_Control(pDX, IDC_LIST_IDENTIFY_USERS, m_listCtrlIdentifyUsers);
	DDX_Control(pDX, IDC_LIST_USERS, m_listCtrlUsers);
   DDX_Control(pDX, IDC_RADIO_BINARY, m_radioBinary);
   DDX_Control(pDX, IDC_RADIO_HANDLE, m_radioHandle);
	DDX_Control(pDX, IDC_BUTTON_ATTACH, m_btnAttach);
	DDX_Control(pDX, IDC_COMBO_BSP, m_comboBSPs);
	DDX_Control(pDX, IDC_LIST_UNITS, m_listUnits);
	DDX_Control(pDX, IDC_LIST_EVENT, m_listEvent);
	DDX_Text(pDX, IDC_EDIT_PAYLOAD, m_szPayload);
   DDX_Text(pDX, IDC_EDIT_FORMAT, m_szFormat);
   DDX_Text(pDX, IDC_EDIT_DEFAULTCAPTURETIMEOUT, m_szDefaultCaptureTimeout);
   DDX_Text(pDX, IDC_EDIT_DEFAULTENROLLTIMEOUT, m_szDefaultEnrollTimeout);
   DDX_Text(pDX, IDC_EDIT_DEFAULTIDENTIFYTIMEOUT, m_szDefaultIdentifyTimeout);
   DDX_Text(pDX, IDC_EDIT_DEFAULTVERIFYTIMEOUT, m_szDefaultVerifyTimeout);
   DDX_Text(pDX, IDC_EDIT_DESCRIPTION, m_szDescription);
   DDX_Text(pDX, IDC_EDIT_NUM_FORMAT, m_szNumFormat);
   DDX_Text(pDX, IDC_EDIT_FACTOR_MASK, m_szFactorMask);
   DDX_Text(pDX, IDC_EDIT_MAXDBSIZE, m_szMaxDBSize);
   DDX_Text(pDX, IDC_EDIT_MAXIDENTIFY, m_szMaxIdentify);
   DDX_Text(pDX, IDC_EDIT_MAXPAYLOADSIZE, m_szMaxPayload);
   DDX_Text(pDX, IDC_EDIT_MODULEID, m_szModuleID);
   DDX_Text(pDX, IDC_EDIT_OPERATIONS, m_szOperations);
   DDX_Text(pDX, IDC_EDIT_OPTIONS, m_szOptions);
   DDX_Text(pDX, IDC_EDIT_PATH, m_szPath);
   DDX_Text(pDX, IDC_EDIT_PAYLOADPOLICY, m_szPayloadPolicy);
   DDX_Text(pDX, IDC_EDIT_PRODUCT_VERSION, m_szProductVersion);
   DDX_Text(pDX, IDC_EDIT_SPECVERSION, m_szSpecVersion);
   DDX_Text(pDX, IDC_EDIT_VENDOR, m_szVendor);
	DDX_Text(pDX, IDC_EDIT_USERID, m_szUserID);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CBioAPI20_DemoDlg, CDialog)
	//{{AFX_MSG_MAP(CBioAPI20_DemoDlg)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_WM_DESTROY()
	ON_CBN_SELCHANGE(IDC_COMBO_BSP, OnSelchangeComboBsp)
	ON_BN_CLICKED(IDC_BUTTON_ATTACH, OnButtonAttach)
	ON_BN_CLICKED(IDC_BUTTON_ENROLL, OnButtonEnroll)
	ON_BN_CLICKED(IDC_BUTTON_REMOVE, OnButtonRemove)
	ON_BN_CLICKED(IDC_BUTTON_VERIFY, OnButtonVerify)
	ON_BN_CLICKED(IDC_BUTTON_IDENTIFY, OnButtonIdentify)
	ON_NOTIFY(NM_CLICK, IDC_LIST_USERS, OnClickListUsers)
	ON_BN_CLICKED(IDC_BUTTON_MODIFY, OnButtonModify)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CBioAPI20_DemoDlg message handlers

#define BIOAPI_REQUIRED_VERSION (0x20)

BOOL CBioAPI20_DemoDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here
   BioAPI_RETURN ret = BioAPI_Init(BIOAPI_REQUIRED_VERSION);
   AddEvent(ret, _T("BioAPI_Init()"));

   // Fill the list of BSPs installed 
   ret = BioAPI_EnumBSPs(&m_pBSPs, &m_nBSPsInstalled);
   AddEvent(ret, _T("BioAPI_EnumBSPs() returned %d BSPs"), m_nBSPsInstalled);

   // cut the list of all available to MAX_BSPS 
   for (UINT i = 0; i < m_nBSPsInstalled; i++) 
   {
     CString strBSP;
     strBSP.Format(_T("%s"), m_pBSPs[i].BSPDescription);
     int nIndex = m_comboBSPs.AddString(strBSP);
     m_comboBSPs.SetItemData(nIndex, i);
   } 
   
   CRect r;
   m_listCtrlUsers.SetExtendedStyle(LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES);
   m_listCtrlUsers.GetWindowRect(&r);
   m_listCtrlUsers.InsertColumn(0, _T("User ID"), LVCFMT_LEFT, r.Width() - 5); 
   
   m_listCtrlIdentifyUsers.SetExtendedStyle(LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES);
   m_listCtrlIdentifyUsers.GetWindowRect(&r);
   m_listCtrlIdentifyUsers.InsertColumn(0, _T("User ID"), LVCFMT_LEFT, r.Width() - 5); 

   m_radioHandle.SetCheck(TRUE);

	return TRUE;  // return TRUE  unless you set the focus to a control
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CBioAPI20_DemoDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CBioAPI20_DemoDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

void CBioAPI20_DemoDlg::AddEvent(LPCTSTR szFormat, ...)
{
   CString strEvent;
   TCHAR szLog[256] = _T("");
   va_list pArg;
   va_start(pArg, szFormat);
   _vstprintf(szLog, szFormat, pArg);
   va_end(pArg);

   strEvent.Format(_T("%d) %s"), m_nEventCnt++, szLog);
   m_listEvent.AddString(strEvent);
   m_listEvent.SetTopIndex(m_listEvent.GetCount()-1);
}

void CBioAPI20_DemoDlg::AddEvent(BioAPI_RETURN ret, LPCTSTR szFormat, ...)
{
   CString strEvent, strErr;
   TCHAR szDesc[256] = _T("");
   GetBioAPIErrorDescription(ret, szDesc, sizeof(szDesc)/sizeof(TCHAR));
   strErr.Format(_T("ret=%s(0x%04X)"), szDesc, ret);
   
   TCHAR szLog[256] = _T("");
   va_list pArg;
   va_start(pArg, szFormat);
   _vstprintf(szLog, szFormat, pArg);
   va_end(pArg);

   strEvent.Format(_T("%d) %s %s"), m_nEventCnt++, szLog, strErr);
   m_listEvent.AddString(strEvent);
   m_listEvent.SetTopIndex(m_listEvent.GetCount()-1);
}

void CBioAPI20_DemoDlg::OnDestroy() 
{
	CDialog::OnDestroy();

   DetachCurrentSession();
   UnloadCurrentBSP();

   UINT i;
   if (m_pBSPs) {
      for (i = 0; i < m_nBSPsInstalled; i++)
      {
         if (m_pBSPs[i].Path)
            BioAPI_Free(m_pBSPs[i].Path);
         if (m_pBSPs[i].BSPSupportedFormats)
            BioAPI_Free(m_pBSPs[i].BSPSupportedFormats);
      }
      BioAPI_Free(m_pBSPs);
   }

   if (m_birArray.Members) {
      for (i = 0; i < m_birArray.NumberOfMembers; i++) {
         if (m_birArray.Members[i].BiometricData.Data)
            BioAPI_Free(m_birArray.Members[i].BiometricData.Data);
         if (m_birArray.Members[i].SecurityBlock.Data)
            BioAPI_Free(m_birArray.Members[i].SecurityBlock.Data);
      }
      delete[] m_birArray.Members;
   }
}

void CBioAPI20_DemoDlg::OnSelchangeComboBsp() 
{
   DetachCurrentSession();
   UnloadCurrentBSP();
   LoadBSP();
}

BioAPI_RETURN BioAPI MyEventHandler(
					                     const BioAPI_UUID*         pBSPUuid,
					                     BioAPI_UNIT_ID			      nUnitId,		
					                     void*                      pAppNotifyCallbackCtx,
					                     const BioAPI_UNIT_SCHEMA*  pUnitSchema,
					                     BioAPI_EVENT			      nEventType)
{
   const char * szEvents[] = {	
         "unknown",
         "BioAPI_NOTIFY_INSERT",
         "BioAPI_NOTIFY_REMOVE",
         "BioAPI_NOTIFY_FAULT",
         "BioAPI_NOTIFY_SOURCE_PRESENT",
         "BioAPI_NOTIFY_SOURCE_REMOVED"};

   CBioAPI20_DemoDlg* pDlg = (CBioAPI20_DemoDlg*)pAppNotifyCallbackCtx;

   if (nEventType > 5)
      nEventType = 0;

   pDlg->AddEvent(_T("BSP event received (unit=%d, event=%s)"), nUnitId, szEvents[nEventType]);
   
   if (pUnitSchema) {
      CString szCategory = _T("");

      if ((pUnitSchema->UnitCategory & BioAPI_CATEGORY_ARCHIVE) == BioAPI_CATEGORY_ARCHIVE) {
         szCategory += _T("Archive ");
      }
      if ((pUnitSchema->UnitCategory & BioAPI_CATEGORY_MATCHING_ALG) == BioAPI_CATEGORY_MATCHING_ALG) {
         szCategory += _T("Matching ");
      }
      if ((pUnitSchema->UnitCategory & BioAPI_CATEGORY_PROCESSING_ALG) == BioAPI_CATEGORY_PROCESSING_ALG) {
         szCategory += _T("Processing ");
      }
      if ((pUnitSchema->UnitCategory & BioAPI_CATEGORY_SENSOR) == BioAPI_CATEGORY_SENSOR) {
         szCategory += _T("Sensor ");
      }

      CString szUnitID;
      szUnitID.Format(_T("UnitId=%d, %s"), nUnitId, szCategory);
      
      switch (nEventType) {
         case BioAPI_NOTIFY_INSERT:
            {
               int nIndex = pDlg->m_listUnits.FindString(0, szUnitID);
               if (nIndex == LB_ERR) {
                  nIndex = pDlg->m_listUnits.AddString(szUnitID);

                  BioAPI_UNIT_LIST_ELEMENT* pUnitList = new BioAPI_UNIT_LIST_ELEMENT;
                  pUnitList->UnitCategory = pUnitSchema->UnitCategory;
                  pUnitList->UnitId = nUnitId;
                  pDlg->m_listUnits.SetItemDataPtr(nIndex, pUnitList);
               }
            }
            break;

         case BioAPI_NOTIFY_REMOVE:
            {
               int nIndex = pDlg->m_listUnits.FindString(0, szUnitID);
               if (nIndex >= 0) {
                  BioAPI_UNIT_LIST_ELEMENT* pUnitList = (BioAPI_UNIT_LIST_ELEMENT*)pDlg->m_listUnits.GetItemDataPtr(nIndex);
                  if (pUnitList)
                     delete pUnitList;
                  pDlg->m_listUnits.DeleteString(nIndex);
               }
            }
            break;
      }
   }

   return BioAPI_OK;
}

void CBioAPI20_DemoDlg::LoadBSP()
{
	BioAPI_RETURN ret = BioAPI_OK;

	m_listUnits.AddString(_T("<attach any available>"));

   int nIndex = m_comboBSPs.GetCurSel();
   int i = m_comboBSPs.GetItemData(nIndex);
   m_nCurIndex = i;

   ret = BioAPI_BSPLoad(&m_pBSPs[i].BSPUuid, MyEventHandler, this);
   if (ret == BioAPI_OK) {
		m_bIsBSPLoaded = TRUE;

      CString tmp;
      m_szModuleID.Format(_T("{%x%x%x%x-%x%x%x%x-%x%x%x%x-%x%x%x%x}"), 
                           m_pBSPs[i].BSPUuid[0], m_pBSPs[i].BSPUuid[1], m_pBSPs[i].BSPUuid[2], m_pBSPs[i].BSPUuid[3],
                           m_pBSPs[i].BSPUuid[4], m_pBSPs[i].BSPUuid[5], m_pBSPs[i].BSPUuid[6], m_pBSPs[i].BSPUuid[7],
                           m_pBSPs[i].BSPUuid[8], m_pBSPs[i].BSPUuid[9], m_pBSPs[i].BSPUuid[10], m_pBSPs[i].BSPUuid[11],
                           m_pBSPs[i].BSPUuid[12], m_pBSPs[i].BSPUuid[13], m_pBSPs[i].BSPUuid[14], m_pBSPs[i].BSPUuid[15]);
      m_szNumFormat.Format(_T("%u (0x%x)"), m_pBSPs[i].NumSupportedFormats, m_pBSPs[i].NumSupportedFormats);
      for (UINT f = 0; f < m_pBSPs[i].NumSupportedFormats; f++) {
         tmp.Format(_T("0x%x/0x%x "), m_pBSPs[i].BSPSupportedFormats[f].FormatOwner, m_pBSPs[i].BSPSupportedFormats[f].FormatType);
         m_szFormat += tmp;
      }
      m_szSpecVersion.Format(_T("%u (0x%x)"), m_pBSPs[i].SpecVersion, m_pBSPs[i].SpecVersion);
      m_szProductVersion.Format(_T("%u (0x%x)"), m_pBSPs[i].ProductVersion, m_pBSPs[i].ProductVersion);
      m_szVendor = m_pBSPs[i].Vendor;
      m_szFactorMask.Format(_T("%u (0x%x)"), m_pBSPs[i].FactorsMask, m_pBSPs[i].FactorsMask);
      m_szOperations.Format(_T("%u (0x%x)"), m_pBSPs[i].Operations, m_pBSPs[i].Operations);
      m_szOptions.Format(_T("%u (0x%x)"), m_pBSPs[i].Options, m_pBSPs[i].Options);
      m_szPayloadPolicy.Format(_T("%u (0x%x)"), m_pBSPs[i].PayloadPolicy, m_pBSPs[i].PayloadPolicy);
      m_szMaxPayload.Format(_T("%u (0x%x)"), m_pBSPs[i].MaxPayloadSize, m_pBSPs[i].MaxPayloadSize);
      m_szDefaultVerifyTimeout.Format(_T("%u (0x%x)"), m_pBSPs[i].DefaultVerifyTimeout, m_pBSPs[i].DefaultVerifyTimeout);
      m_szDefaultIdentifyTimeout.Format(_T("%u (0x%x)"), m_pBSPs[i].DefaultIdentifyTimeout, m_pBSPs[i].DefaultIdentifyTimeout);
      m_szDefaultCaptureTimeout.Format(_T("%u (0x%x)"), m_pBSPs[i].DefaultCaptureTimeout, m_pBSPs[i].DefaultCaptureTimeout);
      m_szDefaultEnrollTimeout.Format(_T("%u (0x%x)"), m_pBSPs[i].DefaultEnrollTimeout, m_pBSPs[i].DefaultEnrollTimeout);
      m_szMaxDBSize.Format(_T("%u (0x%x)"), m_pBSPs[i].MaxBSPDbSize, m_pBSPs[i].MaxBSPDbSize);
      m_szMaxIdentify.Format(_T("%u (0x%x)"), m_pBSPs[i].MaxIdentify, m_pBSPs[i].MaxIdentify);
      m_szDescription = m_pBSPs[i].BSPDescription;
      m_szPath = m_pBSPs[i].Path;

   } else {
		m_listUnits.ResetContent();

      m_szFormat = _T("");
      m_szDefaultCaptureTimeout = _T("");
      m_szDefaultEnrollTimeout = _T("");
      m_szDefaultIdentifyTimeout = _T("");
      m_szDefaultVerifyTimeout = _T("");
      m_szDescription = _T("");
      m_szNumFormat = _T("");
      m_szFactorMask = _T("");
      m_szMaxDBSize = _T("");
      m_szMaxIdentify = _T("");
      m_szMaxPayload = _T("");
      m_szModuleID = _T("");
      m_szOperations = _T("");
      m_szOptions = _T("");
      m_szPath = _T("");
      m_szPayloadPolicy = _T("");
      m_szProductVersion = _T("");
      m_szSpecVersion = _T("");
      m_szVendor = _T("");
   }

   UpdateData(FALSE);
   
   AddEvent(ret, _T("BioAPI_BSPLoad(%s)"), m_pBSPs[i].BSPDescription);
}

void CBioAPI20_DemoDlg::UnloadCurrentBSP() 
{
   if (m_nCurIndex >= 0) {
      BioAPI_RETURN ret = BioAPI_BSPUnload(&m_pBSPs[m_nCurIndex].BSPUuid, MyEventHandler, this);

      m_bIsBSPLoaded = FALSE;

      for (int i = 0; i < m_listUnits.GetCount(); i++) {
         BioAPI_UNIT_LIST_ELEMENT* pUnitList = (BioAPI_UNIT_LIST_ELEMENT*)m_listUnits.GetItemDataPtr(i);
         if (pUnitList)
            delete pUnitList;
      }
      m_listUnits.ResetContent();

      AddEvent(ret, _T("BioAPI_BSPUnload(%s)"), m_pBSPs[m_nCurIndex].BSPDescription);
   }
}

void CBioAPI20_DemoDlg::OnButtonAttach() 
{
   if (m_bIsAttach) {
      DetachCurrentSession();
      AttachSession();

   } else {
      DetachCurrentSession();
   }
}

void CBioAPI20_DemoDlg::AttachSession() 
{
   int i, nItems = m_listUnits.GetSelCount();
   if (nItems > 0) {
      BioAPI_UNIT_LIST_ELEMENT selUnitList[4];
      memset(selUnitList, 0, sizeof(BioAPI_UNIT_LIST_ELEMENT) * 4);

      int nTotalCnt = 0;
      if (m_listUnits.GetCurSel() == 0) {
         for (i = 1; i < m_listUnits.GetCount(); i++) {
            BioAPI_UNIT_LIST_ELEMENT* pUnitList = (BioAPI_UNIT_LIST_ELEMENT*)m_listUnits.GetItemDataPtr(i);
            if (pUnitList) {
               memcpy(&(selUnitList[nTotalCnt++]), pUnitList, sizeof(BioAPI_UNIT_LIST_ELEMENT));
            }
         }

      } else {
         int* pSelItems = new int [nItems];
         m_listUnits.GetSelItems(nItems, pSelItems);

         for (i = 0; i < nItems; i++) {
            BioAPI_UNIT_LIST_ELEMENT* pUnitList = (BioAPI_UNIT_LIST_ELEMENT*)m_listUnits.GetItemDataPtr(pSelItems[i]);
            if (pUnitList) {
               memcpy(&(selUnitList[nTotalCnt++]), pUnitList, sizeof(BioAPI_UNIT_LIST_ELEMENT));
            }
         }

         delete[] pSelItems;
      }
      
      BioAPI_RETURN ret = BioAPI_BSPAttach(&m_pBSPs[m_nCurIndex].BSPUuid,
							                       BIOAPI_REQUIRED_VERSION,
							                       selUnitList, 
                                            nTotalCnt,
							                       &m_hAttachedSession);

      CString strInfo = _T("category/id:");

      for (int i = 0; i < nTotalCnt; i++) {
         CString strTemp;
         strTemp.Format(_T(" %d/%d"), selUnitList[i].UnitCategory, selUnitList[i].UnitId);
         strInfo += strTemp;
      }
      
      AddEvent(ret, _T("BioAPI_BSPAttach(%s) (handle 0x%08x)"), strInfo, m_hAttachedSession);

      m_bIsAttach = FALSE;
      m_btnAttach.SetWindowText(_T("Detach"));
      m_listUnits.EnableWindow(FALSE);
   }	
}

void CBioAPI20_DemoDlg::ClearUserList()
{
   int i, nCnt = m_listCtrlUsers.GetItemCount();

   for (i = 0; i < nCnt; i++) {
      BioAPI_BIR_HANDLE hBIR = m_listCtrlUsers.GetItemData(i);
      BioAPI_FreeBIRHandle(m_hAttachedSession, hBIR);
      m_listCtrlUsers.SetItemData(i, 0);
   }

   m_listCtrlUsers.DeleteAllItems();
}

void CBioAPI20_DemoDlg::DetachCurrentSession()
{
   if (m_hAttachedSession != BioAPI_INVALID_HANDLE)
	{
      ClearUserList();

      BioAPI_RETURN ret = BioAPI_BSPDetach(m_hAttachedSession);
      
      AddEvent(ret, _T("BioAPI_BSPDetach(0x%08x)"), m_hAttachedSession);
      
      m_hAttachedSession = BioAPI_INVALID_HANDLE;
	}

   m_bIsAttach = TRUE;
   m_btnAttach.SetWindowText(_T("Attach"));
   m_listUnits.EnableWindow(TRUE);
}

void CBioAPI20_DemoDlg::OnButtonEnroll() 
{
	UpdateData();

   if (!m_bIsBSPLoaded) {
      AddEvent(_T("BSP is not loaded!"));
      return;
   }
   if (!m_hAttachedSession) {
      AddEvent(_T("Module is not attached!"));
      return;
   }
   if (m_szUserID.IsEmpty()) {
      AddEvent(_T("User ID is empty!"));
      return;
   }
   LVFINDINFO findInfo;
   findInfo.flags = LVFI_STRING;
   findInfo.psz = m_szUserID;
   int nFindPos = m_listCtrlUsers.FindItem(&findInfo);
   if (nFindPos != -1) {
      AddEvent(_T("User ID is already existed!"));
      return;
   }

   BioAPI_RETURN ret;
   BioAPI_BIR_HANDLE hNewTemplate;
   BioAPI_DATA myPayload;
   myPayload.Length = (m_szPayload.GetLength() + 1) * sizeof(TCHAR);
   if (myPayload.Length > 0) {
      myPayload.Data = new BYTE [myPayload.Length];
      memcpy(myPayload.Data, m_szPayload, myPayload.Length);
   }
   
   ret = BioAPI_Enroll(m_hAttachedSession,
                        BioAPI_PURPOSE_ENROLL,
                        BioAPI_DONT_CARE,	   // Subtype,
                        NULL,				      // don't care
                        NULL,  		         // No adaptation, *ReferenceTemplate,
                        &hNewTemplate,		   // New enrolled tempalte
                        &myPayload,          // Payload,
                        -1,				      // Use BSP default timeout for the operation 
                        NULL,                // audit data
                        NULL);	            // no template UUID
   
   if (ret == BioAPI_OK) {
      int nPos = m_listCtrlUsers.InsertItem(m_listCtrlUsers.GetItemCount(), m_szUserID);
      m_listCtrlUsers.SetItemData(nPos, hNewTemplate);
      m_bIsDirtyArray = TRUE;

   } else {
      AddEvent(ret, _T("Error:"));
   }
   
   if (myPayload.Length > 0)
      delete[] myPayload.Data;
}

void CBioAPI20_DemoDlg::OnButtonModify() 
{
	UpdateData();

   if (!m_bIsBSPLoaded) {
      AddEvent(_T("BSP is not loaded!"));
      return;
   }
   if (!m_hAttachedSession) {
      AddEvent(_T("Module is not attached!"));
      return;
   }

   BioAPI_RETURN ret;

   int nItem = -1;
   if (m_listCtrlUsers.GetSelectedCount() == 1) {
      POSITION pos = m_listCtrlUsers.GetFirstSelectedItemPosition();
      nItem = m_listCtrlUsers.GetNextSelectedItem(pos);
   } else {
      AddEvent(_T("Select User first before modifying fingerprint!"));
      return;
   }

   BioAPI_INPUT_BIR inputBIR, *pInputBIR = NULL;
   BioAPI_BIR_HANDLE hBIR = m_listCtrlUsers.GetItemData(nItem);
   inputBIR.Form = BioAPI_BIR_HANDLE_INPUT;
   inputBIR.InputBIR.BIRinBSP = &hBIR;
   pInputBIR = &inputBIR;
   
   BioAPI_BIR_HANDLE hNewTemplate;
   BioAPI_DATA myPayload;
   myPayload.Length = (m_szPayload.GetLength() + 1) * sizeof(TCHAR);
   if (myPayload.Length > 0) {
      myPayload.Data = new BYTE [myPayload.Length];
      memcpy(myPayload.Data, m_szPayload, myPayload.Length);
   }
   
   ret = BioAPI_Enroll(m_hAttachedSession,
                        BioAPI_PURPOSE_ENROLL,
                        BioAPI_DONT_CARE,	   // Subtype,
                        NULL,				      // don't care
                        pInputBIR,  		   // No adaptation, *ReferenceTemplate,
                        &hNewTemplate,		   // New enrolled tempalte
                        &myPayload,          // Payload,
                        -1,				      // Use BSP default timeout for the operation 
                        NULL,                // audit data
                        NULL);	            // no template UUID
   
   if (ret == BioAPI_OK) {
      BioAPI_FreeBIRHandle(m_hAttachedSession, hBIR);
      m_listCtrlUsers.SetItemData(nItem, hNewTemplate);
      m_bIsDirtyArray = TRUE;

   } else {
      AddEvent(ret, _T("Error:"));
   }
   
   if (myPayload.Length > 0)
      delete[] myPayload.Data;
}

void CBioAPI20_DemoDlg::OnButtonRemove() 
{
   if (m_listCtrlUsers.GetSelectedCount() == 1) {
      POSITION pos = m_listCtrlUsers.GetFirstSelectedItemPosition();
      int nItem = m_listCtrlUsers.GetNextSelectedItem(pos);
      BioAPI_BIR_HANDLE hBIR = m_listCtrlUsers.GetItemData(nItem);
      if (hBIR != BioAPI_INVALID_HANDLE)
         BioAPI_FreeBIRHandle(m_hAttachedSession, hBIR);
      m_listCtrlUsers.SetItemData(nItem, BioAPI_INVALID_HANDLE);
      m_listCtrlUsers.DeleteItem(nItem);
      m_bIsDirtyArray = TRUE;
   }
}

void CBioAPI20_DemoDlg::OnButtonVerify() 
{
	if (!m_bIsBSPLoaded) {
      AddEvent(_T("BSP is not loaded!"));
      return;
   }
   if (!m_hAttachedSession) {
      AddEvent(_T("Module is not attached!"));
      return;
   }
   
   BioAPI_RETURN ret;

   int nItem = -1;
   if (m_listCtrlUsers.GetSelectedCount() == 1) {
      POSITION pos = m_listCtrlUsers.GetFirstSelectedItemPosition();
      nItem = m_listCtrlUsers.GetNextSelectedItem(pos);
   } else {
      AddEvent(_T("Select User first before matching fingerprint!"));
      return;
   }

   BioAPI_BIR_HANDLE hBIR = m_listCtrlUsers.GetItemData(nItem);

   BioAPI_INPUT_BIR inputStoredBIR;
   BioAPI_BIR binaryBIR;   
   memset(&inputStoredBIR, 0, sizeof(BioAPI_INPUT_BIR));
   memset(&binaryBIR, 0, sizeof(BioAPI_BIR));

   if (m_radioHandle.GetCheck()) {
      inputStoredBIR.Form = BioAPI_BIR_HANDLE_INPUT;
      inputStoredBIR.InputBIR.BIRinBSP = &hBIR;
   } else if (m_radioBinary.GetCheck()) {
      ret = BioAPI_GetBIRFromHandle(m_hAttachedSession, hBIR, &binaryBIR); // BIR handle is deleted in framework internally when you call this function.
      if (ret == BioAPI_OK) {
         inputStoredBIR.Form = BioAPI_FULLBIR_INPUT;
         inputStoredBIR.InputBIR.BIR = &binaryBIR;

         // Regenerate BIR Handle
         BioAPI_BIR_HANDLE hNewBIR = 0;
         BioAPI_CreateTemplate(m_hAttachedSession, &inputStoredBIR, NULL, NULL, &hNewBIR, NULL, NULL);
         m_listCtrlUsers.SetItemData(nItem, hNewBIR);
      }
   }
   
   BioAPI_DATA myPayload;
   memset(&myPayload, 0, sizeof(BioAPI_DATA));
   
   BioAPI_FMR  MaxFMRRequested	= 0x7fffffff / 10000;   // 0.01%
   BioAPI_FMR  FMRAchieved		= 0; // Actual FAR for the Verify operations
   BioAPI_BOOL bResponse;
   
   ret = BioAPI_Verify(m_hAttachedSession,
                        MaxFMRRequested,	   // BioAPI_FMR *MaxFMRRequested,
                        &inputStoredBIR,     // BioAPI_INPUT_BIR	*ReferenceTemplate,
                        BioAPI_DONT_CARE,	   // BioAPI_BIR_SUBTYPE Subtype
                        NULL,				      // OUT OPTIONAL	BioAPI_BIR_HANDLE *AdaptedBIR,
                        &bResponse,          // OUT	BioAPI_BOOL	*Result,
                        &FMRAchieved,		   // OUT	BioAPI_FMR	*FMRAchieved,
                        &myPayload,          // OUT OPTIONAL	BioAPI_DATA	*Payload, 
                        -1,					   // Use default BSP timeout 
                        NULL);				   // We are not interested in audit data 
   
   if (ret == BioAPI_OK) {
      if (bResponse) {
         TCHAR* msg = new TCHAR [myPayload.Length + 100];
         wsprintf(msg, _T("Match! (Payload: %s)"), (LPTSTR)myPayload.Data);
         AddEvent(ret, msg);
         delete[] msg;
      } else {
         AddEvent(ret, _T("Not Match!"));
      }
      
   } else {
      AddEvent(ret, _T("Error:"));
   }
   
   if (m_radioBinary.GetCheck()) {
      if (binaryBIR.BiometricData.Data)
         BioAPI_Free(binaryBIR.BiometricData.Data);
      if (binaryBIR.SecurityBlock.Data)
         BioAPI_Free(binaryBIR.SecurityBlock.Data);
   }
   if (myPayload.Length > 0)
      BioAPI_Free(myPayload.Data);
}

void CBioAPI20_DemoDlg::OnButtonIdentify() 
{
   BioAPI_RETURN ret;

   if (m_bIsDirtyArray) {
      UINT i;
      if (m_birArray.Members) {
         for (i = 0; i < m_birArray.NumberOfMembers; i++) {
            if (m_birArray.Members[i].BiometricData.Data)
               BioAPI_Free(m_birArray.Members[i].BiometricData.Data);
            if (m_birArray.Members[i].SecurityBlock.Data)
               BioAPI_Free(m_birArray.Members[i].SecurityBlock.Data);
         }
         delete[] m_birArray.Members;
      }

      m_birArray.NumberOfMembers = m_listCtrlUsers.GetItemCount();
      m_birArray.Members = new BioAPI_BIR [m_birArray.NumberOfMembers];

      BioAPI_INPUT_BIR inputBIR;
      memset(&inputBIR, 0, sizeof(BioAPI_INPUT_BIR));

      for (i = 0; i < m_birArray.NumberOfMembers; i++) {
         BioAPI_BIR_HANDLE hBIR = m_listCtrlUsers.GetItemData(i);
         ret = BioAPI_GetBIRFromHandle(m_hAttachedSession, hBIR, &(m_birArray.Members[i])); // BIR handle is deleted in framework internally when you call this function.
         if (ret == BioAPI_OK) {
            inputBIR.Form = BioAPI_FULLBIR_INPUT;
            inputBIR.InputBIR.BIR = &m_birArray.Members[i];

            // Regenerate BIR Handle
            BioAPI_BIR_HANDLE hNewBIR = 0;
            BioAPI_CreateTemplate(m_hAttachedSession, &inputBIR, NULL, NULL, &hNewBIR, NULL, NULL);
            m_listCtrlUsers.SetItemData(i, hNewBIR);
         }
      }

      m_bIsDirtyArray = FALSE;
   }

   BioAPI_IDENTIFY_POPULATION population;
   population.Type = BioAPI_ARRAY_TYPE;
   population.BIRs.BIRArray = &m_birArray;

   // The maximum False Match Rate that is acceptable for the application. 
   // We specify something around 0.01% of acceptance (max value / 10000).
   BioAPI_FMR		 MaxFMRRequested	= 0x7fffffff / 10000;

   UINT nNumberOfResult;
   BioAPI_CANDIDATE *pCandidates = NULL;

   ret = BioAPI_Identify(m_hAttachedSession,
                          MaxFMRRequested,	         // BioAPI_FMR *MaxFMRRequested,
                          BioAPI_NO_SUBTYPE_AVAILABLE,
                          &population,
                          m_birArray.NumberOfMembers,
                          BioAPI_FALSE,
                          1,
                          &nNumberOfResult,
                          &pCandidates,
                          -1,					            // Use default BSP timeout 
                          NULL);				            // We are not interested in audit data 


    AddEvent(ret, _T("BioAPI_Identify(0x%08x)"), m_hAttachedSession);

    m_listCtrlIdentifyUsers.DeleteAllItems();

    if (ret == BioAPI_OK) {
       if (nNumberOfResult != 0) {
          CString szUserID;
          szUserID = m_listCtrlUsers.GetItemText(pCandidates->BIR.BIRInArray[0], 0);
          AddEvent(ret, _T("Identification succeeded, ID=%s"), szUserID);

          m_listCtrlIdentifyUsers.InsertItem(0, szUserID);

       } else {
          AddEvent(ret, _T("Identification failed"));
       }
    }

    if (pCandidates) {
       if (pCandidates->BIR.BIRInArray)
          BioAPI_Free(pCandidates->BIR.BIRInArray);
       BioAPI_Free(pCandidates);
    }
}

void CBioAPI20_DemoDlg::OnClickListUsers(NMHDR* pNMHDR, LRESULT* pResult) 
{
   if (m_listCtrlUsers.GetSelectedCount() == 1) {
      POSITION pos = m_listCtrlUsers.GetFirstSelectedItemPosition();
      int nItem = m_listCtrlUsers.GetNextSelectedItem(pos);

      TCHAR szText[100];
      m_listCtrlUsers.GetItemText(nItem, 0, szText, sizeof(szText));

      m_szUserID = szText;
      UpdateData(FALSE);
   }
      
	*pResult = 0;
}

