#include "pch.h"
#include "MK3.h"

#pragma managed

namespace MK3 {
	Epd2::Epd2(int port)
	{
		//epdBase = gcnew sEpdBase(this);
		epd = new Epd2U(port);
		Jan2000 = gcnew DateTime(2000, 1, 1);
		this->InitRV = epd->InitRv;
		epd->StartCom();
		Issued=isOn=isBG=isMK3=0;
	}

	Epd2::~Epd2()
	{
		delete epd;
		this->!Epd2();
	}

	Epd2::!Epd2()
	{
	}

	int Epd2::Connect(bool reinit)
	{
		ConnectError = 0;
		EpdID = 0;
		DeviceCount = 0;
		DiscRV = 0;
		if (epd != nullptr) {
			if (epd->CommsInitialized == 0) epd->StartCom();
			DiscRV = epd->StartDiscover();
			if (DiscRV == 1)
			{
				DeviceCount = epd->DeviceCount;
				if (epd->DeviceCount >= 0)
				{
					EpdID = epd->DeviceIDs[0];
				}
			}
			else {
				ConnectError = epd->Error;
			}
		}
		return DiscRV;
	}

	int Epd2::Close()
	{
		EpdID = 0;
		if (epd != nullptr) epd->CloseDev();
		return 0;
	}

	int Epd2::DecodeStatus()
	{
		epd->DecodeStatus();
		//OperatingStatus
		DetectorsOn = epd->DetectorsOn;
		EPDIssued = epd->EPDIssued;
		EPDLocked = epd->EPDLocked;
		EPDTesting = epd->EPDTesting;
		EPDProcSec = epd->EPDProcSec;
		EPDFaulty = epd->EPDFaulty;

		EPDNewFault = epd->EPDNewFault;
		EPDComFault = epd->EPDComFault;
		EPDCalFault = epd->EPDCalFault;
		EPDDetFault = epd->EPDDetFault;
		EPDEprFault = epd->EPDEprFault;
		EPDTrhFault = epd->EPDTrhFault;
		EPDOthFault = epd->EPDOthFault;

		AlarmDoseHP101G = epd->AlarmDoseHP101G;
		AlarmDoseHP102G = epd->AlarmDoseHP102G;
		AlarmDoseHP07N = epd->AlarmDoseHP07N;
		AlarmRateHP101G = epd->AlarmRateHP101G;
		AlarmRateHP102G = epd->AlarmRateHP102G;
		AlarmRateHP07N = epd->AlarmRateHP07N;

		OtherAlarmRateHp101G = epd->OtherAlarmRateHp101G;
		OtherAlarmRateHp102G = epd->OtherAlarmRateHp102G;
		OtherAlarmRateHp07N = epd->OtherAlarmRateHp07N;
		OtherAlarmReturn = epd->OtherAlarmReturn;
		OtherAlarmBatLow = epd->OtherAlarmBatLow;
		OtherAlarmCarrier = epd->OtherAlarmCarrier;
		OtherAlarmBatVolt = epd->OtherAlarmBatVolt;

		return 1;
	}

	int Epd2::SetTime() {
		epd->SetTime();
		return epd->utc;
	}

	int Epd2::ReadAlarmConfig() {
		epd->ReadAlarmConfig();
		return epd->numAlarm;
	}

	int Epd2::ReadAlarmTresholds() {
		epd->ReadAlarmTresholds();
		return 0;
	}


	int Epd2::GetStatus()
	{
		GetStatusError = 0;  StatusRV = 0; Issued = false;
		WearerID = String::Empty;
		WearerName = String::Empty;
		StatusRV = epd->ReadStatus();
		if (StatusRV != 0) 
			GetStatusError = epd->Error;

		Issued = epd->EPDIssued;
		
		WearerID = gcnew String((char*)epd->WearerID);
		WearerName = gcnew String((char*)epd->WearerName);
		isOn = (epd->DetectorsOn != 0);
		epdType = (int)epd->EpdType;
		isBG = (epd->EpdType == EpdTypes::Mk2BetaGamma || epd->EpdType == EpdTypes::Mk3BetaGamma);
		
		alarmStatus = epd->AlarmStatus;
		otherAlarms = epd->OtherAlarms;
		errorStatus = epd->ErrorStatus;
		operatingStatus = epd->OperatingStatus;

		EpdID = epd->EpdID;
		HardVersion = epd->HardVersion;
		SoftVersion = epd->SoftVersion;
		FunctionFlags = epd->FunctionFlags;
		CountsClock = epd->EpdClock;
		DecodeStatus();
		return StatusRV;
	}

	int Epd2::GetDoses()
	{
		Hp10 = Hp07 = 0.0;
		int ReadDosesRV = epd->ReadDoses();

		if (ReadDosesRV == 1) {
			GetDosesError = 0;
			Hp10 = (double)epd->Hp10Dose;
			Hp07 = (double)epd->Hp07Dose;
			Hp07Peak = (double)epd->Hp07Peak;
			Hp10Peak = (double)epd->Hp10Peak;

			Hp07Total = epd->Hp07Total;
			Hp10Total = epd->Hp10Total;
		}
		else {
			GetDosesError = epd->Error;
		}

		if (epd->Hp10Time > 0) {
			//seconds since 2000 ?
			//double x = (epd->EpdClock - epd->Hp10Time) * -1.0;
			Hp10PeakTime = Jan2000->AddSeconds(epd->Hp10Time);
		}
		else
			Hp10PeakTime = System::Nullable<System::DateTime>();;
		if (epd->Hp07Time > 0) {
			//double x = (epd->EpdClock - epd->Hp07Time) * -1.0;
			Hp07PeakTime = Jan2000->AddSeconds(epd->Hp07Time);
		}
		else
			Hp07PeakTime = System::Nullable<System::DateTime>();

		QualityData = epd->QualityData;
		K1 = epd->K1;
		K2 = epd->K2;
		K3 = epd->K3;
		K4 = epd->K4;
		K5 = epd->K5;
		K6 = epd->K6;
		SG = epd->SG;
		BC = epd->SG;
		FB = epd->FB;
		HG = epd->HG;

		return ReadDosesRV;
	}

	int Epd2::SetDeIssued()
	{
		return epd->DeIssue();
	}

	int Epd2::PrepareForIssue()
	{
		PrepareForIssueError = 0;
		int rv = epd->PrepareForIssue();
		if (rv != 1) PrepareForIssueError = epd->Error;
		return rv;
	}

	int Epd2::SetIssued()
	{
		SetIssuedError = 0;
		epd->Hp07THDose = (float)Hp07THDose;
		epd->Hp10THDose1 = (float)Hp10THDose1;
		epd->Hp10THDose2 = (float)Hp10THDose2;

		epd->Hp10Rate1On = (float)(Hp10Rate1On);
		epd->Hp10Rate2On = (float)(Hp10Rate2On);
		epd->Hp07RateOn = (float)(Hp07RateOn);

		epd->Hp10Rate1Off = (float)(Hp10Rate1Off);
		epd->Hp10Rate2Off = (float)(Hp10Rate2Off);
		epd->Hp07RateOff = (float)(Hp07RateOff);

		epd->K3 = K3;
		epd->K4 = K4;

		memset(epd->WearerID, ' ', WearerIDLength); epd->WearerID[WearerIDLength] = 0;
		char* str1 = (char*)(void*)Runtime::InteropServices::Marshal::StringToHGlobalAnsi(WearerID);
		int l = strlen(str1);
		if (l > WearerIDLength) l = WearerIDLength;
		_memccpy(epd->WearerID + WearerIDLength - l, str1, l, WearerIDLength - l);
		Runtime::InteropServices::Marshal::FreeHGlobal((IntPtr)str1);

		memset(epd->WearerName, 0, WearerNameLength + 1);
		char* str2 = (char*)(void*)Runtime::InteropServices::Marshal::StringToHGlobalAnsi(WearerName);
		l = strlen(str2);
		if (l > WearerNameLength) l = WearerNameLength;
		_memccpy(epd->WearerName, str2, l, WearerNameLength);
		Runtime::InteropServices::Marshal::FreeHGlobal((IntPtr)str2);

		int rv = epd->Issue();
		if (rv != 0)
			SetIssuedError = epd->Error;
		return rv;
	}

	int Epd2::WriteCalibration()
	{
		epd->K1 = K1;
		epd->K2 = K2;

		epd->K3 = K3;
		epd->K4 = K4;

		epd->K5 = K5;
		epd->K6 = K6;

		//epd->K1 = 903;
		//epd->K2 = 613;
		//epd->K5 = 13100;
		//epd->K6 = 1310;

		int rv = epd->WriteCal();
		return rv;

	}

	int Epd2::ReadTresholds()
	{
		ReadTresholdsError = 0;
		int rv = epd->ReadAlarmTresholds();
		if (rv != 0) ReadTresholdsError = epd->Error;

		Hp10THDose1 = (double)epd->Hp10THDose1 / 64.0;
		Hp10THDose2 = (double)epd->Hp10THDose2 / 64.0;
		Hp07THDose = (double)epd->Hp07THDose / 64.0;

		Hp10Total = (double)epd->Hp10Total / 64.0;
		Hp07Total = (double)epd->Hp07Total / 64.0;

		Hp10Rate1On = (double)epd->Hp10Rate1On;
		Hp10Rate2On = (double)epd->Hp10Rate2On;
		Hp07RateOn = (double)epd->Hp07RateOn;
		Hp10Rate1Off = (double)epd->Hp10Rate1Off;
		Hp10Rate2Off = (double)epd->Hp10Rate2Off;
		Hp07RateOff = (double)epd->Hp07RateOff;

		K1 = epd->K1;
		K2 = epd->K2;
		K3 = epd->K3;
		K4 = epd->K4;
		K5 = epd->K5;
		K6 = epd->K6;
		SG = epd->SG;
		BC = epd->BC;
		FB = epd->FB;
		HG = epd->HG;
		return rv;
	}

	int Epd2::ReadExtraStatus()
	{
		int rv = epd->EPDReadExtraStatus();
		BatADC = epd->byBatADC;
		SupplyADC = epd->bySupplyADC;

		D1 = epd->D1;
		D2 = epd->D2;
		D3 = epd->D3;
		D4 = epd->D4;
		CountsClock = epd->CountsClock;
		CountsClockBase = epd->BaseCountsClock;
		return rv;
	}

	int Epd2::ConnectAndStatus() 
	{
		int rv = Connect(false);
		if (rv == 0) 
		{
			EpdID= epd->Epd.Id;
			isMK3 = (epd->EpdGen == EpdGeneration::Mk3);
			rv = GetStatus();
		}
		return rv;
	}

	void Epd2::WaitEpd()
	{
		int rv = 0; //start
		System::Threading::CancellationToken^ token = tokenSource->Token;
		
		do {
			rv = ConnectAndStatus();
		} while (rv != 0 && --readRetries > 0 && !token->IsCancellationRequested);

		//if (token->IsCancellationRequested) lastStatusRV = 7;
		if (rv == 0) {
			if (_EpdRead != nullptr)
				_EpdRead(this, gcnew EpdEventArgs(EpdID,Issued,isBG,isMK3));
		} else if (rv > 0 && _EpdError != nullptr) {
			_EpdError(this, gcnew EpdErrorEventArgs(rv));
		}
		return ;
	}

	System::Threading::Tasks::Task^ Epd2::Wait(int timeout, int Retries)
	{
		if (waitTask == nullptr)
		{
			tokenSourceTimeout = timeout;
			tokenSource = gcnew System::Threading::CancellationTokenSource(tokenSourceTimeout - 1000);
			readRetries = Retries;
			waitTask = System::Threading::Tasks::Task::Run(gcnew Action(this, &Epd2::WaitEpd)); // System::Threading::Tasks::Task::Factory->cre(gcnew Action(this, &CCard::WaitBadge), tokenSource->Token);
		}
		else {
			readRetries = Retries + 1;
		}
		return waitTask;
	}
	void Epd2::WaitEnd()
	{
		if (waitTask != nullptr)
		{
			tokenSource->Cancel();
			//cbCard->Cancel();
			Sleep(500);
			delete waitTask; waitTask = nullptr;
			delete tokenSource; tokenSource = nullptr;
		}
	}
}