// FingerCellDoc.cpp : implementation of the CFingerCellDoc class
//

#include "stdafx.h"
#include "FingerCell.h"

#include "FingerCellDoc.h"
#include "LogView.h"
#include "FingerCellView.h"

#include "DialogMsg.h"

#include "FncExtractor.h"
#include "FncMatcher.h"
#include "NImage.h"

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


#define MAX_FEATURES_SIZE 10000
#define GENERALIZE_COUNT 3

/////////////////////////////////////////////////////////////////////////////
// CFingerCellDoc

IMPLEMENT_DYNCREATE(CFingerCellDoc, CDocument)

BEGIN_MESSAGE_MAP(CFingerCellDoc, CDocument)
	//{{AFX_MSG_MAP(CFingerCellDoc)
	ON_COMMAND(ID_CLEAR_LOG, OnClearLog)
	ON_COMMAND(ID_LOAD_IMAGE, OnLoadImage)
	ON_COMMAND(ID_ENROLLMENT, OnEnrollment)
	ON_UPDATE_COMMAND_UI(ID_ENROLLMENT, OnUpdateEnrollment)
	ON_COMMAND(ID_ENROLLMENTFG, OnEnrollmentfg)
	ON_UPDATE_COMMAND_UI(ID_ENROLLMENTFG, OnUpdateEnrollmentfg)
	ON_COMMAND(ID_IDENTIFICATION, OnIdentification)
	ON_UPDATE_COMMAND_UI(ID_IDENTIFICATION, OnUpdateIdentification)
	ON_COMMAND(ID_FAST_IDENTIFICATION, OnFastIdentification)
	ON_UPDATE_COMMAND_UI(ID_FAST_IDENTIFICATION, OnUpdateFastIdentification)
	ON_COMMAND(ID_VERIFICATION, OnVerification)
	ON_UPDATE_COMMAND_UI(ID_VERIFICATION, OnUpdateVerification)
	ON_COMMAND(ID_FAST_VERIFICATION, OnFastVerification)
	ON_UPDATE_COMMAND_UI(ID_FAST_VERIFICATION, OnUpdateFastVerification)
	ON_COMMAND(ID_ZOOM_11, OnZoom11)
	ON_COMMAND(ID_ZOOM_IN, OnZoomIn)
	ON_COMMAND(ID_ZOOM_OUT, OnZoomOut)
	ON_COMMAND(ID_SHOW_BLOCKEDORIENTATIONS, OnShowBlockedorientations)
	ON_UPDATE_COMMAND_UI(ID_SHOW_BLOCKEDORIENTATIONS, OnUpdateShowBlockedorientations)
	ON_COMMAND(ID_SHOW_FEATURES, OnShowFeatures)
	ON_UPDATE_COMMAND_UI(ID_SHOW_FEATURES, OnUpdateShowFeatures)
	ON_COMMAND(ID_SHOW_SINGULARPOINTS, OnShowSingularpoints)
	ON_UPDATE_COMMAND_UI(ID_SHOW_SINGULARPOINTS, OnUpdateShowSingularpoints)
	ON_COMMAND(ID_OPTIONS, OnOptions)
	ON_COMMAND(ID_CLEAR_DB, OnClearDb)
	ON_COMMAND(ID_SHOW_BINARY_IMAGE, OnShowBinaryImage)
	ON_UPDATE_COMMAND_UI(ID_SHOW_BINARY_IMAGE, OnUpdateShowBinaryImage)
	ON_COMMAND(ID_SCANF, OnScanf)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CFingerCellDoc construction/destruction

CFingerCellDoc::CFingerCellDoc()
{
	zoom = 70;
	showFeatures = TRUE;
	showBlockedOrientations = TRUE;
	showSingularPoints = TRUE;
	showBinaryImage = TRUE;
	m_fingercount = 0;
#ifndef NO_BIO_API
	m_image_from_iPAQ = FALSE;
	m_fdescription = "TestFinger";
#endif
}

CFingerCellDoc::~CFingerCellDoc()
{
}

BOOL CFingerCellDoc::OnNewDocument()
{
	if (!CDocument::OnNewDocument())
		return FALSE;

	m_features_left  = NULL;
	m_features_right = NULL;

	CString str;
	NLibraryInfo li;

	FnceCreate(&hExtractor);
	FncmCreate(&hMatcher);

	m_settings.SetExtractor(&hExtractor);
	m_settings.SetMatcher(&hMatcher);

	m_settings.DefaultValues();
	m_settings.ApplySettings();

	FnceGetInfo(&li);
	str.Format(TEXT("%s    Version %u.%u.%u.%u"), li.Product, li.VersionMajor, li.VersionMinor, li.VersionBuild, li.VersionRevision);
	AddToLog(str);

	FncmGetInfo(&li);
	str.Format(TEXT("%s    Version %u.%u.%u.%u"), li.Product, li.VersionMajor, li.VersionMinor, li.VersionBuild, li.VersionRevision);
	AddToLog(str);

	m_database.SetLoger((CLogerInterface*)this);
	m_database.Load();

	OnEnrollment();

	return TRUE;
}


/////////////////////////////////////////////////////////////////////////////
// CFingerCellDoc serialization

void CFingerCellDoc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
	}
	else
	{
	}
}

/////////////////////////////////////////////////////////////////////////////
// CFingerCellDoc diagnostics

#ifdef _DEBUG
void CFingerCellDoc::AssertValid() const
{
	CDocument::AssertValid();
}

////void CFingerCellDoc::Dump(CDumpContext& dc) const
////{
////	CDocument::Dump(dc);
////}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CFingerCellDoc commands

void CFingerCellDoc::OnCloseDocument()
{
	CDocument::OnCloseDocument();
}

BOOL CFingerCellDoc::CanCloseFrame(CFrameWnd* pFrame)
{
	FnceFree(hExtractor);
	FncmFree(hMatcher);
	
	m_database.Store();
	m_database.ClearDB();

	if (m_img_left)
		NImageFree(m_img_left);

	if (m_img_right)
		NImageFree(m_img_right);

	if (m_features_left)
		NFRecordFree(m_features_left);

	if (m_features_right)
		NFRecordFree(m_features_right);

	Sleep(200);

	return CDocument::CanCloseFrame(pFrame);
}

BOOL CFingerCellDoc::IsModified()
{
	return FALSE;
}

void CFingerCellDoc::OnClearLog()
{
	POSITION pos = GetFirstViewPosition();
	while (pos != NULL)
	{
		CView* pView = GetNextView(pos);
		if (pView->IsKindOf(RUNTIME_CLASS(CLogView)))
		{
			CLogView *pLog = (CLogView *) pView;
			pLog->ClearLog();
		}
	}
}

void CFingerCellDoc::AddToLog(CString str, BOOL addnewline)
{
	POSITION pos = GetFirstViewPosition();
	while (pos != NULL)
	{
		CView* pView = GetNextView(pos);
		if (pView->IsKindOf(RUNTIME_CLASS(CLogView)))
		{
			CLogView *pLog = (CLogView *) pView;
			pLog->AddToLog(str, addnewline);
		}
	}
}

void CFingerCellDoc::OnLoadImage()
{
	CString str;
	CString fileName;
	HNImage hOriginalImage;
	HNImage hGSImage;
	NUInt width;
	NUInt heigth;
	HNImage img1;
	HNImage img2;
	TimeInterval ti;
	BYTE features[MAX_FEATURES_SIZE];
	NSizeType size;
	NInt minutiaCount;

	int dpi = m_settings.m_DPI;

	CFileDialog dlg(TRUE, NULL, NULL, OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST,
		_T("All supported files|*.bmp;*.tif|TIFF image files(*.tif)|*.tif|Bitmap files(*.bmp)|*.bmp|"));

#ifndef NO_BIO_API
	if (!m_image_from_iPAQ)
	{
#endif
		if (dlg.DoModal() != IDOK)
		{
			return;
		}
		fileName = dlg.GetPathName();
		AddToLog(CString("Loading file: ") + fileName);
		NImageCreateFromFile(fileName, NULL, &hOriginalImage);
		NImageCreateFromImageEx(npfGrayscale, 0, (NFloat)dpi, (NFloat)dpi, hOriginalImage, &hGSImage);
		NImageFree(hOriginalImage);
#ifndef NO_BIO_API
	}
	else
	{
		m_image_from_iPAQ = FALSE;
		/*
			For 5500:
				NImageCreateFromData(npfGrayscale,400, 500, 400, (NFloat)dpi, (NFloat)dpi,
   400, OriginalBIR.BiometricData, &hGSImage);
			For 2700:
				NImageCreateFromData(npfGrayscale,320, 400, 320, (NFloat)dpi, (NFloat)dpi,
   320, OriginalBIR.BiometricData, &hGSImage);
		*/
		NImageCreateFromData(npfGrayscale,400, 500, 400, (NFloat)dpi, (NFloat)dpi,
   400, OriginalBIR.BiometricData, &hGSImage);
	}
#endif

	NImageGetWidth(hGSImage, &width);
	NImageGetHeight(hGSImage, &heigth);

	str.Format(L"Image width: %d, height: %d", width, heigth);
	AddToLog(str);
	str.Format(L"Image DPI: %d", dpi);
	AddToLog(str);

	NImageClone(hGSImage, &img1);

	STTI(&ti);
	if(m_mode == FastIdentificationMode || (m_mode == FastVerificationMode && m_fingercount == 1))
	{
		FnceFastExtractStartFromImage(hExtractor, hGSImage, nfpUnknown, nfitLiveScanPlain, features, MAX_FEATURES_SIZE, &size);
	}
	else
	{
		FnceExtractFromImage(hExtractor, hGSImage, nfpUnknown, nfitLiveScanPlain, features, MAX_FEATURES_SIZE, &size);
	}
	SPTI(&ti);
	
	AddToLog("Fingerprint processing time: " + CString(ti.str));
	str.Format(L"Features array size: %d", size);
	AddToLog(str);

	NImageClone(hGSImage, &img2);
	NImageFree(hGSImage); 

	ClearResults();

	if (!size)
	{
		wchar_t buffer[1024];
		swprintf(buffer, _T("Image is low quality!"));
		AfxMessageBox(buffer, MB_OK);
		return;
	}

	if (m_mode == EnrollmentMode)
	{
		m_img_left = img1;
		m_img_right = img2;

		m_left_dpi = dpi;
		m_right_dpi = dpi;

		NFRecordCreateFromMemory(features, size, 0, NULL, &m_features_right);
		NFRecordGetMinutiaCount(m_features_right, &minutiaCount);

		UpdateAllViews(NULL);
		AfxGetApp()->PumpMessage();

		if (minutiaCount < 10)
		{
			if (AfxMessageBox(L"Minutia count is less than 10.\nContinue enrollment?", MB_YESNO) == IDNO)
				return;
		}

		FPRecord finger;
		finger.size = size;
		finger.features = new BYTE[size];
		if (fileName.GetLength() > MAX_DESCRIPTION)
		{
			fileName = fileName.Right(MAX_DESCRIPTION);
		}
		wcscpy(finger.description, fileName);
		memcpy(finger.features, features, size);
		m_database.AddFingerprint(&finger);
		return;
	}

	if (m_mode == EnrollmentFGMode)
	{
		m_fingercount++;
		NFRecordCreateFromMemory(features, size, 0, NULL, &m_features[m_fingercount-1]);

		if (m_fingercount < GENERALIZE_COUNT)
		{
			AddToLog(L"Enter one more image");

			m_img_left = img1;
			m_img_right = img2;

			m_left_dpi = dpi;
			m_right_dpi = dpi;

			NFRecordCreateFromMemory(features, size, 0, NULL, &m_features_right);

			UpdateAllViews(NULL);
			return;
		}

		// generalization
		m_fingercount = 0;
		const BYTE * gen_features[GENERALIZE_COUNT];
		NSizeType templateSizes[GENERALIZE_COUNT];
		for (int i = 0; i < GENERALIZE_COUNT; i++)
		{
			NSizeType temp;
			BYTE * buffer;
			NFRecordSaveToMemory(m_features[i], NULL, 0, 0, &temp);
			buffer = new BYTE[temp];
			NFRecordSaveToMemory(m_features[i], buffer, temp, 0, &temp);
			gen_features[i]= &buffer[0];
			templateSizes[i] = temp;
			delete[] m_features[i];
		}
		int res;
		STTI(&ti);
		FnceGeneralize(hExtractor, GENERALIZE_COUNT, (const void * *)gen_features, templateSizes,
			(void *) features, MAX_FEATURES_SIZE, &size, &res);
		SPTI(&ti);
		for (int i = 0; i < GENERALIZE_COUNT; i++)
		{
			delete[] gen_features[i];
		}

		AddToLog("Generalization time: " + CString(ti.str));

		if (NSucceeded(res))
		{
			AddToLog(L"Generalization succedded");

			m_img_left = img1;
			m_img_right = img2;

			m_left_dpi = dpi;
			m_right_dpi = dpi;

			NFRecordCreateFromMemory(features, size, 0, NULL, &m_features_right);
			NFRecordGetMinutiaCount(m_features_right, &minutiaCount);

			if (minutiaCount < 10)
			{
				if (AfxMessageBox(L"Minutia count is less than 10.\nContinue enrollment?", MB_YESNO) == IDNO)
					return;
			}

			FPRecord finger;
			finger.size = size;
			finger.features = new BYTE[size];
			fileName = fileName + L" GEN";
			if (fileName.GetLength() > MAX_DESCRIPTION)
			{
				fileName = fileName.Right(MAX_DESCRIPTION);
			}
			wcscpy(finger.description, fileName);
			memcpy(finger.features, features, size);
			m_database.AddFingerprint(&finger);
		}
		else
			AddToLog(L"Generalization failed!");

		return;
	}
	
	if (m_mode == IdentificationMode || m_mode == FastIdentificationMode)
	{
		m_img_left = img1;
		m_img_right = img2;

		NFRecordCreateFromMemory(features, size, 0, NULL, &m_features_right);
	
		m_left_dpi = dpi;
		m_right_dpi = dpi;

		UpdateAllViews(NULL);
		AfxGetApp()->PumpMessage();

		BOOL found = m_database.Identify(features, size, m_settings.m_fullsearch==1, hMatcher);

		if(!found)
		{
			if(m_mode == FastIdentificationMode)
			{
				AddToLog(L"Not identified!");
				AddToLog(L"Updating data...");
				FnceFastExtractFinishWithImage(hExtractor,NULL,features,MAX_FEATURES_SIZE, &size);
				found = m_database.Identify(features, size, m_settings.m_fullsearch==1, hMatcher);
			}

			if(!found)
			{
				CDialogMsg dlg;
				dlg.m_color = RGB(255, 0, 0);
				dlg.m_msg= L"Not identified";
				dlg.DoModal();
			}
		}
		else
		{
			if(m_mode == FastIdentificationMode)
			{
				FnceFastExtractEnd(hExtractor);
			}
		}
		UpdateAllViews(NULL);
		return;
	}

	if (m_mode == VerificationMode || m_mode == FastVerificationMode)
	{
		m_fingercount++;

		NFRecordCreateFromMemory(features, size, 0, NULL, &m_features[m_fingercount-1]);

		if (m_fingercount < 2)
		{
			NImageClone(img2, &m_images_temp);
			AddToLog(L"Enter one more image");

			m_img_left = img2;
			m_left_dpi = dpi;

			NFRecordCreateFromMemory(features, size, 0, NULL, &m_features_left);
			UpdateAllViews(NULL);
			return;
		}

		NImageClone(m_images_temp, &img1);
		m_img_left = img1;
		m_left_dpi = dpi;
		NFRecordClone(m_features[0], &m_features_left);

		m_img_right = img2;
		m_right_dpi = dpi;
		NFRecordCreateFromMemory(features, size, 0, NULL, &m_features_right);
		m_fingercount = 0;

		FncmMatchDetails * pMatchDetails = NULL;

		NInt score = 0;

		NSizeType temlSize1;
		BYTE buffer1[MAX_FEATURES_SIZE];
		NFRecordSaveToMemory(m_features_left, &buffer1, MAX_FEATURES_SIZE, 0, &temlSize1);

		NSizeType temlSize2;
		BYTE buffer2[MAX_FEATURES_SIZE];
		NFRecordSaveToMemory(m_features_right, &buffer2, MAX_FEATURES_SIZE, 0, &temlSize2);

		STTI(&ti);
		FncmVerify(hMatcher, &buffer1, MAX_FEATURES_SIZE, &buffer2, MAX_FEATURES_SIZE, &pMatchDetails, &score);
		SPTI(&ti);

		AddToLog("Verification time: " + CString(ti.str));

		NInt threshold = 0;
		FncmGetParameter(hMatcher, FNCMP_MATCHING_THRESHOLD, &threshold);

		str.Format(L"Similarity: %d Threshold: %d", pMatchDetails->Score, threshold);
		AddToLog(str);

		if (pMatchDetails->Score < threshold)
		{
			if(m_mode == FastVerificationMode)
			{
				AddToLog(L"Fast verification result: failed");
				AddToLog(L"Updating data...");

				FnceFastExtractFinishWithImage(hExtractor, NULL, features, MAX_FEATURES_SIZE, &size);

				NSizeType temlSize;
				BYTE buffer[MAX_FEATURES_SIZE];
				NFRecordSaveToMemory(m_features[0], &buffer, MAX_FEATURES_SIZE, 0, &temlSize);

				STTI(&ti);
				FncmVerify(hMatcher, &buffer, MAX_FEATURES_SIZE, 
					(const void *)features, MAX_FEATURES_SIZE, &pMatchDetails, &score);
				SPTI(&ti);

				AddToLog("Verification time: " + CString(ti.str));
				str.Format(L"Similarity: %d Threshold: %d", pMatchDetails->Score, threshold);
				AddToLog(str);
			}

			if (pMatchDetails->Score < threshold)
			{
				AddToLog(L"Verification result: failed");
			}
			else
			{
				AddToLog(L"Verification result: succeeded");
			}
		}
		else
		{
			if(m_mode == FastVerificationMode)
			{
				FnceFastExtractEnd(hExtractor);
				AddToLog(L"Fast verification result: succeeded");
			}
			else
			{
				AddToLog(L"Verification result: succeeded");
			}
		}

		NFRecordFree(m_features[0]);
		FncmMatchDetailsFree(pMatchDetails);
		NImageFree(m_images_temp);
		UpdateAllViews(NULL);
		return;
	}
}

void CFingerCellDoc::DeleteContents()
{
	CDocument::DeleteContents();
}

void CFingerCellDoc::OnFinalRelease()
{
	CDocument::OnFinalRelease();
}

// modes

void CFingerCellDoc::OnEnrollment()
{
	m_mode = EnrollmentMode;
	AddToLog("Demo mode: Enrollment mode");
	ClearResults();
	UpdateAllViews(NULL);
}

void CFingerCellDoc::OnUpdateEnrollment(CCmdUI* pCmdUI)
{
	pCmdUI->SetCheck(m_mode == EnrollmentMode);
}

void CFingerCellDoc::OnEnrollmentfg()
{
	m_mode = EnrollmentFGMode;
	AddToLog("Demo mode: Enrollment with features generalization mode");
	m_fingercount = 0;
	ClearResults();
	UpdateAllViews(NULL);
}

void CFingerCellDoc::OnUpdateEnrollmentfg(CCmdUI* pCmdUI)
{
	pCmdUI->SetCheck(m_mode == EnrollmentFGMode);
}

void CFingerCellDoc::OnIdentification()
{
	m_mode = IdentificationMode;	
	AddToLog("Demo mode: Identification mode");
	ClearResults();
	UpdateAllViews(NULL);
}

void CFingerCellDoc::OnUpdateIdentification(CCmdUI* pCmdUI)
{
	pCmdUI->SetCheck(m_mode == IdentificationMode);
}

void CFingerCellDoc::OnFastIdentification()
{
	m_mode = FastIdentificationMode;	
	AddToLog("Demo mode: Fast identification mode");
	ClearResults();
	UpdateAllViews(NULL);
}

void CFingerCellDoc::OnUpdateFastIdentification(CCmdUI* pCmdUI)
{
	pCmdUI->SetCheck(m_mode == FastIdentificationMode);
}

void CFingerCellDoc::OnVerification()
{
	m_mode = VerificationMode;
	AddToLog("Demo mode: Verification mode");
	m_fingercount = 0;
	ClearResults();
	UpdateAllViews(NULL);
}

void CFingerCellDoc::OnUpdateVerification(CCmdUI* pCmdUI)
{
	pCmdUI->SetCheck(m_mode == VerificationMode);
}

void CFingerCellDoc::OnFastVerification()
{
	m_mode = FastVerificationMode;
	AddToLog("Demo mode: Fast verification mode");
	m_fingercount = 0;
	ClearResults();
	UpdateAllViews(NULL);
}

void CFingerCellDoc::OnUpdateFastVerification(CCmdUI* pCmdUI)
{
	pCmdUI->SetCheck(m_mode == FastVerificationMode);
}


HNImage CFingerCellDoc::GetLeftImage()
{
	return m_img_left;
}

HNImage CFingerCellDoc::GetRightImage()
{
	return m_img_right;
}

HNFRecord CFingerCellDoc::GetLeftFeatures()
{
	return m_features_left;
}

HNFRecord CFingerCellDoc::GetRightFeatures()
{
	return m_features_right;
}

int CFingerCellDoc::GetZoom()
{
	return zoom;
}

void CFingerCellDoc::OnZoom11()
{
	zoom = 100;
	UpdateAllViews(NULL);
}

void CFingerCellDoc::OnZoomIn()
{
	zoom += 20;
	if (zoom > 800)
		zoom = 800;

	UpdateAllViews(NULL);
}

void CFingerCellDoc::OnZoomOut()
{
	zoom -= 20;
	if (zoom < 25)
		zoom = 25;

	UpdateAllViews(NULL);
}

void CFingerCellDoc::OnShowBlockedorientations()
{
	showBlockedOrientations = !showBlockedOrientations;
	UpdateAllViews(NULL);
}

void CFingerCellDoc::OnUpdateShowBlockedorientations(CCmdUI* pCmdUI)
{
	pCmdUI->SetCheck(showBlockedOrientations == TRUE);
}

void CFingerCellDoc::OnShowFeatures()
{
	showFeatures = !showFeatures;
	UpdateAllViews(NULL);
}

void CFingerCellDoc::OnUpdateShowFeatures(CCmdUI* pCmdUI)
{
	pCmdUI->SetCheck(showFeatures == TRUE);
}

void CFingerCellDoc::OnShowSingularpoints()
{
	showSingularPoints = !showSingularPoints;	
	UpdateAllViews(NULL);
}

void CFingerCellDoc::OnUpdateShowSingularpoints(CCmdUI* pCmdUI)
{
	pCmdUI->SetCheck(showSingularPoints == TRUE);
}

void CFingerCellDoc::OnOptions()
{
	m_settings.DoModal();
}

void CFingerCellDoc::OnClearDb()
{
	m_database.ClearDB();
}

void CFingerCellDoc::ClearResults()
{
	// clear images
	if (m_img_left)
	{
		NImageFree(m_img_left);
		m_img_left = NULL;
	}

	if (m_img_right)
	{
		NImageFree(m_img_right);
		m_img_right = NULL;
	}
	// clear features
	if (m_features_left)
	{
		NFRecordFree(m_features_left);
		m_features_left = NULL;
	}

	if (m_features_right)
	{
		NFRecordFree(m_features_right);
		m_features_right = NULL;
	}
}

void CFingerCellDoc::OnShowBinaryImage()
{
	showBinaryImage = !showBinaryImage;
	UpdateAllViews(NULL);
}

void CFingerCellDoc::OnUpdateShowBinaryImage(CCmdUI* pCmdUI)
{
	pCmdUI->SetCheck(showBinaryImage == TRUE);
}

void CFingerCellDoc::OnScanf()
{
#ifdef NO_BIO_API
	AfxMessageBox(_T("BioAPI is not supported on this platform!"));
#else
	m_fddlg.m_description = m_fdescription;

	bool notneed = (m_mode == IdentificationMode) || 
		(m_mode == VerificationMode);

	if (!notneed)
	{
		if (m_fddlg.DoModal() != IDOK)
			return;
	}

	UpdateAllViews(NULL);
	AddToLog(_T("Scan fingerprint...."));

	UpdateAllViews(NULL);
	AfxGetApp()->PumpMessage();

	m_fdescription = m_fddlg.m_description;

	BioAPI_VERSION Version;

	if (BioAPI_Init(&Version, 0, NULL, 0, NULL) != BioAPI_OK) 
	{
		AfxMessageBox(_T("BioAPI Init failed!"));
		return;

	}

	int Timeout = 5000; //(30 seconds)

	OriginalBIR.BiometricData = NULL;
	retCode = BioAPI_Capture(0, BioAPI_PURPOSE_ENROLL, (BioAPI_BIR_PTR)&CapturedBIR, (BioAPI_BIR_PTR)&OriginalBIR, Timeout);

	while (true)
	{
		if (retCode != BioAPI_OK)
		{
			AddToLog(_T("BioAPI_Capture failed."));	
			break;
		}

		if (CapturedBIR.Header.Quality == 0)
		{
			AddToLog(_T("Image quality is poor."));
			break;
		}

		if (CapturedBIR.Header.Quality == 1)
		{
			AddToLog(_T("Image quality is acceptable."));
		}

		if (CapturedBIR.Header.Quality == 2)
		{
			AddToLog(_T("Image quality is good."));
		}

		// if current image quality is acceptable or better
		if (CapturedBIR.Header.Quality != 0)
		{
			MessageBeep(MB_OK);
			m_image_from_iPAQ = TRUE;
			OnLoadImage();
		}
		else
		{
			MessageBeep(MB_ICONEXCLAMATION);
		}

		break;
	}

	free(OriginalBIR.BiometricData); 


	BioAPI_Terminate();
#endif
}
