#include "AVIC_USB.h"

#define STATUS_COLOR FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY
#define HV_ON FOREGROUND_RED | FOREGROUND_INTENSITY
#define HV_OFF FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED
#define KEY_QUIT 'q'

METERAGE meterage_AVIC;
HANDLE hConsOut;
bool connected;
int offsetIndSpeed;

STRING_AVIC
DeviceStrings[] {
	{8,0, "Аппарат высоковольтный испытательный"},
	{0,16, "Статус:"},
	{0,18, "Производитель:"},
	{48,2, "ВЫСОКОЕ НАПРЯЖЕНИЕ"},
	{0,21, "'q' - выход"}
},
DisplayStrings[] {
	{1,1, "Упр.:"},
	{25,1, "Время"},
	{1,3, "Выходное напряжение"},
	{1,4, "Выходной ток"},
	{1,5, "Среднее напряжение"},
	{1,6, "Амплитуда напряжения"},
	{1,7, "Напряжение стабилизации"},
	{1,9, "Скорость изменения"},
	{4,10, "выходного напряжения"},
	{33,10, "кВ/сек"},
#define COL_KV 35
	{COL_KV,3, "кВ"},
	{COL_KV,4, "мА"},
	{COL_KV,5, "кВ"},
	{COL_KV,6, "кВ"},
	{COL_KV,7, "кВ"},
	{2,12, "Максимальное напряжение"},
	{2,13, "Максимальная сила тока"},
	{2,14, "Род тока"}
},
	msgAuto = {7,1, "авто "},
	msgHand = {7,1, "ручн."},
	msgPost = {33,14, "пост. "},
	msgPerem = {33,14, "перем."};

const char* SpeedString[] = {
	"0,01",
	"0,02",
	"0,05",
	" 0,1",
	" 0,2",
	" 0,5",
	" 1,0",
	" 2,0",
	" 5,0",
	"10,0"
};

const char* DeviceFound =			"Аппарат подключен               ";
const char* NotConnectedHVUnit =	"Не подключен высоковольтный блок";
const char* DoorOpened =			"Открыта дверь                   ";
const char* DeviceNotFound =		"Поиск аппарата                  ";
const char* DeviceAlreadyOpened =	"Подключено несколько аппаратов  ";

void PrintStringToDisplay(STRING_AVIC &strAVIC)
{
	DWORD numSymb;
	COORD position;
	char szBuffer[42];

	CharToOemA(strAVIC.text, szBuffer);
	numSymb = strlen(szBuffer);
	position = strAVIC.pos;
	SetConsoleCursorPosition(hConsOut, position);
	WriteConsoleA(hConsOut, szBuffer, numSymb, &numSymb, 0);
}

void SetHighVoltIndicator()
{
	DWORD numSymb;
	COORD position;

	if (meterage_AVIC.condition & HightVolt)
		SetConsoleTextAttribute(hConsOut, HV_ON);
	else
		SetConsoleTextAttribute(hConsOut, HV_OFF);
	position.X = DeviceStrings[3].pos.X - 4;
	position.Y = DeviceStrings[3].pos.Y;
	SetConsoleCursorPosition(hConsOut, position);
	WriteConsoleA(hConsOut, "(O)", 3, &numSymb, 0);
}

void PrintStatus(const char* statusString)
{
	DWORD numSymb;
	char szBuffer[34];

	SetConsoleTextAttribute(hConsOut, STATUS_COLOR);
	SetConsoleCursorPosition(hConsOut, {(SHORT)(DeviceStrings[1].pos.X + 8), (SHORT)DeviceStrings[1].pos.Y});
	CharToOemA(statusString, szBuffer);
	WriteConsoleA(hConsOut, szBuffer, strlen(szBuffer), &numSymb, 0);
}

void PrintMeterage()
{
	STRING_AVIC Meterage;
	char szBuffer[34], szMeterFmt[] = "%3d,%02d";

	SetConsoleTextAttribute(hConsOut, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
	//mode
	if (meterage_AVIC.condition & AutoMode)
		PrintStringToDisplay(msgAuto);
	else
		PrintStringToDisplay(msgHand);
	//indSpeedFlags
	Meterage.pos.X = 28;
	Meterage.pos.Y = 10;
	unsigned int ind = meterage_AVIC.settings & flgSpeedIndex;
	Meterage.text = SpeedString[ind + offsetIndSpeed];
	PrintStringToDisplay(Meterage);

	Meterage.text = szBuffer;
	Meterage.pos.X = 33;
	if (meterage_AVIC.settings & flgDirrectCurr)
	{
		PrintStringToDisplay(msgPost);
		Meterage.pos.Y = msgPost.pos.Y - 2;
		wsprintf(szBuffer, "%2d кВ", meterage_AVIC.limitVoltDC);
		PrintStringToDisplay(Meterage);
		wsprintf(szBuffer, "%2d мА", meterage_AVIC.limitCurrentDC);
	}
	else
	{
		PrintStringToDisplay(msgPerem);
		Meterage.pos.Y = msgPerem.pos.Y - 2;
		wsprintf(szBuffer, "%2d кВ", meterage_AVIC.limitVoltAC);
		PrintStringToDisplay(Meterage);
		wsprintf(szBuffer, "%2d мА", meterage_AVIC.limitCurrentAC);
	}
	Meterage.pos.Y++;
	PrintStringToDisplay(Meterage);

	wsprintf(szBuffer, "%2d:%02d:%02d",
		meterage_AVIC.timeHour & 0x1f,
		meterage_AVIC.timeMin & 0x3f, meterage_AVIC.timeSec & 0x3f);
	Meterage.pos.Y = 1;
	Meterage.pos.X = 31;
	PrintStringToDisplay(Meterage);

	//Filter
	//filter voltageAverage
	wsprintf(szBuffer, szMeterFmt,
			(int)meterage_AVIC.voltageAverageFlt / 100,
			(int)meterage_AVIC.voltageAverageFlt % 100);
	Meterage.pos.Y = 5;
	Meterage.pos.X = 28;
	PrintStringToDisplay(Meterage);
	szBuffer[0] = (meterage_AVIC.condition & SignVolt) ? '-' : ' ';
	szBuffer[1] = 0;
	PrintStringToDisplay(Meterage);

	//filter voltage
	wsprintf(szBuffer, szMeterFmt,
			(int)meterage_AVIC.voltageFlt / 100,
			(int)meterage_AVIC.voltageFlt % 100);
	Meterage.pos.Y = 3;
	PrintStringToDisplay(Meterage);

	//filter current
	wsprintf(szBuffer, szMeterFmt,
			(int)meterage_AVIC.currentFlt / 100,
			(int)meterage_AVIC.currentFlt % 100);
	Meterage.pos.Y = 4;
	PrintStringToDisplay(Meterage);

	//filter voltageAmplitude
	wsprintf(szBuffer, szMeterFmt,
			(int)meterage_AVIC.voltageAmplitudeFlt / 100,
			(int)meterage_AVIC.voltageAmplitudeFlt % 100);
	Meterage.pos.Y = 6;
	PrintStringToDisplay(Meterage);

	//defineVolt
	float defVolt = meterage_AVIC.defineVolt[1] + meterage_AVIC.defineVolt[0] * 256;
	wsprintf(szBuffer, szMeterFmt, (int)defVolt / 100, (int)defVolt % 100);
	Meterage.pos.Y = 7;
	PrintStringToDisplay(Meterage);

	SetHighVoltIndicator();

	COORD position;
	position.X = 0;
	position.Y = DeviceStrings[2].pos.Y + 1;
	SetConsoleCursorPosition(hConsOut, position);
}

void ClearUSBBuffer()
{
	char* data = (char*)&meterage_AVIC;
	for (unsigned int i = 0; i < sizeof(meterage_AVIC); i++)
		data[i] = 0;
	connected = false;
	PrintMeterage();
}


int main(int argc, char *argv[])
{
	DWORD numSymb, cInRecords;
	COORD position;
	char szManufacturerString[118], szBuffer[34];
	char title[] = "Аппарат высоковольтный испытательный";
	HANDLE hConsIn;
	INPUT_RECORD irBuffer;

	FreeConsole();
	AllocConsole();
	CharToOemA(title, title);
	SetConsoleTitleA(title);

	hConsOut = GetStdHandle(STD_OUTPUT_HANDLE);
	hConsIn = GetStdHandle(STD_INPUT_HANDLE);

	SetConsoleTextAttribute(hConsOut, FOREGROUND_RED | FOREGROUND_GREEN);
	for (unsigned int s = 0; s < sizeof DeviceStrings / sizeof DeviceStrings[0]; s++)
		PrintStringToDisplay(DeviceStrings[s]);
	SetConsoleTextAttribute(hConsOut, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
	for (unsigned int s = 0; s < sizeof DisplayStrings / sizeof DisplayStrings[0]; s++)
		PrintStringToDisplay(DisplayStrings[s]);

	ClearUSBBuffer();
	offsetIndSpeed = 0;

	do
	{
		if (connected)
		{
			switch (AVIC_ReadMeterage(&meterage_AVIC))
			{
			case HID_DEVICE_SUCCESS:
				PrintMeterage();
				if (meterage_AVIC.condition & DoorIsOpen)
					PrintStatus(DoorOpened);
				else
					PrintStatus(DeviceFound);
				break;

			case HID_DEVICE_HIGH_VOLTAGE_BLOCK_OUT:
				PrintStatus(NotConnectedHVUnit);
				break;

			case HID_DEVICE_NOT_FOUND:
				PrintStatus(DeviceNotFound);
				ClearUSBBuffer();
				break;
			}
		}
		else
		{
			switch (AVIC_FindDevice())
			{
			case HID_DEVICE_SUCCESS:
				PrintStatus(DeviceFound);
				if (AVIC_GetManufacturerString(szManufacturerString, sizeof(szManufacturerString)))
				{
					position.X = DeviceStrings[2].pos.X + strlen(DeviceStrings[2].text) + 1;
					position.Y = DeviceStrings[2].pos.Y;
					SetConsoleCursorPosition(hConsOut, position);
					CharToOemA(szManufacturerString, szManufacturerString);
					WriteConsoleA(hConsOut, szManufacturerString, strlen(szManufacturerString), &numSymb, 0);
				}
				if (AVIC_GetDeviceString(szBuffer, sizeof(szBuffer) + 1))
				{
					if (strcmp(szBuffer, "АВИЦ-80") == 0 || strcmp(szBuffer, "АВИЦ-70") == 0)
						offsetIndSpeed = 3;
					else
						offsetIndSpeed = 0;
					position.X = DeviceStrings[0].pos.X + strlen(DeviceStrings[0].text) + 1;
					position.Y = DeviceStrings[0].pos.Y;
					SetConsoleCursorPosition(hConsOut, position);
					CharToOemA(szBuffer, szBuffer);
					WriteConsoleA(hConsOut, szBuffer, strlen(szBuffer), &numSymb, 0);
				}
				connected = true;
				break;

			case HID_DEVICE_ALREADY_OPENED:
				PrintStatus(DeviceAlreadyOpened);
				connected = false;
				break;

			case HID_DEVICE_NOT_FOUND:
				PrintStatus(DeviceNotFound);
				connected = false;
				break;
			}
		}

		GetNumberOfConsoleInputEvents(hConsIn, &cInRecords);
		if (cInRecords)
			ReadConsoleInputA(hConsIn, &irBuffer, 1, &numSymb);
	} while (irBuffer.Event.KeyEvent.uChar.AsciiChar != KEY_QUIT);

    return 0;
}
