#include "stdafx.h"
#include "R-DT-EVO-LEG42-USB-SDK.h"
#include "LegicProtocol.h"
#include "Util.h"

#include "setupapi.h"
#include "SdkString.h"

#ifdef _MANAGED
#pragma managed(push, off)
#endif

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
					 )
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
    return TRUE;
}

#ifdef _MANAGED
#pragma managed(pop)
#endif


DWORD GetAvailableCom(DWORD dwPos)
{
	DWORD dwIndex		= 0x00;
	DWORD dwReaderPos	= 0x00;
	DWORD dwScanCom		= 0x00;
	DWORD dwComFound	= -1;

	const GUID GUID_COM = {0x4D36E978, 0xE325, 0x11CE, {0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18}};
	HDEVINFO hDevHandle = SetupDiGetClassDevs(&GUID_COM, NULL, NULL, DIGCF_PRESENT | DIGCF_PROFILE);

	if(hDevHandle != INVALID_HANDLE_VALUE)
	{
		SP_DEVINFO_DATA stDevInfoData;
		stDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);

		BOOL bStop = FALSE;
		while(SetupDiEnumDeviceInfo(hDevHandle, dwIndex, &stDevInfoData) && (!bStop))
		{
			SP_DRVINFO_DATA stDrvData;
			ZeroMemory(&stDrvData, sizeof(SP_DRVINFO_DATA));
			stDrvData.cbSize = sizeof(SP_DRVINFO_DATA);
			if(SetupDiBuildDriverInfoList(hDevHandle, &stDevInfoData, SPDIT_COMPATDRIVER))
			{
				TCHAR szPath[MAX_PATH];
				DWORD dwDataType = -1, dwAddress = -1, dwSize = MAX_PATH;
				SdkString strDevName = _T(""), strDevDesc = _T("");

				if(SetupDiGetDeviceRegistryProperty(hDevHandle, &stDevInfoData, SPDRP_FRIENDLYNAME, &dwDataType, (BYTE*)szPath, MAX_PATH, &dwSize))
				{
					strDevName = szPath;
					dwDataType = -1, dwAddress = -1, dwSize = MAX_PATH;
					ZeroMemory(szPath, MAX_PATH);
					if(SetupDiGetDeviceRegistryProperty(hDevHandle, &stDevInfoData, SPDRP_DEVICEDESC, &dwDataType, (BYTE*)szPath, MAX_PATH, &dwSize))
					{
						strDevDesc = szPath;
						strDevDesc += _T(" (COM");
						strDevName.erase(0x00, strDevDesc.size());
						strDevName.erase(strDevName.size() - 0x01, 0x01);

						if(dwPos == dwScanCom)
						{
							bStop = TRUE;
							dwComFound = _ttoi(strDevName.c_str());
						}
						dwScanCom++;
					}
				}
				SetupDiDestroyDriverInfoList(hDevHandle, &stDevInfoData, SPDIT_COMPATDRIVER);
			}

			stDevInfoData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
			dwIndex++;
		}
		SetupDiDestroyDeviceInfoList(hDevHandle);
	}
	return dwComFound;
}

SDKHANDLE OpenReader(UINT nCom)
{
	CLegicProtocol *pLegicProt = new CLegicProtocol();
	if(pLegicProt != NULL)
	{
		pLegicProt->SetCom(nCom);
		if(pLegicProt->Open() != ER_OK)
		{
			delete pLegicProt;
			pLegicProt = NULL;
		}
	}
	return pLegicProt;
}

EERROR SetReaderCaps(SDKHANDLE hReader, EREADER_FEATURE eRdFeat, BYTE* pData, DWORD dwCount)
{
	EERROR eRet = ER_INVALID_POINTER;
	CLegicProtocol* pLegProt = (CLegicProtocol*)hReader;
	if((pLegProt != NULL) && (pData != NULL))
	{
		eRet = ER_FEATURE;
		switch(eRdFeat)
		{
			case ERD_LEDS:
			{
				eRet = ER_DATA_SIZE;
				if(dwCount == sizeof(BYTE))
				{
					eRet = pLegProt->SetLeds((BOOL)(*(BYTE*)pData));
				}
			}break;

			case ERD_BUZZER:
			{
				eRet = ER_DATA_SIZE;
				if(dwCount == sizeof(BYTE))
				{
					eRet = pLegProt->SetBuzzer((BOOL)(*(BYTE*)pData));
				}
			}break;

			case ERD_CARD:
			{
				eRet = ER_DATA_SIZE;
				if(dwCount = (3 * sizeof(DWORD)))
				{
					DWORD* pDataInfo = (DWORD*)pData;
					eRet = pLegProt->SelectCard((ECARDTYPE)pDataInfo[0x00], pDataInfo[0x01], pDataInfo[0x02]);
				}
			}break;

			case ERD_SELECT_FILE:
			{
				eRet = ER_DATA_SIZE;
				if(dwCount >= (3 * sizeof(DWORD)))
				{
					DWORD* pDataInfo = (DWORD*)pData; DWORD dwFileSize = 0x00;
					eRet = pLegProt->SelectFile(pDataInfo[0x00], (EFILETYPE)pDataInfo[0x01], 
								pDataInfo[0x02] > 0x00 ? (pData + 3 * sizeof(DWORD)) : NULL, pDataInfo[0x02], dwFileSize);
				}
			}break;
		}
	}
	return eRet;
}

EERROR GetReaderCaps(SDKHANDLE hReader, EREADER_FEATURE eRdFeat, BYTE* pData, DWORD& dwCount)
{
	EERROR eRet = ER_INVALID_POINTER;
	CLegicProtocol* pLegProt = (CLegicProtocol*)hReader;
	if((pLegProt != NULL) && (pData != NULL))
	{
		eRet = ER_FEATURE;
		switch(eRdFeat)
		{
			case ERD_READER_TYPE:
			{
				BYTE* pDataRet = NULL; DWORD dwDataRet = 0x00;
				if((eRet = pLegProt->GetIDB(0x00, &pDataRet, dwDataRet)) == ER_OK)
				{
					eRet = ER_INVALID_DATA;
					if(pDataRet[0x00] == 0x01)
					{
						eRet = CUtil::SetDataStr("SM-4200", pData, dwCount);
					}
					delete[] pDataRet;
				}
			}break;

			case ERD_HARDAWARE_REV:
			{
				BYTE* pDataRet = NULL; DWORD dwDataRet = 0x00;
				if((eRet = pLegProt->GetIDB(0x00, &pDataRet, dwDataRet)) == ER_OK)
				{
					switch(pDataRet[0x01])
					{
						case 0x01: eRet = CUtil::SetDataStr("V0.1",	pData, dwCount); break;
						case 0x02: eRet = CUtil::SetDataStr("V0.2",	pData, dwCount); break;
						case 0x03: eRet = CUtil::SetDataStr("V0.3",	pData, dwCount); break;
						case 0x04: eRet = CUtil::SetDataStr("V0.9",	pData, dwCount); break;
						case 0x05: eRet = CUtil::SetDataStr("V1.0",	pData, dwCount); break;
						default: eRet = CUtil::SetDataStr("Unknown",	pData, dwCount); 
					}
					delete[] pDataRet;
				}
			}break;

			case ERD_POWER:
			{
				BYTE* pDataRet = NULL; DWORD dwDataRet = 0x00;
				if((eRet = pLegProt->GetIDB(0x00, &pDataRet, dwDataRet)) == ER_OK)
				{
					switch(pDataRet[0x02])
					{
						case 0x01: eRet = CUtil::SetDataStr("Standard power",	pData, dwCount); break;
						case 0x10: eRet = CUtil::SetDataStr("Battery power",	pData, dwCount); break;
						default: eRet = CUtil::SetDataStr("Unknown",			pData, dwCount); 
					}
					delete[] pDataRet;
				}
			}break;

			case ERD_BOOT_LOADER:
			{
				BYTE* pDataRet = NULL; DWORD dwDataRet = 0x00;
				if((eRet = pLegProt->GetIDB(0x00, &pDataRet, dwDataRet)) == ER_OK)
				{
					CHAR szTmp[MAX_PATH];
					sprintf_s(szTmp, MAX_PATH, "V%d.%d", pDataRet[0x03], pDataRet[0x04]);
					eRet = CUtil::SetDataStr(szTmp, pData, dwCount);
					delete[] pDataRet;
				}
			}break;

			case ERD_FIRMWARE:
			{
				BYTE* pDataRet = NULL; DWORD dwDataRet = 0x00;
				if((eRet = pLegProt->GetIDB(0x00, &pDataRet, dwDataRet)) == ER_OK)
				{
					CHAR szTmp[MAX_PATH];
					sprintf_s(szTmp, MAX_PATH, "V%d.%d.%d.%d", pDataRet[0x05], pDataRet[0x06], pDataRet[0x07], pDataRet[0x08]);
					eRet = CUtil::SetDataStr(szTmp, pData, dwCount);
					delete[] pDataRet;
				}
			}break;

			case ERD_CRYPT_MODE:
			{
				BYTE* pDataRet = NULL; DWORD dwDataRet = 0x00;
				if((eRet = pLegProt->GetIDB(0x1B, &pDataRet, dwDataRet)) == ER_OK)
				{
					switch(pDataRet[0x00])
					{
						case 0x00: eRet = CUtil::SetDataStr("No encryption",				pData, dwCount); break;
						case 0x01: eRet = CUtil::SetDataStr("AES 128 bit",					pData, dwCount); break; 
						case 0x03: eRet = CUtil::SetDataStr("3DES",						pData, dwCount); break; 
						case 0x04: eRet = CUtil::SetDataStr("AES 128 bit - Auth. only",	pData, dwCount); break;
						case 0x06: eRet = CUtil::SetDataStr("3DES - Auth. only",			pData, dwCount); break; 
						default: eRet = CUtil::SetDataStr("Unknown",						pData, dwCount); 
					}
					delete[] pDataRet;
				}
			}break;

			case ERD_CARD:
			{
				eRet = ER_INVALID_DATA;
				if(dwCount > sizeof(DWORD))
				{
					if((eRet = pLegProt->SetState(EIDLE)) == ER_OK)
					{
						BYTE* pDataRet = NULL; DWORD dwDataRet = 0x00, dwCardType = *(BYTE*)pData, dwCardNr = 0x00;
						if((eRet = pLegProt->GetCards((ECARDTYPE)dwCardType, dwCardNr, &pDataRet, dwDataRet)) == ER_OK)
						{
							*(DWORD*)pData = dwCardNr;
							dwCount -= sizeof(DWORD);
							eRet = CUtil::SetDataByte(pDataRet, dwDataRet, pData + sizeof(DWORD), dwCount);
						}
						delete[] pDataRet;
					}
				}
			}break;

		}
	}
	return eRet;
}

EERROR ReadData(SDKHANDLE hReader, DWORD dwAddress, BYTE* pData, DWORD& dwLen)
{
	EERROR eRet = ER_INVALID_POINTER;
	CLegicProtocol* pLegProt = (CLegicProtocol*)hReader;
	if((pLegProt != NULL) && (pData != NULL))
	{
		eRet = pLegProt->ReadFile(dwAddress, pData, dwLen);
	}
	return eRet;
}

EERROR WriteData(SDKHANDLE hReader, DWORD dwAddress, BYTE* pData, DWORD dwLen)
{
	EERROR eRet = ER_INVALID_POINTER;
	CLegicProtocol* pLegProt = (CLegicProtocol*)hReader;
	if((pLegProt != NULL) && (pData != NULL))
	{
		eRet = pLegProt->WriteFile(dwAddress, pData, dwLen);
	}
	return eRet;
}

void CloseReader(SDKHANDLE hReader)
{
	CLegicProtocol* pLegProt = (CLegicProtocol*)hReader;
	if(pLegProt != NULL)
	{
		pLegProt->Close();
		delete pLegProt;
	}
}
