#pragma once
#pragma unmanaged
#include "..\EpdBase\EpdBase.h"
#pragma comment(lib,"dll2/Reader2.lib")
#undef EPDDLL_API
#pragma unmanaged
#include "..\EpdBase3\Epd3Base.h"
#pragma comment(lib,"dll2/Reader3.lib")
#pragma managed
using namespace System;

namespace EpdBaseClr {

	const char* cEpdError = "Setreader Error";
	ref class Epd2;

	public ref class EpdEventArgs : EventArgs
	{
	public:
		int deviceID;
		bool isIssued, isBG, isMK3;

		EpdEventArgs(int epdID, bool epdIssued, bool isBG, bool isMK3) : EventArgs()
		{

			this->deviceID = epdID;
			this->isIssued = epdIssued;
			this->isBG = isBG;
			this->isMK3 = isMK3;
		}

	};
	public ref struct EpdException : System::Exception
	{
	public:
		int errorCode;
		EpdException(int r) : System::Exception(gcnew String(cEpdError))
		{
			this->errorCode = r;
		}
	};
	public ref class EpdErrorEventArgs : EventArgs
	{
	public:
		int returnValue;
		EpdErrorEventArgs(int ReturnValue) : EventArgs()
		{
			this->returnValue = ReturnValue;
		}
	};
	public ref class EpdTOEventArgs : EventArgs
	{
	public:
		int tries;
		bool connecttimeout;
		EpdTOEventArgs(int _tries, bool _connecttimeout) : EventArgs()
		{
			this->tries=_tries;
			this->connecttimeout = _connecttimeout;
		}
	};




	/*public ref class sEpdBase
	{
	public	:
		DateTime^ RealTime;
		unsigned int CurrentDeviceID;
	};*/


	public ref class Epd2
	{
	/*private:
		DateTime^ Jan2000;*/
		const wchar_t* tHp07 = L"HP07";
		const wchar_t* tHp10 = L"HP10";
		const wchar_t* tHp07N	= L"HPN";
		const wchar_t* tHp10G	= L"HP10G";

	public:
		delegate void dEpdRead(Epd2^ Sender, EpdEventArgs^ e);
		delegate void dEpdTO(Epd2^ Sender, EpdTOEventArgs^ e);
		delegate void dEpdError(Epd2^ Sender, EpdErrorEventArgs^ e);

		dEpdRead^ _EpdRead;
		dEpdTO^ _EpdTO;
		dEpdError^ _EpdError;

		event dEpdRead^ EpdRead
		{
			void add(dEpdRead^ handler)
			{
				_EpdRead += handler;
			}

			void remove(dEpdRead^ handler)
			{
				_EpdRead -= handler;
			}
		}
		event dEpdError^ EpdError
		{
			void add(dEpdError^ handler)
			{
				_EpdError += handler;
			}

			void remove(dEpdError^ handler)
			{
				_EpdError -= handler;
			}
		}
		event dEpdTO^ EpdTO
		{
			void add(dEpdTO^ handler)
			{
				_EpdTO += handler;
			}

			void remove(dEpdTO^ handler)
			{
				_EpdTO -= handler;
			}
		}


	public: 
		EpdBase::Epd2U *epd;
		Epd3Base::Epd3U* epd3;
		
		String^ Hp07Name;
		String^ Hp10Name;
		bool isTitleNG;

		DateTime^ RealTime;
		String^ WearerName;
		String^ WearerID;
		//bool Issued; 
		bool isOn;
		bool isBG, isNG, VersionOK;
		bool isMK3;
		bool hasAlarm = false;

		int InitRV;
		int DiscRV;
		int StatusRV;
		int GetStatusError;
		int GetDosesError;
		int ReadTresholdsError;
		int PrepareForIssueError;
		int SetIssuedError;
		int ConnectError;
		int ReadDosesRV;
		int DeviceCount = 0;

		double Hp07;
		double Hp10;
		double Hp07Peak;
		double Hp10Peak;
		System::Nullable<System::DateTime> Hp10PeakTime;
		System::Nullable<System::DateTime> Hp07PeakTime;
		double Hp07Total;
		double Hp10Total;

		double alarmHP07;
		double alarmHP10;

		double Hp10THDose1;
		double Hp10THDose2;
		double Hp07THDose;

		double Hp10Rate1On;
		double Hp10Rate2On;
		double Hp07RateOn;
		double Hp10Rate1Off;
		double Hp10Rate2Off;
		double Hp07RateOff;

		double NGgain;

		int K1;
		int K2;
		int K3;
		int K4;
		int K5;
		int K6;
		int SG;
		int BC;
		int FB;
		int HG;
		int QualityData;

		unsigned int D1, D2, D3, D4, CountsClock, CountsClockBase;

		int epdType;
		int alarmStatus ;
		int otherAlarms ;
		int errorStatus ;
		int operatingStatus ;
		unsigned int EpdID ;
		int HardVersion ;
		int SoftVersion ;
		int FunctionFlags ;


		unsigned short BatADC;
		unsigned short SupplyADC;


		//OperatingStatus
		BYTE DetectorsOn = 0;
		bool EPDIssued = 0;
		BYTE EPDLocked = 0;
		BYTE EPDTesting = 0;
		BYTE EPDProcSec = 0;
		BYTE EPDFaulty = 0;


		//ERrrostatus
		BYTE EPDNewFault = 0;
		BYTE EPDComFault = 0;
		BYTE EPDCalFault = 0;
		BYTE EPDDetFault = 0;
		BYTE EPDEprFault = 0;
		BYTE EPDTrhFault = 0;
		BYTE EPDOthFault = 0;

		//AlarmStatus
		BYTE AlarmDoseHP101G = 0;
		BYTE AlarmDoseHP102G = 0;
		BYTE AlarmDoseHP07N = 0;
		BYTE AlarmRateHP101G = 0;
		BYTE AlarmRateHP102G = 0;
		BYTE AlarmRateHP07N = 0;

		//OtherAlarm
		BYTE OtherAlarmRateHp101G = 0;
		BYTE OtherAlarmRateHp102G = 0;
		BYTE OtherAlarmRateHp07N = 0;
		BYTE OtherAlarmReturn = 0;
		BYTE OtherAlarmBatLow = 0;
		BYTE OtherAlarmCarrier = 0;
		BYTE OtherAlarmBatVolt = 0;

		
		Epd2(int port);
		~Epd2();
		!Epd2();

		int SetFeedbackSound(byte sound, UINT16 sound3);

		
		private:
		int Connect(bool reinit, int EPDTimeout);
		int Close();
		int DecodeStatus(Epd3Base::Epd3U* epd);
		int DecodeStatus(EpdBase::Epd2U* epd);
		int GetStatus();
		int GetDoses();
		int GetDoses(EpdBase::Epd2U* epd);
		int AfterGetDoses(Epd3Base::Epd3U* epd);
		int GetDoses(Epd3Base::Epd3U* epd);
		int SetIssued();
		int BeforeSetIssued(Epd3Base::Epd3U* epd);
		int SetIssued(Epd3Base::Epd3U* epd);
		int BeforeSetIssued(EpdBase::Epd2U* epd);
		int SetIssued(EpdBase::Epd2U* epd);
		int PrepareForIssue();
		int WriteCalibration();
		int WriteCalibration(EpdBase::Epd2U* epd);
		int WriteCalibration(Epd3Base::Epd3U* epd);
		int ReadTresholds();
		int AfterReadTresholds(EpdBase::Epd2U* epd);
		int ReadTresholds(EpdBase::Epd2U* epd);
		int AfterReadTresholds(Epd3Base::Epd3U* epd);
		int ReadTresholds(Epd3Base::Epd3U* epd);
		int ReadExtraStatus();
		int ReadExtraStatus(EpdBase::Epd2U* epd);
		int ReadExtraStatus(Epd3Base::Epd3U* epd);
		int AfterGetDoses(EpdBase::Epd2U* epd);
		int ConnectAndStatus();
		System::Threading::CancellationTokenSource^ tokenSource;
		int tokenSourceTimeout;
		int readRetries;
		System::Threading::Tasks::Task^ waitTask;

		public:
		int SetDeIssued();
		System::Threading::Tasks::Task^ Wait(int timeout, int Retries);
		void WaitEnd();
		int GetAll(bool close);
		int GetAllDeissue();
		int IssueAndCheck(float gain);

		private:
			int AfterGetStatus(EpdBase::Epd2U* epd);
			int AfterGetStatus(Epd3Base::Epd3U* epd);
			int AfterGetStatus();
			int SwitchCon();
			void InitData();
			void WaitEpd();

	};
}
