#include "Platform.h"
#include <string.h>
#include <stdio.h>
#include <time.h>
#include "KPKReader.h"
#include "BaseCommunication.h"

#include "memory_placements.h"


#define base CECPReader

CKPKReader::CKPKReader(CReader *Owner,CBaseCommunication *Communicator)
			  :base(Owner,Communicator)
{
	m_b_Is_absent = true;
}

CKPKReader::~CKPKReader(void)
{
}

void CKPKReader::SetNFCSpeedLimit()
{
	uint32_t l = 1;
	uint8_t s = (uint8_t)GetEnviroment("NFCSpeedLimit", 0xff);
	Escape(MODULE_ID_KERNEL, CCID_ESCAPE_NFC_SPEED_LIMIT, &s, 1, NULL, &s, &l);// Fire and forgot
}


void CKPKReader::SetHWString(char *String)
{
	SetNFCSpeedLimit();
    strcpy(String,"KPK_");
}

void CKPKReader::GetProductString(uint8_t *Product)
{
	memcpy(Product,"CJKPK",5);
}

CJ_RESULT CKPKReader::CtSetBacklight(EBacklight eBacklight,uint32_t *Result)
{
	CJ_RESULT Res;
	switch(eBacklight)
	{
	case BacklightOff:
		Res=_CtSetBacklight(0,Result);
		break;
	case BacklightVeryLow:
		Res=_CtSetBacklight(70,Result);
		break;
	case BacklightLow:
		Res=_CtSetBacklight(100,Result);
		break;
	case BacklightMedium:
		Res=_CtSetBacklight(120,Result);
		break;
	case BacklightHigh:
		Res=_CtSetBacklight(160,Result);
		break;
	case BacklightVeryHigh:
		Res=_CtSetBacklight(255,Result);
		break;
	default:
		Res=CJ_ERR_WRONG_PARAMETER;
	}
	return Res;
}



bool CKPKReader::ATRFilter(bool IsWarm, uint8_t Slot)
{
	if (m_p_Slot[Slot].m_ATR_Length >= 5)
	{
		if (m_p_Slot[Slot].m_ATR[0] == 0x4b)
		{
			m_p_Slot[Slot].m_ATR[0] = 0x3b;
			m_p_Slot[Slot].m_bIsRF = true;
			return true;
		}
	}
	return base::ATRFilter(IsWarm, Slot);
}

RSCT_IFD_RESULT CKPKReader::_IfdPower(uint32_t Mode, uint8_t *ATR, uint32_t *ATR_Length, uint32_t Timeout, uint8_t Slot)
{
	uint32_t OrginalATR_Length = 0;
	if (ATR_Length != 0)
		OrginalATR_Length = *ATR_Length;
	m_p_Slot[Slot].m_bIsRF = false;
#ifdef D_ALWAYS_ON
	if (m_b_Is_absent == true || clock() - m_last_insertation_time <= CLOCKS_PER_SEC)
	{
		if (Mode == SCARD_COLD_RESET || Mode == SCARD_WARM_RESET)
		{
			uint32_t state;
			uint32_t merk = 0;
			clock_t start;
			int count = 0;
			start = clock();
			while (IfdGetState(&state, Slot) == STATUS_SUCCESS)
			{
				if (merk != state)
				{
					merk = state;
					start = clock();
				}
				if (clock() - start > CLOCKS_PER_SEC)
					break;
				Sleep(50);
				if (++count == 400)
					break;
			}
		}
	}
#endif
	RSCT_IFD_RESULT Result;
	if (!(Mode == SCARD_POWER_DOWN && (m_p_Slot[Slot].m_ReaderState == SCARD_SWALLOWED || m_p_Slot[Slot].m_ReaderState == SCARD_ABSENT)))
	{
		Result = base::_IfdPower(Mode, ATR, ATR_Length, Timeout, Slot);
		if ((Result == STATUS_NO_MEDIA || Result == STATUS_IO_TIMEOUT) && (Mode == SCARD_COLD_RESET || Mode == SCARD_WARM_RESET))
		{
			Sleep(100);
			Result = base::_IfdPower(Mode, ATR, ATR_Length, Timeout, Slot);
		}
	}
	else
	{
		Result = STATUS_SUCCESS;
	}

	if (Result == STATUS_SUCCESS && (Mode == SCARD_COLD_RESET || Mode == SCARD_WARM_RESET))
	{
		if (m_p_Slot[Slot].m_bIsRF)
		{
			m_p_Slot[Slot].m_PossibleProtocols =/*SCARD_PROTOCOL_T0 |*/ SCARD_PROTOCOL_T1;
			m_p_Slot[Slot].m_ActiveProtocol = SCARD_PROTOCOL_T1;
			m_p_Slot[Slot].m_ReaderState = SCARD_SPECIFIC;
		}
	}

	return Result;

}


uint32_t CKPKReader::GetReadersInputBufferSize()
{
	cj_ModuleInfo *Info;
	Info = FindModule(MODULE_ID_KERNEL);

	return 5130;
}

bool CKPKReader::PinDirectSupported()
{
	return true;
}

CJ_RESULT CKPKReader::SpecialLess3_0_41()
{
	return CJ_SUCCESS;
}

void CKPKReader::DoInterruptCallback(uint8_t * Data, uint32_t ulDataLen)
{
	base::DoInterruptCallback(Data, ulDataLen);
	if (m_b_Is_absent && ulDataLen == 2 && Data[0] == 0x50 && (Data[1] & 1) == 1)
	{
		m_b_Is_absent = false;
		m_last_insertation_time = clock();
	}
	else
	{
		m_b_Is_absent = true;
	}
}

RSCT_IFD_RESULT CKPKReader::IfdSetProtocol(uint32_t *pProtocol, uint8_t Slot)
{
	if (m_p_Slot[Slot].m_bIsRF)
	{
		uint32_t Protocol = *pProtocol;
		*pProtocol = 0;
		if (m_p_Slot[Slot].m_ReaderState == SCARD_ABSENT)
			return STATUS_NO_MEDIA;
		if (m_p_Slot[Slot].m_ReaderState == SCARD_SPECIFIC)
		{
			if (Protocol & (SCARD_PROTOCOL_DEFAULT | SCARD_PROTOCOL_OPTIMAL))
				Protocol |= (SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1 | SCARD_PROTOCOL_RAW);
			if (m_p_Slot[Slot].m_ActiveProtocol & Protocol)
			{
				*pProtocol = m_p_Slot[Slot].m_ActiveProtocol;
				return STATUS_SUCCESS;
			}
			else
				return STATUS_NOT_SUPPORTED;
		}
		else
			return STATUS_NOT_SUPPORTED;
	}
	return base::IfdSetProtocol(pProtocol, Slot);
}

RSCT_IFD_RESULT CKPKReader::_IfdTransmit(const uint8_t *cmd, uint16_t cmd_len, uint8_t *response, uint16_t *response_len, uint8_t Slot)
{
	if (cmd_len == 5 && cmd[0] == 0xff && cmd[1] == 0x9a && cmd[2] == 0x01 && cmd[4] == 0)
	{
		switch (cmd[3])
		{
		case 9:
			if (*response_len >= 8)
			{
				memcpy(response, "848500\x90\x00", 8);
				*response_len = 8;
				return STATUS_SUCCESS;
			}
			else
			{
				*response_len = 0;
				return STATUS_BUFFER_TOO_SMALL;
			}
			break;
		default:;
		}
		return CEC30Reader::_IfdTransmit(cmd, cmd_len, response, response_len, Slot);
		/*		switch(cmd[3])
		{
		case 3:
		if(*response_len>=(l=strlen("cyberJack RFID standard"))+2)
		{
		memcpy(response,"cyberJack RFID standard",l);
		memcpy(response+l,"\x90\x00",2);
		*response_len=l+2;
		return STATUS_SUCCESS;
		}
		else
		{
		*response_len=0;
		return STATUS_BUFFER_TOO_SMALL;
		}
		break;
		case 4:
		default:;
		}*/
	}

	if (m_p_Slot[Slot].m_bIsRF && cmd_len == 5 && cmd[0] == 0xff && cmd[1] == 0xca && cmd[2] == 0x01 && cmd[3] == 0)
	{
		if (*response_len >= m_p_Slot[Slot].m_ATR_Length - 3)
		{
			if (cmd[4] == 0 || cmd[4] >= m_p_Slot[Slot].m_ATR_Length - 5)
			{
				memcpy(response, m_p_Slot[Slot].m_ATR + 4, m_p_Slot[Slot].m_ATR_Length - 5);
				if (cmd[4] != 0 && cmd[4]>m_p_Slot[Slot].m_ATR_Length - 5)
				{
					memset(response + m_p_Slot[Slot].m_ATR_Length - 5, 0, cmd[4] - m_p_Slot[Slot].m_ATR_Length + 5);
					memcpy(response + cmd[4], "\x62\x82", 2);
					*response_len = cmd[4] + 2;
				}
				else
				{
					memcpy(response + m_p_Slot[Slot].m_ATR_Length - 5, "\x90\x00", 2);
					*response_len = (uint16_t)(m_p_Slot[Slot].m_ATR_Length - 3);
				}
				return STATUS_SUCCESS;
			}
		}
		if (*response_len >= 2)
		{
			response[0] = 0x6C;
			response[1] = (uint8_t)(m_p_Slot[Slot].m_ATR_Length - 5);
			*response_len = 2;
			return STATUS_SUCCESS;
		}
		return STATUS_BUFFER_TOO_SMALL;
	}
	return base::_IfdTransmit(cmd, cmd_len, response, response_len, Slot);
}

CJ_RESULT CKPKReader::CtSetContrast(EContrast eContrast, uint32_t *Result)
{
	CJ_RESULT Res;
	switch (eContrast)
	{
	case ContrastVeryLow:
		Res = _CtSetContrast(0, Result);
		break;
	case ContrastLow:
		Res = _CtSetContrast(70, Result);
		break;
	case ContrastMedium:
		Res = _CtSetContrast(120, Result);
		break;
	case ContrastHigh:
		Res = _CtSetContrast(160, Result);
		break;
	case ContrastVeryHigh:
		Res = _CtSetContrast(255, Result);
		break;
	default:
		Res = CJ_ERR_WRONG_PARAMETER;
	}
	return Res;
}

RSCT_IFD_RESULT CKPKReader::IfdVendor(uint32_t IoCtrlCode, uint8_t *Input, uint32_t InputLength, uint8_t *Output, uint32_t *OutputLength)
{
	uint32_t Result;
	uint32_t ResponseLen = *OutputLength - 6;
	uint32_t ApplicationErrorLength = 4;
	uint16_t InternalLength;
	uint16_t InternalLength2;
	uint16_t InternalLengthBuffer;
	uint8_t lengthCHAT = 0;
	uint8_t lengthPIN = 0;
	uint16_t lengthCD;
	uint8_t lengthCAR;
	uint8_t lengthCARprev;
	uint8_t buffer[2];

	switch (IoCtrlCode)
	{
	case CJPCSC_VEN_IOCTRL_EXECUTE_PACE:
		if (InputLength<3 || *OutputLength<6)
			return STATUS_INFO_LENGTH_MISMATCH;
		memcpy(&InternalLengthBuffer, Input + 1, 2);
		if (InputLength != 3u + InternalLengthBuffer)
			return STATUS_INFO_LENGTH_MISMATCH;
		InternalLength = HostToReaderShort(InternalLengthBuffer);
		if (CopyIfdInput(Input, InputLength))
			return STATUS_INSUFFICIENT_RESOURCES;
		Input = ifd_in_buffer;
		memcpy(Input + 1, &InternalLength, 2);
		if (Input[0] == 2)
		{
			buffer[0] = RDR_TO_PC_KEYEVENT;
			buffer[1] = 0xa0;
			DoInterruptCallback(buffer, 2);
			if (InputLength>4)
				lengthCHAT = Input[4];
			if (InputLength>5U + lengthCHAT)
				lengthPIN = Input[5 + lengthCHAT];
			/*			if(InputLength==7+lengthCHAT+lengthPIN)
			return STATUS_INFO_LENGTH_MISMATCH;*/
			if (InputLength>7U + lengthCHAT + lengthPIN)
			{
				memcpy(&lengthCD, Input + 7 + lengthCHAT + lengthPIN, 2);
				/*				if(InputLength!=8+lengthCHAT+lengthPIN+lengthCD)
				return STATUS_INFO_LENGTH_MISMATCH;*/
				lengthCD = HostToReaderShort(lengthCD);
				memcpy(Input + 7 + lengthCHAT + lengthPIN, &lengthCD, 2);
			}
		}

		switch (CtApplicationData(MODULE_ID_KERNEL, CCID_ESCAPE_DO_PACE, Input, InputLength, &Result, Output + 6, &ResponseLen, Output, &ApplicationErrorLength))
		{
		case CJ_SUCCESS:
			if (*OutputLength<6 + ResponseLen || ResponseLen>65535)
				return STATUS_INSUFFICIENT_RESOURCES;
			*OutputLength = 6 + ResponseLen;
			InternalLength2 = (uint16_t)ResponseLen;
			memcpy(Output + 4, &InternalLength2, 2);
			if (ApplicationErrorLength == 0)
				memset(Output, 0, 4);
			if (Input[0] == 2 && ResponseLen >= 4)
			{
				memcpy(&InternalLength, Output + 8, 2);
				InternalLength = ReaderToHostShort(InternalLength);
				memcpy(Output + 8, &InternalLength, 2);
				if (ResponseLen>6U + InternalLength)
				{
					lengthCAR = Output[10 + InternalLength];
					if (ResponseLen>7U + InternalLength + lengthCAR)
					{
						lengthCARprev = Output[11 + InternalLength + lengthCAR];
						if (lengthCARprev>0 && GetEnviroment("PACE_DisableCARprev", 0))
						{
							Output[11 + InternalLength + lengthCAR] = 0;
							memmove(Output + 12 + InternalLength + lengthCAR, Output + 12 + InternalLength + lengthCAR + lengthCARprev, ResponseLen - (6 + InternalLength + lengthCAR + lengthCARprev));
							ResponseLen -= lengthCARprev;
							*OutputLength -= lengthCARprev;
							InternalLength2 -= lengthCARprev;
							memcpy(Output + 4, &InternalLength2, 2);

							lengthCARprev = 0;
						}
						if (ResponseLen>8U + InternalLength + lengthCAR + lengthCARprev)
						{
							memcpy(&InternalLengthBuffer, Output + 12 + InternalLength + lengthCAR + lengthCARprev, 2);
							InternalLengthBuffer = ReaderToHostShort(InternalLengthBuffer);
							memcpy(Output + 12 + InternalLength + lengthCAR + lengthCARprev, &InternalLengthBuffer, 2);
						}
					}
				}
			}
			if (Input[0] == 2)
			{
				buffer[0] = RDR_TO_PC_KEYEVENT;
				buffer[1] = 0xa1;
				DoInterruptCallback(buffer, 2);
			}
			return STATUS_SUCCESS;
		default:
			if (Input[0] == 2)
			{
				buffer[0] = RDR_TO_PC_KEYEVENT;
				buffer[1] = 0xa1;
				DoInterruptCallback(buffer, 2);
				//			  return STATUS_SUCCESS;
			}
			*OutputLength = 0;
			return STATUS_UNHANDLED_EXCEPTION;
		}

	default:
		return base::IfdVendor(IoCtrlCode, Input, InputLength, Output, OutputLength);
	}
}

CJ_RESULT CKPKReader::BuildReaderInfo()
{
	CJ_RESULT Res;
	uint8_t disablesync = 0;
	uint32_t Result;

	Res = base::BuildReaderInfo();



	m_ReaderInfo.HardwareMask |= RSCT_READER_HARDWARE_MASK_RFID |
		RSCT_READER_HARDWARE_MASK_PACE;

	Escape(MODULE_ID_KERNEL, CCID_ESCAPE_CTRL_SYNC, &disablesync, sizeof(disablesync), &Result, 0, 0);
	return Res;
}

bool CKPKReader::HastModulestoreInfo()
{
	return true;
}

CJ_RESULT CKPKReader::CtSetSilentMode(bool boolMode, bool *pboolMode, uint32_t *Result)
{
	if (pboolMode)
		*pboolMode = boolMode;
	if (Result)
		*Result = 0;
	return CJ_SUCCESS;
}

CJ_RESULT CKPKReader::CtGetSilentMode(bool *pboolMode, uint32_t *Result)
{
	if (pboolMode)
		*pboolMode = 0;
	if (Result)
		*Result = 0;
	return CJ_SUCCESS;
}


