#include <Windows.h>
#include <libloaderapi.h>
#include <errhandlingapi.h>

#include <iostream>
#include <vector>

#include "spdQuoteAPI.h"

static HMODULE hSpeedyDLL = NULL;

fptrPyQuoteAdapter_New pyQuoteAdapter_New = NULL;
fptrPyQuoteAdapter_Delete pyQuoteAdapter_Delete = NULL;
fptrPyQuoteAdapter_IsConnected pyQuoteAdapter_IsConnected = NULL;
fptrPyQuoteAdapter_Logon pyQuoteAdapter_Logon = NULL;
fptrPyQuoteAdapter_Subscribe pyQuoteAdapter_Subscribe = NULL;
fptrPyQuoteAdapter_UnsubscribeAll pyQuoteAdapter_UnsubscribeAll = NULL;
fptrPyQuoteAdapter_DownloadContracts pyQuoteAdapter_DownloadContracts = NULL;
fptrPyQuoteAdapter_RegEvents pyQuoteAdapter_RegEvents = NULL;
fptrPyQuoteAdapter_GetLastErrorMessage pyQuoteAdapter_GetLastErrorMessage = NULL;

bool spdQuoteAPI::LoadQuoteAPIFromDLL()
{
#ifdef _M_X64
	std::string dll_name = "megaSpeedyAPI_64.dll";
#else
	std::string dll_name = "megaSpeedyAPI.dll";
#endif

	if (hSpeedyDLL)
		return true;

	hSpeedyDLL = LoadLibraryA(dll_name.c_str());
	if (!hSpeedyDLL)
	{
		DWORD err = GetLastError();
		std::cout << "Load " << dll_name << " fail! Error Code:" << err << std::endl;
		return false;
	}

	std::vector<std::pair<void*, std::string>> exported_function;

	pyQuoteAdapter_New = (fptrPyQuoteAdapter_New)GetProcAddress(hSpeedyDLL, "pyQuoteAdapter_New");
	pyQuoteAdapter_Delete = (fptrPyQuoteAdapter_Delete)GetProcAddress(hSpeedyDLL, "pyQuoteAdapter_Delete");
	pyQuoteAdapter_IsConnected = (fptrPyQuoteAdapter_IsConnected)GetProcAddress(hSpeedyDLL, "pyQuoteAdapter_IsConnected");
	pyQuoteAdapter_Logon = (fptrPyQuoteAdapter_Logon)GetProcAddress(hSpeedyDLL, "pyQuoteAdapter_Logon");
	pyQuoteAdapter_Subscribe = (fptrPyQuoteAdapter_Subscribe)GetProcAddress(hSpeedyDLL, "pyQuoteAdapter_Subscribe");
	pyQuoteAdapter_UnsubscribeAll = (fptrPyQuoteAdapter_UnsubscribeAll)GetProcAddress(hSpeedyDLL, "pyQuoteAdapter_UnsubscribeAll");
	pyQuoteAdapter_DownloadContracts = (fptrPyQuoteAdapter_DownloadContracts)GetProcAddress(hSpeedyDLL, "pyQuoteAdapter_DownloadContracts");
	pyQuoteAdapter_RegEvents = (fptrPyQuoteAdapter_RegEvents)GetProcAddress(hSpeedyDLL, "pyQuoteAdapter_RegEvents");
	pyQuoteAdapter_GetLastErrorMessage = (fptrPyQuoteAdapter_GetLastErrorMessage)GetProcAddress(hSpeedyDLL, "pyQuoteAdapter_GetLastErrorMessage");

	exported_function.push_back(std::pair<void*, std::string>(pyQuoteAdapter_New, "pyQuoteAdapter_New"));
	exported_function.push_back(std::pair<void*, std::string>(pyQuoteAdapter_Delete, "pyQuoteAdapter_Delete"));
	exported_function.push_back(std::pair<void*, std::string>(pyQuoteAdapter_IsConnected, "pyQuoteAdapter_IsConnected"));
	exported_function.push_back(std::pair<void*, std::string>(pyQuoteAdapter_Logon, "pyQuoteAdapter_Logon"));
	exported_function.push_back(std::pair<void*, std::string>(pyQuoteAdapter_Subscribe, "pyQuoteAdapter_Subscribe"));
	exported_function.push_back(std::pair<void*, std::string>(pyQuoteAdapter_UnsubscribeAll, "pyQuoteAdapter_UnsubscribeAll"));
	exported_function.push_back(std::pair<void*, std::string>(pyQuoteAdapter_DownloadContracts, "pyQuoteAdapter_DownloadContracts"));
	exported_function.push_back(std::pair<void*, std::string>(pyQuoteAdapter_RegEvents, "pyQuoteAdapter_RegEvents"));
	exported_function.push_back(std::pair<void*, std::string>(pyQuoteAdapter_GetLastErrorMessage, "pyQuoteAdapter_GetLastErrorMessage"));

	for (size_t i = 0; i < exported_function.size(); ++i)
	{
		if (!exported_function[i].first)
		{
			std::cout << "function \"" << exported_function[i].second << "\" is missing in " << dll_name << std::endl;
			FreeLibrary(hSpeedyDLL);
			hSpeedyDLL = NULL;

			return false;
		}
	}

	return true;
}

void spdQuoteAPI::OnQuoteConnected(void* user_defined)
{
	spdQuoteAPI* target = reinterpret_cast<spdQuoteAPI*>(user_defined);
	target->OnStarwaveConnected();
}

void spdQuoteAPI::OnQuoteDisconnected(void* user_defined)
{
	spdQuoteAPI* target = reinterpret_cast<spdQuoteAPI*>(user_defined);
	target->OnStarwaveDisconnected();
}

void spdQuoteAPI::OnQuoteOrderBook(void* user_defined, const char* Exchange, const char* Symbol, const char* MsgTime, spdMsgOrderBook* OrderBook)
{
	spdQuoteAPI* target = reinterpret_cast<spdQuoteAPI*>(user_defined);
	target->OnOrderBook(Exchange, Symbol, MsgTime, OrderBook);
}

void spdQuoteAPI::OnQuoteTrade(void* user_defined, const char* Exchange, const char* Symbol, const char* MatchTime, double MatchPrice, int MatchQty, bool isTestMatch)
{
	spdQuoteAPI* target = reinterpret_cast<spdQuoteAPI*>(user_defined);
	target->OnTrade(Exchange, Symbol, MatchTime, MatchPrice, MatchQty, isTestMatch);
}

void spdQuoteAPI::OnQuoteLogonResponse(void* user_defined, bool isLoginOK, const char* ReplyMsg)
{
	spdQuoteAPI* target = reinterpret_cast<spdQuoteAPI*>(user_defined);
	target->OnStarwaveLogonResponse(isLoginOK, ReplyMsg);
}

void spdQuoteAPI::OnQuoteContract(void* user_defined, const char* Exchange, const char* Symbol, const char* Name, const char* MaturityDate, const char* Category, spdContract* Contract)
{
	spdQuoteAPI* target = reinterpret_cast<spdQuoteAPI*>(user_defined);
	target->OnContract(Exchange, Symbol, Name, MaturityDate, Category, Contract);
}

void spdQuoteAPI::OnQuoteContractDownloadComplete(void* user_defined, int TotalContracts)
{
	spdQuoteAPI* target = reinterpret_cast<spdQuoteAPI*>(user_defined);
	target->OnContractDownloadComplete(TotalContracts);
}

spdQuoteAPI::spdQuoteAPI() : quoteAPI(NULL)
{
	LoadQuoteAPIFromDLL();
	quoteAPI = pyQuoteAdapter_New();
	pyQuoteAdapter_RegEvents(quoteAPI,
		                     this,
		                     OnQuoteConnected,
		                     OnQuoteDisconnected,
		                     OnQuoteLogonResponse,
		                     OnQuoteContract,
		                     OnQuoteContractDownloadComplete,
		                     OnQuoteOrderBook,
		                     OnQuoteTrade);
}

spdQuoteAPI::~spdQuoteAPI()
{
	if (quoteAPI)
		pyQuoteAdapter_Delete(quoteAPI);
}

bool spdQuoteAPI::IsStarwaveConnected(void)
{
	return pyQuoteAdapter_IsConnected(quoteAPI);
}

bool spdQuoteAPI::LogonStarwave(const char* IP, int Port, const char* ID, const char* Password, bool DownloadContracts)
{
	return pyQuoteAdapter_Logon(quoteAPI, IP, Port, ID, Password, DownloadContracts);
}

bool spdQuoteAPI::Subscribe(const char* Exchange, const char* Symbol)
{
	return pyQuoteAdapter_Subscribe(quoteAPI, Exchange, Symbol);
}

void spdQuoteAPI::UnsubscribeAll()
{
	pyQuoteAdapter_UnsubscribeAll(quoteAPI);
}

void spdQuoteAPI::DownloadContracts(void)
{
	pyQuoteAdapter_DownloadContracts(quoteAPI);
}

std::string spdQuoteAPI::GetQuoteAPILastErrorMessage()
{
	std::string err_msg = pyQuoteAdapter_GetLastErrorMessage(quoteAPI);
	return err_msg;
}