/*
 * BluePad.h
 *
 *  Created on: 19 января 2022 г.
 *      Author: Igor
 */

#ifndef BLUEPAD_H_
#define BLUEPAD_H_

#include "ComPort.h"
#include "SocketPort.h"
#include "DataToSend.h"
#include "Sockets.h"

#define HAVE_STRUCT_TIMESPEC
#include <thread>
#include <mutex>

#define fcDisplayClear 0x21 //(33)Очистка дисплея

//Свои коды ошибок
#define ERRCRC 100000 // RCR Error
#define ERRIO 100001 // ERR_IO
#define ERRSOCK 100002 // Ошибка закрытия сокета
#define ERRSOCKSND 100003 // Ошибка закрытия сокета
#define ERRTIMEOUT 100004 // Ошибка закрытия сокета

//#define ERRActivation 100050 //Ошибка изза не активации программы
//#define ERRDiscounts 100051 //Ошибка если прентер не поддерживает скидки

//---------------------------------------------------------------------------
//Виды транзакций
#define BOR_CMD_TRANS_TYPE_PURCH 0x01 //1 Оплата
#define BOR_CMD_TRANS_TYPE_PURCH_CASH 0x02 
#define BOR_CMD_TRANS_TYPE_PURCH_REF 0x03 
#define BOR_CMD_TRANS_TYPE_CASH 0x04 
#define BOR_CMD_TRANS_TYPE_AUTH 0x05 
#define BOR_CMD_TRANS_TYPE_PURCH_CODE 0x06 
#define BOR_CMD_TRANS_TYPE_VOID_PURCH 0x07 
#define BOR_CMD_TRANS_TYPE_VOID_CASH 0x08 
#define BOR_CMD_TRANS_TYPE_VOID_AUTH 0x09 
#define BOR_CMD_TRANS_TYPE_END_OF_DAY 10 
#define BOR_CMD_TRANS_TYPE_LOYALTY_BALANCE 11 
#define BOR_CMD_TRANS_TYPE_LOYALTY_SPEND 0x12 
#define BOR_CMD_TRANS_TYPE_VOID_LOYALTY_SPEND 13 
#define BOR_CMD_TRANS_TYPE_TEST_CONN 0x0E //14 Проверить соединение с сервером
#define BOR_CMD_TRANS_TYPE_TMS_UPDATE 15 

#define BOR_CMD_TRANS_TYPE_PURCH_RET 0x16 //22 Возвратить продажу
//---------------------------------------------------------------------------
#define BOR_CMD_TAG_AMOUNT		0x81 //- [HEX BIG ENDIAN - 4 bytes]
#define BOR_CMD_TAG_CASHBACK	0x9F04 // - [HEX BIG ENDIAN - 4 bytes]
#define BOR_CMD_TAG_RRN			0xDF01 // - [STRING]
#define BOR_CMD_TAG_AUTH_ID		0xDF02 // - [STRING]
#define BOR_CMD_TAG_REF			0xDF03 // ~not used
#define BOR_CMD_TAG_DF04_AMOUNT_EUR 0xDF04 //[HEX] 
#define BOR_CMD_TAG_TIP			0xDF63 // - [HEX BIG ENDIAN - 4 bytes]

#define BOR_CMD_TAG_RN			0xDF13 // - [STRING]
//---------------------------------------------------------------------------
#define PAY_CL_UI_NOT_WORKING			0x0000 //– Не працює
#define PAY_CL_UI_APPROVED				0x0003 //- Затверджено
#define PAY_CL_UI_DECLINED				0x0007 //- Відхилено
#define PAY_CL_UI_ENTER_PIN				0x0009 //– Введіть PIN
#define PAY_CL_UI_ERROR_PROCESSING		0x000F //– Обробка помилки
#define PAY_CL_UI_REMOVE_CARD			0x0010 //– Заберіть картку
#define PAY_CL_UI_IDLE					0x0014 //- Бездіяльний
#define PAY_CL_UI_PRESENT_CARD			0x0015 //– ППрикладть картку
#define PAY_CL_UI_PROCESSING			0x0016 //- Обробка
#define PAY_CL_UI_CARD_READ_OK_REMOVE	0x0017 //- Зчитування картки видалено
#define PAY_CL_UI_TRY_OTHER_INTERFACE	0x0018 //– Спробуйте інший інтерфейс
#define PAY_CL_UI_CARD_COLLISION		0x0019 //- Зіткнення карт
#define PAY_CL_UI_SIGN_APPROVED			0x001A //– Підпис підтверджено
#define PAY_CL_UI_ONLINE_AUTHORISATION	0x001B //– Онлайн авторизація
#define PAY_CL_UI_TRY_OTHER_CARD		0x001C //- Спробуйте іншу картку
#define PAY_CL_UI_INSERT_CARD			0x001D //– Вставте картку
#define PAY_CL_UI_CLEAR_DISPLAY			0x001E //– Очистити дисплей
#define PAY_CL_UI_SEE_PHONE				0x0020 //– Подивитися на телефон
#define PAY_CL_UI_PRESENT_CARD_AGAIN	0x0021 //– Прикладіть картку ще раз
#define PAY_CL_UI_CARD_ERROR			0x0022 //– Помилка карти
#define PAY_CL_UI_CARD_BLOCKED			0x0081 //– Картку заблоковано
#define PAY_CL_UI_CARD_NUMBER			0x0082 //– Номер картки
#define PAY_CL_UI_INVALID_NUMBER		0x0083 //- Недійсний номер
#define PAY_CL_UI_EXPIRATION_DATE		0x0084 //- Термін придатності
#define PAY_CL_UI_ENTER_CVV				0x0085 //– Введіть cvv
#define PAY_CL_UI_MANUAL_BUTTON			0x0086 //- Ручне введення
#define PAY_CL_UI_MAGNETIC_BUTTON		0x0087 //– Магнітна кнопка
#define PAY_CL_UI_SWIPE_MAGNETIC_CARD	0x0088 //– Магнітна картка
#define EMV_UI_TRY_AGAIN				0x0013 //– Спробуйте ще раз
//---------------------------------------------------------------------------
#define TAGSLEN 100
//---------------------------------------------------------------------------
class Sockets;
//---------------------------------------------------------------------------
struct MyError
{
	int ErrorCode;
	std::string ErrorMessage;
};
//---------------------------------------------------------------------------
class Tags {
public:
	int tag;
	std::string data;
	Tags() {
		tag = 0;
		data = "";
	}
};
//---------------------------------------------------------------------------
class BluePad
{
private:
	int m_cnt; //Для наблюдения за тем сколько пакетов было прочитанно в потоке
	int m_length; //Каким количеством данных заполнен массив
	char m_ans[65535]; //Буфер для приёма ответа в поток	

	//Нижэ всё для отдельных потоков
	
	DataToSend* m_sendData; //FIFO буффер для потока отправки данных
	std::mutex m_mutex; // Для защиты связанного списка "m_sendData"

	bool m_execute_thread_read = false; //По умолчанию потоки отправки и приёма не работают
	std::thread* m_threadid_read;
	static void thread_func_read(void *d); //Для чтения из порта

	bool m_execute_thread_write = false; //По умолчанию потоки отправки и приёма не работают
	std::thread* m_threadid_write;
	static void thread_func_write(void *d); //Для записи в порт

	Tags tags[TAGSLEN]; //для хранения последних тегов
	int m_tagsInCnt; //Сколько раз прочитали все теги
public:
	Sockets* sockets;
	
	bool existsData(int id); //Проверяем не отправились ли данные в пинпад
	bool addData(DataToSend* data); //Добавляем данные в конец списка на отправку


	Port* csPort;
	bool m_open; //Открыт и настроен ли порт или сокет

	bool m_SaveLog; ///<Сохранять ли в лог файл
	std::string m_LogFilePath; ///<Куда сохранять лог файл
	int TimeOut;
	int m_LastErrorCode; ///<Код ошибки 0 без ошибок
	std::string m_LastErrorDescription; ///<Описание последней ошибки
	std::string PrinterNumber;

	BluePad(std::string path);
	virtual ~BluePad();

	void ReadingError(int Code, std::string& ErrorMessage);
	MyError OpenSerialPort(std::string ComNumber, int BaudRate);
	MyError CloseSerialPort();
	//int SendPMessage(char* answer);
	MyError Ping();
	MyError getInfo(std::string& model, std::string& serial, std::string& ver, std::string& id, int* menu);
	MyError getRTC(std::string& date);
	MyError getStatus(std::string& reversal, std::string& endday);
	MyError setEventStatus(bool val);
	bool getLastTag(int id, std::string& tag);
	bool waitTags(int timeout); //Подождать появления новых тегов
	MyError getReportTags(int type,std::string tags, std::string& tag); //Прочитать из пинпада 04: GET REPORT TAGS 

	//MyError setData(char* data, int length); //Отправить долученные данные через интернет на пинпад
	MyError getMaxLenData(int* length); //Запросить сколько байт можно передать в пинпад за 1 пакет
	MyError SocketOpen();  // Открываю сокет в отдельном потоке для коммуникации с сервером
	MyError SocketClose(); // Закрыть сокет по ID
	MyError SocketSend();  // Отправить данные полученные от пинпада на сокет

	//Функции для транзакции
	MyError startPurchase(double amount,int timeout); //Начало транзакции для оплаты
	MyError voidPurchase(double amount,std::string RRN); //Отменить оплату
	MyError startRetPurchase(double amount, std::string RRN); //Вернуть оплату

	MyError startAuthorization(double amount); //Начало авторизации оплаты
	MyError voidAuthorization(double amount, std::string RRN, std::string auth); //Отменить авторизацию //09 - VOID OF AUTHORIZATION
	MyError confirmAuthorization(double amount, std::string RRN, std::string auth);
	MyError cancelCheck(double amount, unsigned int num); // Отменить оплату по чеку в рамках одного дня
	MyError testConnection(); //Начало транзакции для проверки соединения
	MyError transactionEnd(char val);
	MyError endOfDay(); //Завершить день (Z - отчёт)



	MyError getStatus(unsigned short& status); //Прочитать статус терминала
	void ReadingStatus(int Status, std::string& Message); //Получить описание статуса

	void parseEMVTLV(unsigned char* data, int length);
	int readTag(unsigned char* data, int length, int& tag, std::string& tagData);
};
//---------------------------------------------------------------------------
#endif
