//---------------------------------------------------------------------------
#pragma hdrstop

#include "PrinterOPOS.h"
//#include "OposFiscalPrinter_1_7_Lib_OCX.h"
//#include "ud_Module.h"
//#include <Registry.hpp>
#include <Math.h>
#include <exception>
#include <winreg.h>
//#include <DateUtils.hpp>
//#include <Dialogs.hpp>

#include "inifile.h"
#include "stdTools.h"
//---------------------------------------------------------------------------

//#pragma package(smart_init)
//---------------------------------------------------------------------------
//FiscalPrinter* g_printer;
//---------------------------------------------------------------------------
wchar_t * kkm_err_msg_ru[] = {
L"OK",								//0
L"ФП ID ошибка",						//1	FM ID Error
L"Ошибка записи в ФП ",				//2	FM Rec Error
L"Flash Chip не может быть очищен",	//3 Flash Chip cant clear
L"ФП не пуста",						//4	FM not empty
L"Данные в ФП разрушенны",			//5	FM Data destroyed
L"Реж принтер игнорир кмд",			//6	Cmd ignor prn mode
L"Нет кода оператора",				//7	Oper code is absent
L"Нет типа документа",				//8	Doc type is absent
L"Сер. номер ККМ",					//9 Ser num CR
L"Ошибка пароля",					//10 Password error
L"Ошибка дата/время",				//11 Data/Time error
L"Завод. рег. ранее",				//12 Factory registration has already pass
L"Сер ном ККМ разрушен",				//13 Ser num CR destroyed
L"Фискализация ранее",				//14 Fiscalize has already pass
L"ККМ не фиск режим",				//15 Not fisc mode CR
L"Фискал ККМ разрушен",				//16 Fiscalize Data destroyed
L"Перерег ККМ исчерпан",				//17 Rewrite is conclude
L"Перерег ККМ разрушен",				//18 Rewrite is destroyed
L"Смена открыта",					//19 Shift already open
L"См не была открыта",				//20 Shift not opened
L"Много товара в чеке",				//21 Many goods in receipt
L"СМ в ФП разрушенна",				//22 EOD data in FM destroyed
L"Формат документа",					//23 Document format error
L"Перезапись текста",				//24 Text rewrite
L"Много пар-ров док",				//25 Many parameters in document
L"Ош параметр док-та",				//26 Document parameters error
L"Ош значения пар-ра",				//27 Parameters value error
L"Несуществующ объект",				//28 Object non-existent
L"Док не был завершен",				//29 Document is not finished
L"Товар/опер не полно",				//30 goods/operation description not enough
L"Контрол сумма пакета",				//31 Check sum packet
L"Принтер не готов",					//32 Prn not ready
L"Вложенные прерывания",				//33 Nested interrupts
L"Байт подтв прием данных",			//34 Check Sum Error
L"Переполненние в ФП",				//35 Overflow if FM
L"Неизвестная комманда",				//36 Unknown command
L"CRC ОЗУ",							//37 CRC RAM
L"CRC ФП",							//38 CRC FM
L"Порт данных неисправ",				//39 Data port defective
L"Порядок рекв чека",				//40 Receipts parameters sequence
L"0xy для обязат рекв",				//41 0xy for required properties
L"Длинна запроса",					//42 Length request
L"Разрядность числа",				//43 number capacity
L"Переполнение",						//44 Overflow
L"Нет числа",						//45 Number is absent
L"Нет ответа",						//46 Not response
L"Ошибка передачи",					//47 Transmission error
L"Мат. переполнение",				//48 Math overflow
L"Нет бумаги...",					//49 Paper out...
L"ККМ не готова!!!",					//50 CR not ready!!!
L"Сбой памяти!!",					//51 Memory error!!
L"Принтер выключен",					//52 Printer off
L"Недостаточно памяти",				//53 Insufficient memory
L"Длинна номера меньше",				//54 Lenght number less
L"Нулевая длинна номера",			//55 Zero lenght number
L"Длинна пароля меньше допустимой",	//56 Password lenght less permissible
L"Нулевая длинна пароля",			//57 Zero lenght password
L"Недопустимая величина",			//58 Impossible value
L"Превышен тайм-аут",				//59 Time-out overdraw
L"",
L"Ош.ЭКЛЗ",
L"Недопустимое состояние ЭКЛЗ",
L"Данные учтены",
L"",L"",L"",L"",L"",L"",//69
L"",L"",L"",L"",L"",L"",L"",L"",L"",L"",//79
L"",L"",L"",L"",L"",L"",L"",L"",L"",L"",//89
L"",L"",L"",L"",L"",L"",L"",L"",L"",L"",//99
L"",L"",L"",L"",L"",L"",L"",L"",L"",L"",//109
L"",L"",L"",L"",L"",L"",L"",L"",L"",L"",//119
L"",L"",L"",L"",L"",L"",L"",L"",L"",L"",//129
L"",L"",L"",L"",L"",L"",L"",L"",L"",L"",//139
L"",L"",L"",L"",L"",L"",L"",L"",L"",L"",//149
L"",L"",L"",L"",L"",L"",L"",L"",L"",L"",//159

L"",L"",L"",L"",L"",L"",L"",L"",L"",L"",//169
L"",L"",L"",L"",L"",L"",L"",L"",L"",L"",//179
L"",L"",L"",L"",L"",L"",L"",L"",L"",L"",//189
L"",L"",L"",L"",L"",L"",L"",L"",L"",L"",//199
L"",L"",L"",L"",L"",L"",L"",L"",L"",L"",//209
L"",L"",L"",L"",L"",L"",L"",L"",L"",L"",//219
L"",L"",L"",L"",L"",L"",L"",L"",L"",L"",//229
L"",L"",L"",L"",L"",L"",L"",L"",L"",L"",//239
L"Команды нет",//240									Cmd not init
L"Ош. посылки команды",//241							Cmd write err
L"Команда не отослана ККМ-неготов(DSR=0)",//242					Prn not ready (DSR=0)
L"Команда отослана, но ответ что ККМ-неготов",//243		Cmd ok
L"Превышено время ожидания ответа",//244					Cmd resp timeout
L"Ошибка",//245										Prn error
L"Пришло больше данных, чем ожидали",//246			Cmd resp large
L"Пришло меньше данных, чем ожидали",//247			Cmd resp small
L"Пришли некие данные",//248
L"Порт закрыт",//249
L"Порт закрыт во время выполнения",//250				Cmd break
L"ККМ выключен или сломан",//251
L"ККМ неготов",//252
L"Ошибка в параметрах команды",//253
L"Несуществующий номер команды",//254
L"ККМ занят(предыдущая команда)!"//255			Previous cmd run
};
//------------------------------------------------------------------------------
bool FiscalPrinter::getNextCheckId(int &id)
{
	CheckId++; //Номер чека
	SaveSetup(); //сохраняем номер чека
        id=CheckId;
	return true;
}
//---------------------------------------------------------------------------
bool FiscalPrinter::SaveCheck(int CheckId) //Сохранение чека для последующей распечатки (суммы)
{
	/*if(dModule->UserType) //true - Юредическое лицо; false - физическое лицо
		dModule->SaveCheck(CheckId,dModule->UserId,0,getGoodsPrice());
	else
		dModule->SaveCheck(CheckId,0,dModule->UserId,getGoodsPrice());*/
	return true;
}
//---------------------------------------------------------------------------
bool FiscalPrinter::deleteCheck(int CheckId) //Удаление чека
{
	//dModule->UpdateChek(CheckId);
	return true;
}
//---------------------------------------------------------------------------
int FiscalPrinter::getCOMPort()
{
	HKEY keyHandle;
	char rgValue[1024];
	char fnlRes[1024];
	DWORD size1;
	DWORD Type;

	std::string str = "-1";

	if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,L"\\SOFTWARE\\OLEforRetail\\ServiceOPOS\\FiscalPrinter\\MbsFiscalPrinter", 0, KEY_QUERY_VALUE, &keyHandle) == ERROR_SUCCESS)
	{
		size1 = 1023;
		RegQueryValueEx(keyHandle, L"COM Num", NULL, &Type, (LPBYTE)rgValue, &size1);
		str = rgValue;
		RegCloseKey(keyHandle);
	}
	return Utility::StdStrToInt(str);
}
//---------------------------------------------------------------------------
bool FiscalPrinter::setBaudRate(std::wstring data)
{
	HKEY keyHandle;
	bool result;
	if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"\\SOFTWARE\\OLEforRetail\\ServiceOPOS\\FiscalPrinter\\MbsFiscalPrinter", 0, KEY_QUERY_VALUE, &keyHandle) == ERROR_SUCCESS)
	{
		LONG nError = RegSetValueEx(keyHandle, L"COM Speed", NULL, REG_DWORD, (LPBYTE)data.c_str(), sizeof(DWORD));
		RegCloseKey(keyHandle);
		result = true;
	} else result = false;
	return result;
}
//---------------------------------------------------------------------------
int FiscalPrinter::getBaudRate()
{
	HKEY keyHandle;
	char rgValue[1024];
	char fnlRes[1024];
	DWORD size1;
	DWORD Type;

	std::string str = "-1";

	if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"\\SOFTWARE\\OLEforRetail\\ServiceOPOS\\FiscalPrinter\\MbsFiscalPrinter", 0, KEY_QUERY_VALUE, &keyHandle) == ERROR_SUCCESS)
	{
		size1 = 1023;
		RegQueryValueEx(keyHandle, L"COM Speed", NULL, &Type, (LPBYTE)rgValue, &size1);
		str = rgValue;
		RegCloseKey(keyHandle);
	}
	return Utility::StdStrToInt(str);
}
//---------------------------------------------------------------------------
bool PrinterOPOS::setCOMPort(std::wstring data)
{
	HKEY keyHandle;
	bool result;
	if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"\\SOFTWARE\\OLEforRetail\\ServiceOPOS\\FiscalPrinter\\MbsFiscalPrinter", 0, KEY_QUERY_VALUE, &keyHandle) == ERROR_SUCCESS)
	{
		LONG nError = RegSetValueEx(keyHandle, L"COM Num", NULL, REG_DWORD, (LPBYTE)data.c_str(), sizeof(DWORD));
		RegCloseKey(keyHandle);
		result = true;
	}
	else result = false;
	return result;
}
//---------------------------------------------------------------------------
void FiscalPrinter::LoadSetup()
{
	TIniFile* ini = new TIniFile();
	ini->Load("settings.ini");

	//TIniFile* ini=new TIniFile(ExtractFilePath(ParamStr(0))+"\\Setup.ini");
//	cPort->port=ini->ReadString("Printer","Port","");
//	cPort->BaudRate=ini->ReadInteger("Printer","BaudRate",0);
	CheckId=ini->ReadLong("Printer","CheckCount","0");
	TestMode=ini->ReadBool("Printer","TestMode","1");
	HeadLine=ini->ReadString(L"Printer",L"HeadLine",L"");
	GoodsName=ini->ReadString(L"Printer",L"GoodsName",L"");
	CasireName=ini->ReadString(L"Printer",L"CasireName",L"");
	AutoOpenShift=ini->ReadBool("Printer","AutoOpenShift","0");
	delete ini;
}
//---------------------------------------------------------------------------
void FiscalPrinter::SaveSetup()
{
	TIniFile* ini = new TIniFile();
	ini->Load("settings.ini");
//	ini->WriteString("Printer","Port",cPort->port); //Зачем коментил раньше:
//	ini->WriteInteger("Printer","BaudRate",cPort->BaudRate); //Зачем коментил раньше:
	ini->WriteLong("Printer","CheckCount",CheckId);
	ini->WriteBool("Printer","TestMode",TestMode);
	ini->WriteString(L"Printer",L"GoodsName",GoodsName);
	ini->WriteString(L"Printer",L"CasireName",CasireName);
	ini->WriteBool("Printer","AutoOpenShift",AutoOpenShift);
	delete ini;
}
//---------------------------------------------------------------------------
int FiscalPrinter::getGoodsPrice()
{
	int sum=0;
	for(int i=0;i<FListGoods->count();i++)
		sum+=((Goods*)FListGoods->get(i))->price;
	return sum;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
PrinterOPOS::PrinterOPOS():FiscalPrinter()
{
	Crashed=false;
	AutoOpenShift=false;
	//fp=new TOPOSFiscalPrinter(AOwner);
	fp.CreateInstance(L"OposFiscalPrinter_1_7.OPOSFiscalPrinter");
	fp->DeviceEnabled = 0; /// 0 == FALSE, -1 == TRUE
	LoadSetup();
}
//---------------------------------------------------------------------------
PrinterOPOS::~PrinterOPOS()
{
	delete FListGoods;
	delete fp;
}
//---------------------------------------------------------------------------
//Соедениться по COM порту и проинициализировать принтер
bool PrinterOPOS::Start()
{
	if(fp->DeviceEnabled) return true;

	FState = fp->Open(L"MbsFiscalPrinter");
	if(FState!=0)
	{
		Utility::logrotateW(m_LogFileWPath + std::wstring(L"\\log.txt"), Utility::IntToStdWStr(FState)+std::wstring(L"(PrinterOPOS::Start)")+GetStatusDescription(FState));
		return false;
	}
	FState = fp->ClaimDevice(1000);
	if(FState!=0)
	{
		Utility::logrotateW(m_LogFileWPath + std::wstring(L"\\log.txt"), Utility::IntToStdWStr(FState)+ std::wstring(L"(PrinterOPOS::Start)")+GetStatusDescription(FState));
		return false;
	}
	fp->DeviceEnabled = -1; // 0 == FALSE, -1 == TRUE
	return true;
}
//---------------------------------------------------------------------------
void PrinterOPOS::setHeader(TSimpleList2<std::wstring>* Text)
{
	long err=0;
	try
	{
		if(Crashed) throw std::runtime_error("Драйвер принтера разрушен!");

		for(int i=0;i<Text->count();i++)
		{
			std::wstring str=Text->get(i);
			err=fp->SetHeaderLine(i+1,str.c_str(),VARIANT_FALSE);
			if (err)
			{
				std::wstring estr = getLastError(&err);
				throw std::runtime_error(Utility::WStringToString(estr, std::locale("")));
			}
		}
		err=fp->ResetPrinter();
		if (err)
		{
			std::wstring estr = getLastError(&err);
			throw std::runtime_error(Utility::WStringToString(estr, std::locale("")));
		}
	}catch(std::exception &exception)
	{
		if(err==251) Crashed=true; //Кабздец
		Utility::logrotate(m_LogFilePath + "\\log.txt", std::string("(PrinterOPOS::setHeader)")+exception.what());
		//dModule->SendError(err,std::string("(PrinterOPOS::setHeader)")+exception);
	}catch(...)
	{
		Utility::logrotate(m_LogFilePath + "\\log.txt", std::string("(PrinterOPOS::setHeader) Нет описания ошибки"));
		//dModule->SendError(1,std::string("(PrinterOPOS::setHeader) Нет описания ошибки"));
	}
}
//---------------------------------------------------------------------------
void PrinterOPOS::getHeader(TSimpleList2<std::wstring>* Text)
{
	
	TIniFile* ini=new TIniFile();
	ini->Load("settings.ini");
	Text->add(ini->ReadString(L"Printer",L"HeadLine1",L""));
	Text->add(ini->ReadString(L"Printer",L"HeadLine2",L""));
	Text->add(ini->ReadString(L"Printer",L"HeadLine3",L""));
	Text->add(ini->ReadString(L"Printer",L"HeadLine4",L""));
	Text->add(ini->ReadString(L"Printer",L"HeadLine5",L""));
	delete ini;

	//Удаляю первые пустые строки если они есть
	for(int i=Text->count()-1;i>=0;i--)
		if(Text->get(i)==L"") Text->del(i); else break;
}
//---------------------------------------------------------------------------
void PrinterOPOS::setTrailer(TSimpleList2<std::wstring>* Text)
{
	long err=0;
	try
	{	if(Crashed) throw std::runtime_error("Драйвер принтера разрушен!");
		for(int i=0;i<Text->count();i++)
		{
			std::wstring str=Text->get(i);
			err=fp->SetTrailerLine(i+1,str.c_str(),false);
			if (err)
			{
				std::wstring estr = getLastError(&err);
				throw std::runtime_error(Utility::WStringToString(estr, std::locale("")));
			}
		}
		err=fp->ResetPrinter();
		if (err)
		{
			std::wstring estr = getLastError(&err);
			throw std::runtime_error(Utility::WStringToString(estr, std::locale("")));
		}
	}catch(std::exception &exception)
	{
		if(err==251) Crashed=true; //Кабздец
		Utility::logrotate(m_LogFilePath + "\\log.txt", std::string("(PrinterOPOS::setTrailer)")+exception.what());
		//dModule->SendError(err,std::string("(PrinterOPOS::setTrailer)")+exception);
	}catch(...)
	{
		Utility::logrotate(m_LogFilePath + "\\log.txt", std::string("(PrinterOPOS::setTrailer) Нет описания ошибки"));
		//dModule->SendError(1,std::string("(PrinterOPOS::setTrailer) Нет описания ошибки"));
	}
}
//---------------------------------------------------------------------------
void PrinterOPOS::getTrailer(TSimpleList2<std::wstring>* Text)
{
	TIniFile* ini=new TIniFile();
	ini->Load("settings.ini");
	Text->add(ini->ReadString(L"Printer",L"TailLine1",L""));
	Text->add(ini->ReadString(L"Printer",L"TailLine2",L""));
	Text->add(ini->ReadString(L"Printer",L"TailLine3",L""));
	Text->add(ini->ReadString(L"Printer",L"TailLine4",L""));
	Text->add(ini->ReadString(L"Printer",L"TailLine5",L""));
	delete ini;

	for(int i=Text->count()-1;i>=0;i--)
		if(Text->get(i)==L"") Text->del(i); else break;
}
//---------------------------------------------------------------------------
bool PrinterOPOS::PrintLine(std::wstring line)
{
	//Не фискальная печать
	long err=0;
	try
	{	if(Crashed) throw std::runtime_error("Драйвер принтера разрушен!");
		
		std::wstring str = L"";
		str += WCHAR(0x1B);
		str += WCHAR(0x7C);
		str += line;
		str += L"\n";

		BSTR bstr = SysAllocString(str.c_str());
		err = fp->PrintNormal(2, bstr);
		SysFreeString(bstr);

		if (err)
		{
			std::wstring estr = getLastError(&err);
			throw std::runtime_error(Utility::WStringToString(estr, std::locale("")));
		}
	}catch(std::exception &exception)
	{
		if(err==251) Crashed=true; //Кабздец
		Utility::logrotate(m_LogFilePath + "\\log.txt", std::string("(PrinterOPOS::PrintLine)")+exception.what());
		//dModule->SendError(err,std::string("(PrinterOPOS::PrintLine)")+exception);
	}catch(...)
	{
		Utility::logrotate(m_LogFilePath + "\\log.txt", std::string("(PrinterOPOS::PrintLine) Нет описания ошибки"));
		//dModule->SendError(1,std::string("(PrinterOPOS::PrintLine) Нет описания ошибки"));
	}
	return err==0;
}
//---------------------------------------------------------------------------
//sales - true продажа, false - возврат
//check - номер чека если не задан =0 то генериться
//TODO Фича это фиксировать не распечатанные чеки потом печатать их
bool PrinterOPOS::PrintCheck(bool sales, int check, std::wstring headLine) //Тестовая печать
{
	long err=0;
	double cur=0;
	double cAllPrice=0;
	bool bOk=true;

	try
	{	if(Crashed) throw std::runtime_error("Драйвер принтера разрушен!");

		//Считаем сумму в чеке (заранее на случай ошибки)
		cAllPrice=getGoodsPrice();

		if(check==0) //если не задан номер чека то генерим сдесь
		{
			CheckId++; //Номер чека
			check=CheckId;
			SaveSetup(); //сохраняем номер чека
		}

		if(fp->RecEmpty) throw std::runtime_error("Нет бумаги!");
		if(!DayOpened()) throw std::runtime_error("Смена не открыта");

		double UnitPrice,AllPriceDrb,AllPrice;
		long Qnt,vat;
		BSTR* bstr;
		std::wstring sStr;
		BSTR sTmp=new OLECHAR[255];
		sTmp=L"";
		long MbsResponceCode;
		CURRENCY Amount1,Amount2;

		//Установка номера отдела
		//vat=11; sTmp=L"отдел";
		//err = fp->DirectIO(4, &vat, &sTmp);
		//if (err) goto ErrHandler;

		//Желателььно сделать в нутри чека TODO!!!
		if(headLine.size()>0)
			PrintLine(headLine);


		if(sales) fp->FiscalReceiptType = FPTR_RT_SALES; //Чек продажи
		else fp->FiscalReceiptType=FPTR_RT_SERVICE; //Чек возврата

//setTrainingMode(true);

		//Фискальная печать (с заголовком или без)
		err = fp->BeginFiscalReceipt(true);
		if (err)
		{
			std::wstring estr = getLastError(&err);
			throw std::runtime_error(Utility::WStringToString(estr, std::locale(""))); //251
		}

		//Товары из списка в драйвер (TODO При печати чека не печатается услуга)
		for(int i=0;i<FListGoods->count();i++)
		{
			Goods* goods=(Goods*)FListGoods->get(i);
			VarCyFromR8(goods->price*100,&Amount1);
			Amount2.int64=0;
			std::wstring tmp=goods->name1+L"-/--/-0";
			err=fp->PrintRecItem(tmp.c_str(), Amount1, goods->count, goods->VatInfo, Amount2, L"Шт");
			if (err)
			{
				std::wstring estr = getLastError(&err);
				throw std::runtime_error(Utility::WStringToString(estr, std::locale("")));
			}
		}
		ClearGoods();

		//установка номера чека (Перед PrintRecTotal)
		err = fp->DirectIO(3, &CheckId, &sTmp);
		if (err)
		{
			std::wstring estr = getLastError(&err);
			throw std::runtime_error(Utility::WStringToString(estr, std::locale("")));
		}

		//Установка значений массива налоговых ставок
		//setNalog(1,12);

		//Формирования итога в чеке
		Amount2.int64=0;
		VarCyFromR8(cAllPrice*100,&Amount1);
		err=fp->PrintRecTotal(Amount1, Amount1, L"na");
		if (err)
		{
			std::wstring estr = getLastError(&err);
			throw std::runtime_error(Utility::WStringToString(estr, std::locale("")));
		}


		err = fp->EndFiscalReceipt(VARIANT_TRUE); //Окончания печати, в нем происходит печать дополнительного трейлера (AdditionalTrailer) и обрезка бумаги
		if (err)
		{
			std::wstring estr = getLastError(&err);
			throw std::runtime_error(Utility::WStringToString(estr, std::locale("")));
		}
	}
	catch(std::exception &exception)
	{
		ClearGoods();
		if(err==251) Crashed=true; //Кабздец
		//Utility::logrotate(m_LogFilePath + "\\log.txt", "Ошибка при печати чека: N: "+IntToStr(dModule->UserId)+" сумма: "+CurrToStr(cAllPrice)+" Чек: "+ std::string(CheckId)+". "+exception);
		//dModule->SendError(err,"Ошибка при печати чека: N: "+IntToStr(dModule->UserId)+" сумма: "+IntToStr(cAllPrice)+" Чек: "+ std::string(CheckId)+". "+exception);
		bOk=false;
	}
	catch(...)
	{
		ClearGoods();
		if(err==251) Crashed=true; //Кабздец
		//Utility::logrotate(m_LogFilePath + "\\log.txt", "Не опознанная ошибка при печати чека: N: "+IntToStr(dModule->UserId)+" сумма: "+IntToStr(cAllPrice)+" Чек: "+ std::string(CheckId));
		//dModule->SendError(1,"Не опознанная ошибка при печати чека: N: "+IntToStr(dModule->UserId)+" сумма: "+IntToStr(cAllPrice)+" Чек: "+ std::string(CheckId));
		bOk=false;
	}
	//сброс чека
	if(!bOk)
	{
		fp->PrintRecVoid(L"");
	}

	return bOk;
}
//---------------------------------------------------------------------------
bool PrinterOPOS::Cut() //Отрезать бумагу
{
	long err=0;
	try
	{
		if (Crashed)
		{
			throw std::runtime_error("Драйвер принтера разрушен!");
		}
		std::wstring wstr = L"";
		wstr += WCHAR(0x1B);
		wstr += WCHAR(0x7C);
		wstr += L"75P";
		err=fp->PrintNormal(2, wstr.c_str());
		if (err)
		{
			std::wstring estr = getLastError(&err);
			throw std::runtime_error(Utility::WStringToString(estr, std::locale("")));
		}
	}catch(std::exception &exception)
	{
		if(err==251) Crashed=true; //Кабздец
		Utility::logrotate(m_LogFilePath + "\\log.txt", std::string("(PrinterOPOS::Cut)")+exception.what());
		//dModule->SendError(err,std::string("(PrinterOPOS::Cut)")+exception);
	}catch(...)
	{
		Utility::logrotate(m_LogFilePath + "\\log.txt", std::string("(PrinterOPOS::Cut) Нет описания ошибки"));
		//dModule->SendError(1,std::string("(PrinterOPOS::Cut) Нет описания ошибки"));
	}
}
//---------------------------------------------------------------------------
//Получить текущее состояние принтера (чтоб проверить готовность печати)
/*int PrinterOPOS::GetState()
{
	if(!fp->DeviceEnabled)FState=245;
	//if(FState!=0) return FState;
	//проверяем
	//Надо добавить лог
//	fp->ResultCodeExtended
	return 0;
} */
//---------------------------------------------------------------------------
//Проверка роботоспособности принтера
bool PrinterOPOS::isOk()
{
	long err=0;
	try
	{
		if(Crashed) throw std::runtime_error("Драйвер принтера разрушен!");
		if(fp->RecEmpty) throw "Нет бумаги!";
		err=fp->ResetPrinter();
		if (err)
		{
			std::wstring estr = getLastError(&err);
			throw std::runtime_error(Utility::WStringToString(estr, std::locale(""))); //Очищает очередь с событиями
		}

		std::wstring str;

		//if(!dModule->getDayShift())throw std::runtime_error("Смена в базе не открыта!"); //Проверяем в базе открыта ли смен

		bool dOpen=DayOpened();
		if(!dOpen && AutoOpenShift && OpenShift()) dOpen=true;
		if(!dOpen) throw std::runtime_error("Смена не открыта!");

		if(DayOpened())
		{
			//Проверка на длину смены
			std::wstring dt=getDateOpenShift();
			str=getLastError(&err);
			if (err)
			{
				std::wstring estr = getLastError(&err);
				throw std::runtime_error(Utility::WStringToString(estr, std::locale("")));
			}

			//dModule->getDate();
			//if(HoursBetween(dt,dModule->date)>24) //Разница не более 24 часов
			//	throw std::runtime_error("[1]Смена не закрыта");

		} else throw std::runtime_error("Принтер не работает!");
		BSTR bstr=new OLECHAR[50];
		err=fp->GetDate(&bstr);
		if (err)
		{
			std::wstring estr = getLastError(&err);
			throw std::runtime_error(Utility::WStringToString(estr, std::locale("")));
		}
	}
	catch(std::exception &exception)
	{
		if(err==251) Crashed=true; //Кабздец
		Utility::logrotate(m_LogFilePath + "\\log.txt", std::string("(PrinterOPOS::isOk)")+exception.what());
		//dModule->SendError(err,std::string("(PrinterOPOS::isOk)")+exception);
		return false;
	}
	catch (...)
	{
		if(err==251) Crashed=true; //Кабздец
		Utility::logrotate(m_LogFilePath + "\\log.txt", std::string("(PrinterOPOS::isOk)Неопознанная ошибка"));
		//dModule->SendError(1,std::string("(PrinterOPOS::isOk)Неопознанная ошибка"));
		return false;
	}
	return true;
}
//---------------------------------------------------------------------------
//Получить дату открытия смены
std::wstring PrinterOPOS::getDateOpenShift()
{
	long err=0;
	std::wstring date=0;
	try
	{
		if(Crashed) throw std::runtime_error("Драйвер принтера разрушен!");

		long iTmp;
		BSTR sTmp=new OLECHAR[50];
		err=fp->DirectIO(13, &iTmp, &sTmp); //ММ/ДД/ГГ ЧЧ:ММ:СС
		if (err) {
			std::wstring estr = getLastError(&err);
			throw std::runtime_error(Utility::WStringToString(estr, std::locale("")));
		}
		date=sTmp; 
	}catch(std::exception &exception)
	{
		if(err==251) Crashed=true; //Кабздец
		Utility::logrotate(m_LogFilePath + "\\log.txt", std::string("(PrinterOPOS::getDateOpenShift)")+exception.what());
		//dModule->SendError(err,std::string("(PrinterOPOS::getDateOpenShift)")+exception);
	}catch(...)
	{
		Utility::logrotate(m_LogFilePath + "\\log.txt", std::string("(PrinterOPOS::getDateOpenShift) Нет описания ошибки"));
		//dModule->SendError(1,std::string("(PrinterOPOS::getDateOpenShift) Нет описания ошибки"));
	}
	return date;
}
//---------------------------------------------------------------------------
//Описание статуса
std::wstring PrinterOPOS::GetStatusDescription(long err)
{
	std::wstring str;
	try
	{
		if(err<256)
			str=kkm_err_msg_ru[err];
		if(str==L"") str=L"Нет описания ошибки";
	}catch(...)
	{
		Utility::logrotate(m_LogFilePath + "\\log.txt", std::string("(PrinterOPOS::GetStatusDescription) Нет описания ошибки"));
		return L"Нет описания ошибки";
	}
	return str;
}
//---------------------------------------------------------------------------
//Получить код последней ошибки
std::wstring PrinterOPOS::getLastError(long* err)
{
	BSTR str=new OLECHAR[255];
	str=L"Нет описания ошибки!";
	try
	{
		fp->DirectIO(1, err, &str);
	}catch(...)
	{
		Utility::logrotate(m_LogFilePath + "\\log.txt", std::string("(PrinterOPOS::getLastError) Нет описания ошибки"));
	}
	if(str==L"") return GetStatusDescription(*err);
	return std::wstring(str);
}
//---------------------------------------------------------------------------
std::wstring PrinterOPOS::getLastError()
{
	long err;
	return getLastError(&err);
}
//---------------------------------------------------------------------------
//Печать отчёта и закрытие смены
bool PrinterOPOS::PrintZReport()
{
	long err=0;
	try
	{
		if(Crashed) throw std::runtime_error("Драйвер принтера разрушен!");

		int sum=getDaySum();
		err=fp->PrintZReport();
		if (err)
		{
			std::wstring estr = getLastError(&err);
			throw std::runtime_error(Utility::WStringToString(estr, std::locale("")));
		}
		//dModule->addZReport(sum);//Послать на сервер время снятия Z отчёта
		//dModule->addPaper(-142*2);//Для подсчёта конца бумаги
	}catch(std::exception &exception)
	{
		if(err==251) Crashed=true; //Кабздец
		Utility::logrotate(m_LogFilePath + "\\log.txt", std::string("(PrinterOPOS::PrintZReport)")+exception.what());
		//dModule->SendError(err,std::string("(PrinterOPOS::PrintZReport)")+exception);
	}catch(...)
	{
		Utility::logrotate(m_LogFilePath + "\\log.txt", std::string("(PrinterOPOS::PrintZReport) Нет описания ошибки"));
		//dModule->SendError(1,std::string("(PrinterOPOS::PrintZReport) Нет описания ошибки"));
	}
	return err==0;
}
//---------------------------------------------------------------------------
//Печать суточного отчёта без закрытия смены
void PrinterOPOS::PrintXReport()
{
	long err=0;
	try
	{	if(Crashed) throw std::runtime_error("Драйвер принтера разрушен!");
		err=fp->PrintXReport();
		if (err)
		{
			std::wstring estr = getLastError(&err);
			throw std::runtime_error(Utility::WStringToString(estr, std::locale("")));
		}
	}catch(std::exception &exception)
	{
		if(err==251) Crashed=true; //Кабздец
		Utility::logrotate(m_LogFilePath + "\\log.txt", std::string("(PrinterOPOS::PrintXReport)")+exception.what());
		//dModule->SendError(err,std::string("(PrinterOPOS::PrintXReport)")+exception);
	}catch(...)
	{
		Utility::logrotate(m_LogFilePath + "\\log.txt", std::string("(PrinterOPOS::PrintXReport) Нет описания ошибки"));
		//dModule->SendError(1,std::string("(PrinterOPOS::PrintXReport) Нет описания ошибки"));
	}
}
//---------------------------------------------------------------------------
//Открытие смены
bool PrinterOPOS::OpenShift()
{
	long err;
	try
	{	if(Crashed) throw std::runtime_error("Драйвер принтера разрушен!");
		long n=1;
		//if(CasireName==NULL) CasireName=L" ";
		BSTR str= SysAllocString(CasireName.c_str());
		err=fp->DirectIO (6,&n,&str);
		SysFreeString(str);
		if (err) {
			std::wstring estr = getLastError(&err);
			throw std::runtime_error(Utility::WStringToString(estr, std::locale(""))); //Передал номер и название кассира
		}
		err=fp->SetVatValue(1,L"120");
		if (err)
		{
			std::wstring estr = getLastError(&err);
			throw std::runtime_error(Utility::WStringToString(estr, std::locale("")));
		}
	}catch(std::exception &exception)
	{
		if(err==251) Crashed=true; //Кабздец
		Utility::logrotate(m_LogFilePath + "\\log.txt", std::string("(PrinterOPOS::OpenShift)")+exception.what());
		//dModule->SendError(err,std::string("(PrinterOPOS::OpenShift)")+exception);
	}catch(...)
	{
		Utility::logrotate(m_LogFilePath + "\\log.txt", std::string("(PrinterOPOS::OpenShift) Нет описания ошибки"));
		//dModule->SendError(1,std::string("(PrinterOPOS::OpenShift) Нет описания ошибки"));
	}
	return err==0;
}
//---------------------------------------------------------------------------
bool PrinterOPOS::DayOpened()
{
	return fp->DayOpened;
}
//---------------------------------------------------------------------------
bool PrinterOPOS::setTrainingMode(bool val)
{
	long err;
	try
	{	if(Crashed) throw std::runtime_error("Драйвер принтера разрушен!");
		if(getTrainingMode()==val) return true;
		if(val) err=fp->BeginTraining(); else err=fp->EndTraining();
		if (err)
		{
			throw std::runtime_error(Utility::WStringToString(getLastError(&err), std::locale("")));
		}
	}catch(std::exception &exception)
	{
		if(err==251) Crashed=true; //Кабздец
		Utility::logrotate(m_LogFilePath + "\\log.txt", std::string("(PrinterOPOS::setTrainingMode)")+exception.what());
		//dModule->SendError(err,std::string("(PrinterOPOS::setTrainingMode)")+exception);
	}catch(...)
	{
		Utility::logrotate(m_LogFilePath + "\\log.txt", std::string("(PrinterOPOS::setTrainingMode) Нет описания ошибки"));
		//dModule->SendError(1,std::string("(PrinterOPOS::setTrainingMode) Нет описания ошибки"));
	}
	return err==0;
}
//---------------------------------------------------------------------------
bool PrinterOPOS::getTrainingMode()
{
	return fp->TrainingModeActive;
}
//---------------------------------------------------------------------------
//Заполнение массива с суммами по налоговым ставкам
bool PrinterOPOS::setNalog(long n,float stavka)
{
	long err;
	try
	{	if(Crashed) throw std::runtime_error("Драйвер принтера разрушен!");
		long s=stavka*10;
		std::wstring str= Utility::IntToStdWStr(s);
		BSTR bstr = SysAllocString(str.c_str());
		err = fp->DirectIO(2, &n, &bstr);
		SysFreeString(bstr);

		if (err) {
			std::wstring estr = getLastError(&err);
			throw std::runtime_error(Utility::WStringToString(estr, std::locale("")));
		}
	}catch(std::exception &exception)
	{
		if(err==251) Crashed=true; //Кабздец
		Utility::logrotate(m_LogFilePath + "\\log.txt", std::string("(PrinterOPOS::setNalog)")+exception.what());
		//dModule->SendError(err,std::string("(PrinterOPOS::setNalog)")+exception);
		return true;
	}catch(...)
	{
		Utility::logrotate(m_LogFilePath + "\\log.txt", std::string("(PrinterOPOS::setNalog) Нет описания ошибки"));
		//dModule->SendError(1,std::string("(PrinterOPOS::setNalog) Нет описания ошибки"));
		return true;
	}

	return err==0;
}
//---------------------------------------------------------------------------
//Дневной итог
int PrinterOPOS::getDaySum()
{
	long err;
	try
	{	if(Crashed) throw std::runtime_error("Драйвер принтера разрушен!");
		long n=1;
		BSTR str=new OLECHAR[20];
		err=fp->DirectIO (300,&n,&str);
		if (err)
		{
			std::wstring estr = getLastError(&err);
			throw std::runtime_error(Utility::WStringToString(estr, std::locale("")));
		}
		return Utility::StdWStrToInt(str)/100.0;
	}catch(std::exception &exception)
	{
		if(err==251) Crashed=true; //Кабздец
		Utility::logrotate(m_LogFilePath + "\\log.txt", std::string("(PrinterOPOS::getDaySum)")+exception.what());
		//dModule->SendError(err,std::string("(PrinterOPOS::getDaySum)")+exception);
		return 0;
	}catch(...)
	{
		Utility::logrotate(m_LogFilePath + "\\log.txt", std::string("(PrinterOPOS::getDaySum) Нет описания ошибки"));
		//dModule->SendError(1,std::string("(PrinterOPOS::getDaySum) Нет описания ошибки"));
		return 0;
	}
}
//---------------------------------------------------------------------------
//Сумма  в кассе
int PrinterOPOS::getAllSum()
{
	long err=0;
	try
	{	if(Crashed) throw std::runtime_error("Драйвер принтера разрушен!");
		long n=2;
		BSTR str=new OLECHAR[20];
		err=fp->DirectIO (300,&n,&str);
		if (err) {
			std::wstring estr = getLastError(&err);
			throw std::runtime_error(Utility::WStringToString(estr, std::locale("")));
		}
		std::wstring wstr = str;
		return Utility::StdWStrToInt(wstr)/100.0;
	}catch(std::exception &exception)
	{
		if(err==251) Crashed=true; //Кабздец
		Utility::logrotate(m_LogFilePath + "\\log.txt", std::string("(PrinterOPOS::getAllSum)")+exception.what());
		//dModule->SendError(err,std::string("(PrinterOPOS::getAllSum)")+exception);
		return 0;
	}catch(...)
	{
		Utility::logrotate(m_LogFilePath + "\\log.txt", std::string("(PrinterOPOS::getAllSum) Нет описания ошибки"));
		//dModule->SendError(1,std::string("(PrinterOPOS::getAllSum) Нет описания ошибки"));
		return 0;
	}
}

//---------------------------------------------------------------------------
//sales - true продажа, false - возврат
//check - номер чека если не задан =0 то генериться
//Фича: фиксировать не распечатанные чеки потом печатать их
bool FiscalPrinterPort::PrintCheck(bool sales, int check, std::wstring headLine )
{
	//bool err=0;
	double cur=0;
	double cAllPrice=0;
	bool bOk=true;

	try
	{
		//Считаем сумму в чеке (заранее на случай ошибки)
		cAllPrice=getGoodsPrice();

		double UnitPrice,AllPriceDrb,AllPrice;
		long Qnt,vat;
		BSTR* bstr;
		std::wstring sStr;
		BSTR sTmp=new OLECHAR[255];
		sTmp=L"";
		long MbsResponceCode;
		double Amount1,Amount2;

		//Фискальный чек продажи или возврата
		if(sales) bOk = fp->OpenFiscalInv(1,"0000",1).ErrorCode==0;
		else bOk = fp->OpenBackInv(1,"0000",1).ErrorCode==0;
		if (!bOk)
		{
			std::wstring estr = getLastError();
			throw std::runtime_error(Utility::WStringToString(estr, std::locale("")));
		}

		if(headLine.size()>0)
			PrintLine(headLine);

		//Товары из списка в драйвер
		for(int i=0;i<FListGoods->count();i++)
		{
			Goods* goods=(Goods*)FListGoods->get(i);
			bOk=fp->RegisterSale(goods->name1.c_str(),goods->name2.c_str(),0,"А",goods->price,goods->count,0,0).ErrorCode==0; //Регистрация продажи (либо возврата)
			if (!bOk)
			{
				std::wstring estr = getLastError();
				throw std::runtime_error(Utility::WStringToString(estr, std::locale("")));
			}
		}
		ClearGoods();

		//Формирования итога в чеке (оплата)
		double Change;
		bOk=fp->Total("","","P",cAllPrice,Change).ErrorCode==0;
		if (!bOk)
		{
			std::wstring estr = getLastError();
			throw std::runtime_error(Utility::WStringToString(estr, std::locale("")));
		}
		//Закрываем чек
		bOk = fp->CloseFiscalInv().ErrorCode==0;
		if (!bOk)
		{
			std::wstring estr = getLastError();
			throw std::runtime_error(Utility::WStringToString(estr, std::locale("")));
		}
	}
	catch(std::exception &exception)
	{
		ClearGoods();
		//Utility::logrotate(m_LogFilePath + "\\log.txt", "Ошибка при печати чека: N: "+IntToStr(dModule->UserId)+" сумма: "+CurrToStr(cAllPrice)+" Чек: "+ std::string(CheckId)+". "+exception);
		//dModule->SendError(bOk,"Ошибка при печати чека: N: "+IntToStr(dModule->UserId)+" сумма: "+FloatToStr(cAllPrice)+" Чек: "+ std::string(CheckId)+". "+exception);
		bOk=false;
	}
	catch(...)
	{
		ClearGoods();
		//Utility::logrotate(m_LogFilePath + "\\log.txt", "Не опознанная ошибка при печати чека: N: "+IntToStr(dModule->UserId)+" сумма: "+FloatToStr(cAllPrice)+" Чек: "+ std::string(CheckId));
		//dModule->SendError(1,"Не опознанная ошибка при печати чека: N: "+IntToStr(dModule->UserId)+" сумма: "+FloatToStr(cAllPrice)+" Чек: "+ std::string(CheckId));
		bOk=false;
	}
	//сброс чека
	if(!bOk)
	{
		fp->CancelFiscalInv();
	}
	return bOk;
}
//---------------------------------------------------------------------------
bool FiscalPrinterPort::PrintZReport()
{
	bool bOk;
	try
	{
		double Amount=0,CashSum=0,ServIn=0,ServOut=0;
		std::string Oper,Password,ExitCode="";
		std::wstring strH,strF;
		bOk=fp->ParishOrConsumption(Oper,Password,Amount,strH,strF,ExitCode,CashSum,ServIn,ServOut).ErrorCode==0;
		if (!bOk)
		{
			std::wstring estr = getLastError();
			throw std::runtime_error(Utility::WStringToString(estr, std::locale("")));
		}
		bOk=fp->PrintZReport().ErrorCode==0;
		if (!bOk)
		{
			std::wstring estr = getLastError();
			throw std::runtime_error(Utility::WStringToString(estr, std::locale("")));
		}
		//dModule->addZReport(CashSum);//Послать на сервер время снятия Z отчёта
	}
	catch(std::exception &exception)
	{
		ClearGoods();
		Utility::logrotate(m_LogFilePath + std::string("\\log.txt"), std::string("Ошибка при печати Z отчёта ")+exception.what());
		//dModule->SendError(bOk,"Ошибка при печати Z отчёта "+exception);
		bOk=false;
	}
	catch(...)
	{
		ClearGoods();
		Utility::logrotate(m_LogFilePath + std::string("\\log.txt"), std::string("Не опознанная ошибка при печати Z отчёта."));
		//dModule->SendError(1,"Не опознанная ошибка при печати Z отчёта.");
		bOk=false;
	}

	return bOk;
};
//---------------------------------------------------------------------------
bool FiscalPrinterPort::isOk()
{
	try
	{
		MyError err = fp->DiagnosticInfo();
		if (err.ErrorCode!=0)
		{
			std::wstring estr = Utility::convUTF8ToUTF16(err.ErrorMessage);
			throw std::runtime_error(Utility::WStringToString(estr, std::locale("")));
		}
		//if(!dModule->getDayShift())throw std::runtime_error("Смена в базе не открыта!"); //Проверяем в базе открыта ли смен
	}
	catch(std::exception &exception)
	{
		Utility::logrotate(m_LogFilePath + std::string("\\log.txt"), std::string("(PrinterOPOS::isOk)")+exception.what());
		//dModule->SendError(1,std::string("(PrinterOPOS::isOk)")+exception);
		return false;
	}
	catch (...)
	{
		Utility::logrotate(m_LogFilePath + std::string("\\log.txt"), std::string("(PrinterOPOS::isOk)Неопознанная ошибка"));
		//dModule->SendError(1,std::string("(PrinterOPOS::isOk)Неопознанная ошибка"));
		return false;
	}
	return true;
};
//---------------------------------------------------------------------------
