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

#include "memory_placements.h"


#define base CWAVReader

CWICReader::CWICReader(CReader *Owner, CBaseCommunication *Communicator)
	:base(Owner, Communicator)
{
	m_maxSlot = 2;
}

CWICReader::~CWICReader(void)
{
}

static cj_ModuleInfo helpModule;

cj_ModuleInfo *CWICReader::FindModule(uint32_t ModuleID)
{
	if (ModuleID == MODULE_ID_KT_LIGHT || ModuleID == MODULE_ID_MKT_COMP)
	{
		memset(&helpModule, 0, sizeof(helpModule));
		return &helpModule;
	}
	return CBaseReader::FindModule(ModuleID);
}

cj_ModuleInfo *CWICReader::FindModuleWithMask(uint32_t ModuleID, uint32_t Mask)
{
	if (ModuleID == MODULE_ID_KT_LIGHT || ModuleID == MODULE_ID_MKT_COMP)
	{
		memset(&helpModule, 0, sizeof(helpModule));
		return &helpModule;
	}
	return CBaseReader::FindModuleWithMask(ModuleID, Mask);
}

bool CWICReader::HasDiversifier()
{
	return true;
}

int CWICReader::cjccid_SecureMV(uint8_t Timeout,
	uint8_t PinPosition, uint8_t PinType,
	uint8_t PinLengthSize, uint8_t PinLength,
	uint8_t PinLengthPosition,
	uint8_t Min, uint8_t Max,
	uint8_t bConfirmPIN,
	uint8_t Condition, uint8_t *Prologue,
	uint8_t OffsetOld, uint8_t OffsetNew,
	uint8_t *out, int out_len, uint8_t *in, int *in_len, int TextCount, uint8_t *Text[3], uint8_t Textlen[3], uint8_t bMessageIndex[3], uint8_t bNumberMessage, uint8_t *pDiversifier, uint8_t Slot)
{
	if (Max > 15)
		Max = 15;
	if (pDiversifier == NULL)
	{
		return CEC30Reader::cjccid_SecureMV(Timeout, PinPosition, PinType, PinLengthSize, PinLength,
			PinLengthPosition, Min, Max, bConfirmPIN, Condition, Prologue, OffsetOld, OffsetNew,
			out, out_len, in, in_len, TextCount, Text, Textlen, bMessageIndex, bNumberMessage, pDiversifier, Slot);
	}
	else
	{
		uint32_t Result;
		uint8_t RespData[1000];
		uint8_t buffer[1000];
		uint32_t RespDataLen = sizeof(RespData);
		uint8_t *ptr;
		struct _CCID_Message::_Data::_Secure *Secure;
		uint8_t Error;
		uint32_t ErrorLength = sizeof(Error);
		int i;
		int Res;
		uint32_t len = 0;

		for (i = 0, ptr = buffer; i < TextCount; i++)
		{
			*ptr++ = Textlen[i];
			memcpy(ptr, Text[i], Textlen[i]);
			ptr += Textlen[i];
			len += Textlen[i];
		}
		for (; i < 3; i++)
		{
			*ptr++ = 0;
		}

		if (pDiversifier == NULL)
		{
			*ptr++ = 0;
		}
		else
		{
			*ptr++ = 4;
			memcpy(ptr, pDiversifier, 4);
			ptr += 4;
		}



		Secure = (struct _CCID_Message::_Data::_Secure *)ptr;


		Secure->bPINOperation = 1;
		Secure->bTimeOut = Timeout;
		Secure->bmFormatString = (uint8_t)(0x80 | (PinPosition << 3) | PinType);
		Secure->bmPINBlockString = (uint8_t)((PinLengthSize << 4) | PinLength);
		Secure->bmPINLengthFormat = PinLengthPosition;
		Secure->Data.Modify.bInsertionOffsetOld = OffsetOld;
		Secure->Data.Modify.bInsertionOffsetNew = OffsetNew;
		Secure->Data.Modify.wPINMaxExtraDigit = HostToReaderShort((((uint16_t)Min) << 8) + Max);
		Secure->Data.Modify.bConfirmPIN = bConfirmPIN;
		Secure->Data.Modify.bEntryValidationCondition = Condition;
		Secure->Data.Modify.bNumberMessage = bNumberMessage;
		Secure->Data.Modify.wLangId = HostToReaderShort(0x0409);
		Secure->Data.Modify.bMsgIndex1 = bMessageIndex[0];
		Secure->Data.Modify.bMsgIndex2 = bMessageIndex[1];
		Secure->Data.Modify.bMsgIndex3 = bMessageIndex[2];
		memcpy(Secure->Data.Modify.bTeoPrologue, Prologue, 3);
		memcpy(Secure->Data.Modify.abData, out, out_len);
#ifdef _INSERT_KEY_EVENTS
		{
			uint8_t bufferx[2];
			bufferx[0] = RDR_TO_PC_KEYEVENT;
			bufferx[1] = 0xa0;
			DoInterruptCallback(bufferx, 2);
		}
#endif
		Res = CtApplicationData(MODULE_ID_MKT_COMP, 2, buffer, 20 + out_len + len + 8, &Result, RespData, &RespDataLen, &Error, &ErrorLength, Slot);

#ifdef _INSERT_KEY_EVENTS
		if (Res == CJ_SUCCESS)
		{
			if (m_p_Slot[Slot].m_ReaderState == SCARD_SPECIFIC)
			{
				uint8_t bufferx[2];
				bufferx[0] = RDR_TO_PC_KEYEVENT;
				if (ErrorLength == 1 && Error == PIN_CANCELED)
					bufferx[1] = 0x01;
				else
					bufferx[1] = 0x02;
				DoInterruptCallback(buffer, 2);
			}
		}
		{
			uint8_t bufferx[2];
			bufferx[0] = RDR_TO_PC_KEYEVENT;
			bufferx[1] = 0xa1;
			DoInterruptCallback(bufferx, 2);
		}
#endif
		if (Res != 0)
			return Res;
		return ExecuteApplSecureResult(Error, ErrorLength, in, in_len, RespData, RespDataLen, 5, Slot);
	}
}

int CWICReader::cjccid_SecurePV(uint8_t Timeout,
	uint8_t PinPosition, uint8_t PinType,
	uint8_t PinLengthSize, uint8_t PinLength,
	uint8_t PinLengthPosition,
	uint8_t Min, uint8_t Max,
	uint8_t Condition, uint8_t *Prologue,
	uint8_t *out, int out_len, uint8_t *in, int *in_len, uint8_t *Text, uint8_t Textlen, uint8_t bMessageIndex, uint8_t bNumberMessage, uint8_t Slot)
{
	if (Max > 15)
		Max = 15;
	if (Text == NULL || Textlen == 0 || FindModule(MODULE_ID_MKT_COMP) == NULL)
		return base::cjccid_SecurePV(Timeout,
			PinPosition, PinType,
			PinLengthSize, PinLength,
			PinLengthPosition,
			Min, Max,
			Condition, Prologue,
			out, out_len, in, in_len, Text, Textlen, bMessageIndex, bNumberMessage, Slot);
	else
	{
		uint32_t Result;
		uint8_t RespData[1000];
		uint8_t buffer[1000];
		uint32_t RespDataLen = sizeof(RespData);
		struct _CCID_Message::_Data::_Secure *Secure;
		uint8_t Error;
		uint32_t ErrorLength = sizeof(Error);
		int Res;

		buffer[0] = Textlen;
		memcpy(buffer + 1, Text, Textlen);
		buffer[1 + Textlen] = buffer[2 + Textlen] = 0;
		Secure = (struct _CCID_Message::_Data::_Secure *)(buffer + Textlen + 3);

		Secure->bPINOperation = 0;
		Secure->bTimeOut = Timeout;
		Secure->bmFormatString = (uint8_t)(0x80 | (PinPosition << 3) | PinType);
		Secure->bmPINBlockString = (uint8_t)((PinLengthSize << 4) | PinLength);
		Secure->bmPINLengthFormat = PinLengthPosition;
		Secure->Data.Verify.wPINMaxExtraDigit = HostToReaderShort((((uint16_t)Min) << 8) + Max);
		Secure->Data.Verify.bEntryValidationCondition = Condition;
		Secure->Data.Verify.bNumberMessage = bNumberMessage;
		Secure->Data.Verify.wLangId = HostToReaderShort(0x0409);
		Secure->Data.Verify.bMsgIndex = bMessageIndex;
		memcpy(Secure->Data.Verify.bTeoPrologue, Prologue, 3);
		memcpy(Secure->Data.Verify.abData, out, out_len);
#ifdef _INSERT_KEY_EVENTS
		{
			uint8_t bufferx[2];
			bufferx[0] = RDR_TO_PC_KEYEVENT;
			bufferx[1] = 0xa0;
			DoInterruptCallback(bufferx, 2);
		}
#endif
		Res = CtApplicationData(MODULE_ID_MKT_COMP, 2, buffer, 15 + out_len + Textlen + 3, &Result, RespData, &RespDataLen, &Error, &ErrorLength, Slot);
#ifdef _INSERT_KEY_EVENTS
		if (Res == CJ_SUCCESS)
		{
			if (m_p_Slot[Slot].m_ReaderState == SCARD_SPECIFIC)
			{
				uint8_t bufferx[2];
				bufferx[0] = RDR_TO_PC_KEYEVENT;
				if (ErrorLength == 1 && Error == PIN_CANCELED)
					bufferx[1] = 0x01;
				else
					bufferx[1] = 0x02;
				DoInterruptCallback(bufferx, 2);
			}
		}
		{
			uint8_t bufferx[2];
			bufferx[0] = RDR_TO_PC_KEYEVENT;
			bufferx[1] = 0xa1;
			DoInterruptCallback(bufferx, 2);
		}
#endif
		if (Res != 0)
			return Res;
		return ExecuteApplSecureResult(Error, ErrorLength, in, in_len, RespData, RespDataLen, 0, Slot);
	}
}