// FingerAnalyserDlg.cpp : implementation file
//#pragma once

#include "stdafx.h"
#include "FingerAnalyser.h"
#include "FingerAnalyserDlg.h"
#include "math.h"

#include <list>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CFingerAnalyserDlg dialog

CFingerAnalyserDlg::CFingerAnalyserDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CFingerAnalyserDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

	// Инициализация переменных
	m_WorkFile = _T("");			// рабочий файл
	m_ShowBase = FALSE;				// Просмотр выключен
	mouseX = 0;						// Координаты точки
	mouseY = 0;
	m_DotsCount = 0;					// Количество точек
	m_ScanTime = 0;					// Время анализа
	picture = NULL;
}
// Деструктор
CFingerAnalyserDlg::~CFingerAnalyserDlg()
{
	delete(fp);
	delete(picture);

	if(compareResult) 
	{	
		for(list<CCompareFing>::iterator i = compareResult->begin();i != compareResult->end();i++)
		{	
			list<CPairSur>::iterator j;
			
			for(j=i->surdots.begin(); j!=i->surdots.end(); j++)
			{
				j->first->clear();  
				delete(j->first);
				j->second->clear(); 
				delete(j->second);
			}
		}

		compareResult->clear();
		delete(compareResult);
		compareResult = NULL;
	}
}

void CFingerAnalyserDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Check(pDX, IDC_SHOW, m_ShowBase);
	DDX_Control(pDX, IDC_PROGRESS_COMPARE, m_ProgressCompare);
	DDX_Control(pDX, IDC_PROGRESS_SAVE, m_ProgressSave);
	DDX_Text(pDX, IDC_POINTS, m_DotsCount);
	DDX_Text(pDX, IDC_TIME, m_ScanTime);
	DDX_Text(pDX, IDC_FILE, m_WorkFile);
}

BEGIN_MESSAGE_MAP(CFingerAnalyserDlg, CDialog)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDC_OPEN, &CFingerAnalyserDlg::OnBnClickedOpen)
	ON_BN_CLICKED(IDC_ANALYSE, &CFingerAnalyserDlg::OnBnClickedAnalyse)
	ON_BN_CLICKED(IDC_COMPARE, &CFingerAnalyserDlg::OnBnClickedCompare)
	ON_BN_CLICKED(IDC_SAVE, &CFingerAnalyserDlg::OnBnClickedSave)
	ON_BN_CLICKED(IDC_BACK, &CFingerAnalyserDlg::OnBnClickedBack)
	ON_BN_CLICKED(IDC_NEXT, &CFingerAnalyserDlg::OnBnClickedNext)
	ON_BN_CLICKED(IDC_SHOW,&CFingerAnalyserDlg::OnBnClickedShowBase)
	ON_WM_LBUTTONDOWN()
	ON_WM_TIMER()
END_MESSAGE_MAP()


// CFingerAnalyserDlg message handlers

BOOL CFingerAnalyserDlg::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

	fp = new CFingPicture(this->GetDC());

	char fullpath[200];
	_fullpath(fullpath, NULL, 200);
	pathToSAV = fullpath;
	pathToSAV += "\\sav\\";
	dbFile = pathToSAV + "fingbase.bse";
	compareResult = NULL;

	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 CFingerAnalyserDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<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
	{
		CPaintDC dc(this);
		if(m_ShowBase)
		{
			ShowBase(true,false);
		}
		else
		{//режим просмотра открытого образа
			if (picture != NULL)
			{
				picture->GetPic1()->Show(140, 70);
				picture->GetPic2()->Show(545, 70);
			}
			
			m_DotsCount = (int)fingA.size();
			UpdateData(false);
	}

		CDialog::OnPaint();
	}
}

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

// Открытие файла
void CFingerAnalyserDlg::OnBnClickedOpen()
{
	char szFilters[]= "Образы (*.bmp)|*.bmp|All Files (*.*)|*.*||";
	CFileDialog dlg(TRUE, "bmp", "*.bmp", OFN_FILEMUSTEXIST| OFN_HIDEREADONLY, szFilters, this);

	if(dlg.DoModal() != IDOK) 
		return;		//никаких файлов не открыли

	if(dlg.GetFileExt().CompareNoCase("bmp")) 
		return;	//открытый файл не имеет расширеня .bmp

	CString fileName = dlg.GetFileName();
	
	if(picture != NULL)
		delete(picture);

	picture = new CAnalysePicture(fileName, this->GetDC());
	m_WorkFile = fileName;

	if(compareResult)
	{
		for(list<CCompareFing>::iterator i = compareResult->begin(); i != compareResult->end(); i++)
		{	
			list<CPairSur>::iterator j;
			for(j=i->surdots.begin(); j!=i->surdots.end(); j++)
			{
				j->first->clear(); 
				delete(j->first);
				j->second->clear(); 
				delete(j->second);
			}	
		}
	
		compareResult->clear();
	}
	
	m_ShowBase = false;
	Invalidate();
}

// Анализ изображения
void CFingerAnalyserDlg::OnBnClickedAnalyse()
{
	if(picture == NULL) 
		return;

	LPSYSTEMTIME mTime;
	mTime = new SYSTEMTIME;
	GetSystemTime(mTime);
	long int workTime;
	workTime = mTime->wSecond*1000+mTime->wMilliseconds;

	fingA = picture->AnalysePicture();
	fingA.SaveFing(GetSAV(picture->getPathSrc()));

	GetSystemTime(mTime);

	workTime = mTime->wSecond*1000+mTime->wMilliseconds - workTime;
	workTime = (workTime<0)?60000+workTime:workTime;
	delete(mTime);
	m_ScanTime = workTime;
	Invalidate();
}
// Сравнение
void CFingerAnalyserDlg::OnBnClickedCompare()
{
	if(fingA.size() == 0) 
	{	
		MessageBox("Отпечаток не обработан", "Ошибка");
		return;
	}

	fingR.Convert(fingA);

	if(compareResult) 
	{	
		for(list<CCompareFing>::iterator i = compareResult->begin(); i != compareResult->end(); i++)
		{	
			list<CPairSur>::iterator j;

			for(j=i->surdots.begin(); j!=i->surdots.end(); j++)
			{
				j->first->clear(); delete(j->first);
				j->second->clear(); delete(j->second);
			}
		}

		compareResult->clear();
		delete(compareResult);
		compareResult = NULL;
		showIter = NULL;
	}

	compareResult = CompareWithBase();

	if(compareResult->size() == 0) 
		return;

	CString sOut="";

	for(list<CCompareFing>::iterator i = compareResult->begin(); i != compareResult->end(); i++)
	{
		CString s="";
		int mlevel = min(i->nfng,m_DotsCount);
		int percent;
	
		if(mlevel > 10) 
			mlevel = 10;

		if(i->cDot > mlevel) 
			percent = 100;
		else 
			percent = (int)(100.0*i->cDot/(double)mlevel + 0.5);

		if(percent == 0) 
			continue;

		s.Format("%d %d %% %s\n", i->cDot, percent, i->name);
		sOut += s;
	}

	if(sOut.GetLength()==0) 
		sOut = "Ни одного отпечатка не найдено!\n";

	CString kol; 
	kol.Format("\n Всего в базе: %d", compareResult->size());
	sOut += kol;

	PrintReport(picture->getPathSrc(), sOut);
	MessageBox(sOut, picture->getPathSrc()); 
}

// Сохранить в БД
void CFingerAnalyserDlg::OnBnClickedSave()
{
	char szFilters[] = "Образы (*.bmp)|*.bmp|All Files (*.*)|*.*||";
	CFileDialog dlg(	TRUE, "bmp", "*.bmp", OFN_FILEMUSTEXIST| OFN_HIDEREADONLY| OFN_ALLOWMULTISELECT, szFilters, this);

	if(dlg.DoModal() == IDOK)
	{
		listCInfo *fingDB = LoadDB(dbFile);
		FILE *fbse = fopen(dbFile, "wb");

		if(fbse == NULL)
		{
			MessageBox("Невозможно создать базу данных с отпечатками", "Ошибка создания БД", MB_OK);
			return;
		}

		POSITION pos, posStart;
		CInfo newFingInDB;
		pos = posStart = dlg.GetStartPosition();
		int kolFile = 0;

		while(pos)
		{
			dlg.GetNextPathName(pos); 
			kolFile++;
		}

		pos = posStart;
		m_ProgressSave.SetRange(0, kolFile);
		int progressPos = 1;
		
		while(pos)
		{
			CString fileName = dlg.GetNextPathName(pos).MakeLower();
	
			if(fileName.Find(".bmp") == -1) 
				continue;

			CAnalysePicture *loadingPic;
			loadingPic = new CAnalysePicture(fileName, this->GetDC());
			m_WorkFile = fileName;
			fingA = loadingPic->AnalysePicture();
		
			if(fingA.size() < MIN_SIZE) 
			{
				MessageBox("Отпечаток не пригоден для сохраниения в базу!", fileName); 
				continue;
			}

			if(fingA.size() > MAX_SIZE) 
			{
				MessageBox("Отпечаток не пригоден для сохраниения в базу!", fileName); 
				continue;
			}

			fingA.SaveFing(GetSAV(fileName));
			newFingInDB.src = fileName;
			fingDB->remove(newFingInDB);
			fingDB->push_back(newFingInDB);
			m_ProgressSave.SetPos(progressPos);
			progressPos++;
			Invalidate();
			delete(loadingPic);
		} 

		m_ProgressSave.SetPos(0);
		int count = 0;
		fwrite((void*)&count, sizeof(count), 1, fbse);
	
		for(list<CInfo>::iterator iter = fingDB->begin(); iter != fingDB->end(); iter++)
		{
			iter->Printf(fbse);
			count++;
		}
		
		fseek(fbse, 0, SEEK_SET);
		fwrite((void*)&count, sizeof(count), 1, fbse);
		fingDB->clear();
		delete(fingDB);
		fclose(fbse);
	}

}

void CFingerAnalyserDlg::OnBnClickedBack()
{
	ShowBase(false);
}

void CFingerAnalyserDlg::OnBnClickedNext()
{
	ShowBase(true);
}

// Нажатие кнопки мыши над формой
void CFingerAnalyserDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
	if(!m_ShowBase) 
		return;

	mousePos = point;
	mousePos.x -= 110;
	mousePos.y -= 45;
	ShowBase(true, false);

	CDialog::OnLButtonDown(nFlags, point);
}

// обновлять при событии от таймера
void CFingerAnalyserDlg::OnTimer(UINT_PTR nIDEvent)
{
	Invalidate();
	CDialog::OnTimer(nIDEvent);
}


void CFingerAnalyserDlg::OnBnClickedShowBase()
{
	m_ShowBase =! m_ShowBase;
	UpdateData(false);

	if(m_ShowBase)
	{
		ShowBase(true, false);
	}
	else
	{
		OnPaint();
	}
}

//key - направление перемотки по базе (влево, вправо)
//next - нужно ли переходить к следующему отпечатку
void CFingerAnalyserDlg::ShowBase(bool key, bool next)
{

	if(!compareResult) 
		return;

	if(compareResult->size() == 0)
	{	
		MessageBox("База данных отпечатков пуста", "Сообщение", MB_OK);
		return;
	}

	if (showIter == NULL)
		showIter = compareResult->begin();
	else 
	{	
		if(next)
			if(key) 
			{
				showIter++;
			
				if(showIter == compareResult->end())
					showIter = compareResult->begin();
			}
			else
			{
				if(showIter == compareResult->begin()) 
					showIter = compareResult->end();
				showIter--;
			}
	}

	CFingPicture *pic;
	pic = new CFingPicture(this->GetDC());

	if(!pic->Load(BLANK)) 
		return;

	CPaintDC dc(this); // device context for painting

	list<CPairSur>::iterator is = showIter->surdots.begin();
	list<CPairAbsDot>::iterator id = showIter->dots.begin();

	for(; id != showIter->dots.end(); id++, is++)
	{	
		COLORREF col;

		if(is->first->empty())	
			col = 0xBBBBBB;
		else					
			col = (id->first.type)?0xff0000:0x000000;

		pic->Line(id->first.coord, id->first.coord, 5, col);
		pic->Line(id->first.coord, 
		CPoint(id->first.coord.x+(int)(10.0*cos(id->first.alpha)),id->first.coord.y-(int)(10.0*sin(id->first.alpha))),2, col);

		if(is->first->empty()) 
			continue;	//окружения для этой точки нет

		//проверка, что "мышь" находится над точкой
		if( abs(mousePos.x-id->first.coord.x)<6 && abs(mousePos.y-id->first.coord.y)<6 )
		{
			CFingPicture pic2(this->GetDC());
		
			if(!pic2.Load(BLANK)) 
				return;

			pic2.Copy(*picture->GetPic2());

			for(listCRelDot::iterator ii = is->first->begin(); ii != is->first->end(); ii++)
			{	
				COLORREF cl = 0x554444;
				CPoint cd;
				cd.x = (long)(id->first.coord.x - ii->l * cos(ii->a1*M_PI/180.0 - id->first.alpha));
				cd.y = (long)(id->first.coord.y - ii->l * sin(ii->a1*M_PI/180.0 - id->first.alpha));
				pic->Line(id->first.coord, cd, 1, cl);
			}

			for(listCRelDot::iterator ii = is->second->begin(); ii != is->second->end(); ii++)
			{		
				COLORREF cl = 0x554444;
				CPoint cd;
				cd.x = (long)(id->second.coord.x - ii->l * cos(ii->a1*M_PI/180.0 - id->second.alpha));
				cd.y = (long)(id->second.coord.y - ii->l * sin(ii->a1*M_PI/180.0 - id->second.alpha));
				pic2.Line(id->second.coord, cd, 1, cl);
			}

			pic2.Show(545, 45);
		}
	}

	if (pic != NULL)
	{
		pic->Show(110, 45);
		m_WorkFile = showIter->name;
	}
	
	UpdateData(false);
	delete(pic);
}

void CFingerAnalyserDlg::PrintReport(CString file, CString report)
{
	FILE *outf = fopen("report.txt", "a");
	CString msg = "\n------ "+file+" ------\n"+report;
	fprintf(outf, msg);
	fclose(outf);
}
CString CFingerAnalyserDlg::GetSAV(CString srcName)
{
	CString fsav = srcName.Left(srcName.GetLength() - 3) + "sav";
	while(fsav.Find("\\") != -1){ fsav = fsav.Right(fsav.GetLength() - fsav.Find("\\")-1); }
	return pathToSAV + fsav;
}

//загрузить точки из БД
listCInfo *CFingerAnalyserDlg::LoadDB(CString dbFile)
{
	listCInfo *bse = new listCInfo();
	CInfo finf;			//данные по отпечатку

	FILE *fbse = fopen(dbFile, "rb");

	if(fbse == NULL)
	{
//		MessageBox("Невозможно загрузить базу данных с отпечатками", "Ошибка загрузки БД", MB_OK);
		return bse;
	}

	int count = 0;
	fread((void*)&count, sizeof(count), 1, fbse);

	for(;count > 0; count--)
	{
		finf.Scanf(fbse);
		bse->push_back(finf);
	}

	fclose(fbse);
	
	return bse;
}

//сравнить точку с точками в БД
list<CCompareFing> *CFingerAnalyserDlg::CompareWithBase()
{
	listCInfo *bse;
	list<CCompareFing> *cFng;
	cFng = new list<CCompareFing>;
	bse = LoadDB(dbFile);

	if(bse->empty()) 
	{	
		MessageBox("База данных отпечатков пуста", "Сообщение", MB_OK);
		return cFng;
	}

	CAbsFing aFng;
	CRelFing baseFng;

	m_ProgressCompare.SetRange(0, (short)bse->size());

	for(list<CInfo>::iterator ibse = bse->begin();ibse != bse->end(); ibse++)
	{
	
		if(!aFng.LoadFing(GetSAV(ibse->src))) 
			continue;

		baseFng.Convert(aFng);
		CCompareFing compareRes = fingR.Compare(baseFng);
		compareRes.name = ibse->src;
		cFng->push_back(compareRes);
		m_ProgressCompare.SetPos((int)cFng->size());
	}
	
	bse->clear();
	m_ProgressCompare.SetPos(0);
	delete(bse);
	return cFng;
}
