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

#include "memory_placements.h"


#define base CECPReader

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

CRFSReader::~CRFSReader(void)
{
}

void CRFSReader::SetHWString(char *String)
{
   strcpy(String,"RFS_");
}

void CRFSReader::GetProductString(uint8_t *Product)
{
	memcpy(Product,"CJRFS",5);
}

bool CRFSReader::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 CRFSReader::_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 CRFSReader::GetReadersInputBufferSize()
{
	cj_ModuleInfo *Info;
	Info=FindModule(MODULE_ID_KERNEL);
	
  return 5130;
}

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

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

void CRFSReader::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 CRFSReader::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 CRFSReader::_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 CRFSReader::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 CRFSReader::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 CRFSReader::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 CRFSReader::HastModulestoreInfo()
{
	return true;
}

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

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

CJ_RESULT CRFSReader::CtSetMFT(const uint8_t *const pData, uint32_t DataLen, uint32_t *Result)
{
	CJ_RESULT Res;
	if ((Res = Escape(MODULE_ID_KERNEL, CCID_ESCAPE_SET_MFT, const_cast<uint8_t*>(pData), DataLen, Result, 0, 0)) != CJ_SUCCESS)
	{
		m_Owner->DebugLeveled(DEBUG_MASK_COMMUNICATION_ERROR, "Can't set MFT status!");
	}
	return Res;
}

CJ_RESULT CRFSReader::CtGetMFT(cj_MFT_Info *const pData, uint32_t *const pNumElemnts)
{
	uint32_t Result;
	uint32_t FeatureMap = 0xFFFFFFFF;
	uint32_t Mask = 1;
	uint32_t Count = 0;
	uint32_t RetLen = sizeof(FeatureMap);
	CJ_RESULT Res;

	if (*pNumElemnts < 1)
	{
		*pNumElemnts = 0;
		return CJ_ERR_RBUFFER_TO_SMALL;
	}

	if ((Res = Escape(MODULE_ID_KERNEL, CCID_ESCAPE_GET_MFT, NULL, 0, &Result, (BYTE*)&FeatureMap, &RetLen)) != CJ_SUCCESS)
	{
		m_Owner->DebugLeveled(DEBUG_MASK_COMMUNICATION_ERROR, "Can't get MFT status!");
		return Res;
	}
	FeatureMap = ReaderToHostLong(FeatureMap);
	FeatureMap = ~FeatureMap;
	for (uint32_t idx = 0; idx < 32; idx++, Mask <<= 1)
	{
		if ((FeatureMap & Mask))
		{
			if (Count < *pNumElemnts)
			{
				switch (idx)
				{
				case 0:
					pData[Count].FID = 0x00000001;
					pData[Count].Status = 1;
					strcpy((char*)pData[Count].Name, "chipTAN 1.1");
					break;

				default:
					pData[Count].FID = 0xF0000000 | idx;
					pData[Count].Status = 1;
					strcpy((char*)pData[Count].Name, "UNKONW FEATURE");
					break;
				}
				++Count;
			}
			else
			{
				*pNumElemnts = 0;
				return CJ_ERR_RBUFFER_TO_SMALL;
			}
		}
		else
		{
			switch (idx)
			{
			case 0:
				pData[Count].FID = 0x00000001;
				pData[Count].Status = 0;
				strcpy((char*)pData[Count].Name, "chipTAN 1.1");
				++Count;
				break;

			default:
				break;
			}
		}
	}
	*pNumElemnts = Count;
	return CJ_SUCCESS;
}

#ifdef WITH_SECODER_INFO_OVERRIDE
bool CRFSReader::hasReaderChipTanLicense(void)
{
	CJ_RESULT res;
	cj_MFT_Info Features[32];
	uint32_t FeatureCount = 32;

	if ((res = CtGetMFT(Features, &FeatureCount)) == CJ_SUCCESS)
	{
		for (uint32_t i = 0; i < FeatureCount; ++i)
		{
			if (Features[i].FID == 1 && Features[i].Status == 1)
			{
				return true;
			}
		}
	}
	return false;
}

CJ_RESULT CRFSReader::KTLightCall(uint8_t *sad, uint8_t *dad, uint8_t *cmd, uint16_t lenc, int32_t Lc, uint8_t *data_ptr, int32_t Le, uint8_t *response, uint16_t *lenr)
{
	static const uint8_t SECODER3_INFO_0[] = {
		"\x40\x07""Secoder"
		"\x80\x05""1.2.0"
		"\x80\x05""1.1.2"
		"\x81\x21""Reiner Kartenger\x7b""te GmbH & Co.KG."
	};
	static const uint8_t SECODER3_INFO_1[] = {
		"\x84\x02""de"
		"\x90\x01\x01"
		"\xa0\x13\x40\x03""tan\x80\x05""1.1.2\x83\x05""1.0.0"
		"\xa0\x13\x40\x03""aut\x80\x05""1.1.2\x83\x05""1.0.0"
		"\xa0\x13\x40\x03""sig\x80\x05""1.1.2\x83\x05""1.0.0"
		"\xa0\x13\x40\x03""gkp\x80\x05""1.1.2\x83\x05""1.0.0"
		"\xa0\x16\x40\x03""ctn\x80\x05""1.2.1\x83\x05""1.0.0\x84\x01\x33"
		"\x90\x00"
	};

	CJ_RESULT res;
	uint16_t InLenr = *lenr;
	uint8_t ReaderId[20 + 2];
	uint8_t SWImpVers[10 + 2];
	uint8_t ReaderPorp[9 + 2];
	int lenReaderId = 0;
	int lenSWImpVers = 0;
	int lenReaderProp = 0;
	uint8_t *Tag92 = NULL;
	uint8_t *Tag83 = NULL;
	uint8_t *Tag91 = NULL;
	uint8_t inCmd1 = *(cmd + 1);

	memset(ReaderId, 0, sizeof(ReaderId));
	memset(SWImpVers, 0, sizeof(SWImpVers));

	if ((res = base::KTLightCall(sad, dad, cmd, lenc, Lc, data_ptr, Le, response, lenr)) == CJ_SUCCESS)
	{
		if (inCmd1 == 0x70 && hasReaderChipTanLicense())
		{
			if (GetEnviroment("SecoderInfoOverride", 0x00000001) > 0)
			{
				if (GetEnviroment("SecoderInfoOverride_RFS", 0x00000001) > 0)
				{
					if (((Tag91 = GetTag(response, *lenr - 2, 0x91, &lenReaderProp)) != NULL) &&
						((Tag92 = GetTag(response, *lenr - 2, 0x92, &lenReaderId)) != NULL) &&
						((Tag83 = GetTag(response, *lenr - 2, 0x83, &lenSWImpVers)) != NULL) &&
						(lenReaderId <= 20) && (lenSWImpVers <= 10) && (lenReaderProp == 9))
					{
						lenReaderProp += 2;
						memcpy(ReaderPorp, Tag91 - 2, lenReaderProp);

						lenReaderId += 2;
						memcpy(ReaderId, Tag92 - 2, lenReaderId);

						lenSWImpVers += 2;
						memcpy(SWImpVers, Tag83 - 2, lenSWImpVers);

						if (InLenr >= (sizeof(SECODER3_INFO_0) + lenReaderProp + lenReaderId + lenSWImpVers + sizeof(SECODER3_INFO_1)))
						{
							memcpy(response, SECODER3_INFO_0, sizeof(SECODER3_INFO_0) - 1);
							memcpy(response + sizeof(SECODER3_INFO_0) - 1, ReaderPorp, lenReaderProp);
							memcpy(response + sizeof(SECODER3_INFO_0) - 1 + lenReaderProp, ReaderId, lenReaderId);
							memcpy(response + sizeof(SECODER3_INFO_0) - 1 + lenReaderProp + lenReaderId, SWImpVers, lenSWImpVers);
							memcpy(response + sizeof(SECODER3_INFO_0) - 1 + lenReaderProp + lenReaderId + lenSWImpVers, SECODER3_INFO_1, sizeof(SECODER3_INFO_1) - 1);
							*lenr = sizeof(SECODER3_INFO_0) - 1 + (USHORT)lenReaderProp + (USHORT)lenReaderId + (USHORT)lenSWImpVers + sizeof(SECODER3_INFO_1) - 1;
						}
						else
						{
							return CJ_ERR_RBUFFER_TO_SMALL;
						}
					}
				}
			}
		}
	}
	return res;
}
#endif
