//---------------------------------------------------------------------------00


#pragma hdrstop

#include <IniFiles.hpp>
#include "Validator.h"
#include "ud_Module.h"

//---------------------------------------------------------------------------
Validator* validator=NULL;
//---------------------------------------------------------------------------

#pragma package(smart_init)
//---------------------------------------------------------------------------
#define POLYNOMIAL 0x08408
unsigned int GetCRC16(unsigned char* bufData, unsigned int sizeData)
{
	unsigned int CRC, i;
	unsigned char j;
	CRC = 0;
	for(i=0; i < sizeData; i++)
	{
		CRC ^= bufData[i];
		for(j=0; j < 8; j++)
		{
			if(CRC & 0x0001) {CRC >>= 1; CRC ^= POLYNOMIAL;}
			else CRC >>= 1;
		}
	}
	return CRC;
}
//---------------------------------------------------------------------------
//Добавить нули к цифре
int addZero(int val,int cnt)
{
	for(int i=0;i<cnt;i++)
		val=val*10;
	return val;
}
//---------------------------------------------------------------------------
Validator::Validator()
{
	Pay=0;
	cPort=new ComPort();
	bNominals=false;

	LoadSetup();
}
//---------------------------------------------------------------------------
Validator::~Validator()
{
	delete cPort;
}
//---------------------------------------------------------------------------
bool Validator::Start()
{
	if(cPort->Open(cPort->port))
	{
		cPort->BaudRate=cPort->BaudRate;
		if(!cPort->Setup()) return false;

		if(!Reset()) return false; //Перезагрузить валидатор
		if(!getSerialNumber()) return false; //Получить серийный номер
		if(!getNominals()) return false; //Получить номиналы прошитых купюр
	}else return false;
}
//---------------------------------------------------------------------------
//Сравнить последние 2 байта с CRC данных
bool Validator::CheckOnCRC(unsigned char* lpBuffer,unsigned long nSize)
{
	if(nSize<2) return false;
	unsigned int CRC=GetCRC16(lpBuffer,nSize-2);
	WORD* pCRC=(WORD*)&lpBuffer[nSize-2];
	return (CRC==*pCRC);
}
/*---------------------------------------------------------------------------
Перезагрузить валидатор*/
bool Validator::Reset()
{
	DWORD BytesWritten=cPort->Write(ConReset,sizeof(ConReset));
	DWORD BytesRead=cPort->Read(ReadAr,sizeof(ReadAr));
	Sleep(5000);
	return CheckOnCRC(ReadAr,BytesRead);
}
//---------------------------------------------------------------------------
bool Validator::getSerialNumber()
{
	DWORD BytesWritten=cPort->Write(ConIdent,sizeof(ConIdent));
	DWORD BytesRead=cPort->Read(ReadAr,sizeof(ReadAr));
	if(!CheckOnCRC(ReadAr,BytesRead)) return false;
	//Нужный ли нам ответ
	if(BytesRead!=39)
	{
		saveLog("Не удалось получить номер партии валидатора");
		return false;
	}
	//Выбираем № партии
	AnsiString str1((char*)&ReadAr[3],15);
	BatchNumber=str1.Trim();

	AnsiString str2((char*)&ReadAr[18],12);
	SerialNumber=str2.Trim();

	Sleep(100);
	return true;
}
//---------------------------------------------------------------------------
bool Validator::getNominals()
{
        bNominals=false;
	Sleep(100); //на всяк
	DWORD BytesWritten=cPort->Write(ConGetBT,sizeof(ConGetBT));
	DWORD BytesRead=cPort->Read(ReadAr,sizeof(ReadAr));
	if(!CheckOnCRC(ReadAr,BytesRead)) return bNominals;
	Sleep(100); //на всяк
	for(unsigned char i=0;i<23;i++)
	{
		bt[i].val=addZero(ReadAr[3+i*5],ReadAr[3+i*5+4]);
		//Код страны 3 буквы
		bt[i].country[0]=ReadAr[3+i*5+1];
		bt[i].country[1]=ReadAr[3+i*5+2];
		bt[i].country[2]=ReadAr[3+i*5+3];
		bt[i].val=addZero(ReadAr[3+i*5],ReadAr[3+i*5+4]);
	}
        bNominals=true;
	return bNominals;
}
//---------------------------------------------------------------------------
void Validator::LoadSetup()
{
	TIniFile* ini=new TIniFile(ExtractFilePath(ParamStr(0))+"\\Setup.ini");
	cPort->port=ini->ReadString("Validator","Port","");
	cPort->BaudRate=ini->ReadInteger("Validator","BaudRate",0);
	delete ini;
}
//---------------------------------------------------------------------------
void Validator::SaveSetup()
{
	TIniFile* ini=new TIniFile(ExtractFilePath(ParamStr(0))+"\\Setup.ini");
	ini->WriteString("Validator","Port",cPort->port);
	ini->WriteInteger("Validator","BaudRate",cPort->BaudRate);
	delete ini;
}
//---------------------------------------------------------------------------
bool Validator::startPay() //Стартуем поток
{
	vThread = new ValidatorThread(false);
}
//---------------------------------------------------------------------------
bool Validator::stopPay() //Стопим поток
{
	vThread->Stop();
}
//---------------------------------------------------------------------------
//Это выполняется в цикле в отдельном потоке
int Validator::getPay()
{
	if(!cPort->bOpen){Sleep(1000); return 0;}

	int result=0;
	DWORD BytesWritten=0;
	DWORD BytesRead=0;

	BytesWritten=cPort->Write(ConReACK, sizeof(ConReACK)); //Ответ валидатору что всё нормально
	Sleep(10);

	BytesWritten=cPort->Write(ConStPoll, sizeof(ConStPoll)); //Перейти в режим получения платежей
	BytesRead=cPort->Read(ReadAr,sizeof(ReadAr));
	if(CheckOnCRC(ReadAr,BytesRead))
	{
		if(ReadAr[3] == 19)
		{}else
		if(ReadAr[3]==20) //IDLING – The state in which Bill-to-Bill is ready accept bills.
		{}else
		if(ReadAr[3]==21) //******Приняли купюру(Прошла 1 из проверок)*****
		{}else
		if(ReadAr[3]==23)
		{}else
		if(ReadAr[3]==25) //DISABLED – The Bill-to-Bill unit has been disabled by the Controller and also the state in which Bill-to-Bill unit is after initialization.
		{
			BytesWritten=cPort->Write(ConEnBT , sizeof(ConEnBT));
			BytesRead=cPort->Read(ReadAr,sizeof(ReadAr));
		}else
		if(ReadAr[3]==28) //Извлечена купюра
		{}else
		if(ReadAr[3]==69)
		{}else
		if(ReadAr[3]==129) //В какую касету попала купюра
		{
			if(ReadAr[4]<23)
			{
				result=bt[ReadAr[4]].val; //В касете ReadAr[5]
				saveLog("(Pay)"+IntToStr(result));
			}
		}
	}
	Sleep(100);

	return result;
}
//---------------------------------------------------------------------------
//Завершение работы по приёму платежей
void Validator::endPay()
{
	DWORD BytesWritten=cPort->Write(ConDiBT , sizeof(ConDiBT));
	DWORD BytesRead=cPort->Read(ReadAr,sizeof(ReadAr));

	BytesWritten=cPort->Write(ConReACK , sizeof(ConReACK));

	BytesWritten=cPort->Write(ConStPoll , sizeof(ConStPoll));
	BytesRead=cPort->Read(ReadAr,sizeof(ReadAr));
}
//---------------------------------------------------------------------------
int Validator::GetState() //Если 0 то всё в порядке
{
	//if(! bNominals) getNominals();  //todo не подходит для проверки
	if(! bNominals) return 1;

	return 0;
}
//---------------------------------------------------------------------------
AnsiString Validator::GetStatusDescription(BYTE StatusCode) //Описание статуса
{
	if (StatusCode == 0x00)
		return "OK";
	else
	if (StatusCode == 1)
		return "Не удалось получить номиналы купюр";
	else
		return "Error";
}
//---------------------------------------------------------------------------
