#include "sardIntegration.h"

#include <Windows.h>
#include <string>

namespace
{
	class armour_guard
	{
		enum errors
		{
			armour_load_failed = 1,
			get_sardInitialize_failed = 2
		};

	public:
		static int init(const wchar_t* armour_path, const char* sid);

		static void sard_set_user_name(const char* uname);
		static void sard_set_user_nameW(const wchar_t* uname);

		static void sard_set_user_id(const char* uid);
		static void sard_set_user_idW(const wchar_t* uid);

		static void sard_set_sess_id(const char* sid);
		static void sard_set_sess_idW(const wchar_t* sid);

		static void sard_relogin(const char* uname, const char* sid);
		static void sard_reloginW(const wchar_t* uname, const wchar_t* sid);

		static const char* sard_get_sec_sess_id();

		static void sard_finalize();


	private:

		static std::wstring get_default_path();
		static HMODULE armour_lib;
	};
	HMODULE armour_guard::armour_lib = 0;

	std::wstring armour_guard::get_default_path()
	{
		const unsigned FilenameSize = 2048;
		wchar_t* lpFilename = new wchar_t[FilenameSize];
		GetModuleFileNameW(0, lpFilename, FilenameSize);
		std::wstring myModulePath(lpFilename);
		delete[] lpFilename;
		std::string::size_type pos = myModulePath.find_last_of(L"\\/");
		if (std::string::npos != pos)
		{
			myModulePath = myModulePath.substr(0, pos);
		}
		else
		{
			myModulePath = L".";
		}
		myModulePath += L"\\sard\\armour.dll";
		return myModulePath;
	}

	int armour_guard::init(const wchar_t* armour_path, const char* sid)
	{
		int retValue = 0;
		std::wstring path = armour_path ? armour_path : get_default_path();
		armour_guard::armour_lib = LoadLibraryW(path.c_str());
		if (armour_guard::armour_lib)
		{
			using func_ptr = void(*)(const char*);
			func_ptr sardInitializePtr = reinterpret_cast<func_ptr> (GetProcAddress(armour_guard::armour_lib, "sardInitialize"));
			if (sardInitializePtr)
			{
				sardInitializePtr(sid);
			}
			else
			{
				retValue = get_sardInitialize_failed;
			}
		}
		else
		{
			retValue = armour_load_failed;
		}

		return retValue;
	}


	void armour_guard::sard_set_user_name(const char* uname)
	{
		using func_ptr = void(*)(const char*);
		func_ptr sardSetUserNamePtr = reinterpret_cast<func_ptr> (GetProcAddress(armour_guard::armour_lib, "sardSetUserName"));
		if (sardSetUserNamePtr)
		{
			sardSetUserNamePtr(uname);
			//print_dbg1("s", "sardSetUserName() Called\n");
		}
		else
		{
			//print_dbg3("sus", "GetProcAddress() failed for sardSetUserName. GetLastError = ", GetLastError(), "\n");
		}
	}

	void armour_guard::sard_set_user_nameW(const wchar_t* uname)
	{
		using func_ptr = void(*)(const wchar_t*);
		func_ptr sardSetUserNameWPtr = reinterpret_cast<func_ptr> (GetProcAddress(armour_guard::armour_lib, "sardSetUserNameW"));
		if (sardSetUserNameWPtr)
		{
			sardSetUserNameWPtr(uname);
			//print_dbg1("s", "sardSetUserNameW() Called\n");
		}
		else
		{
			//print_dbg3("sus", "GetProcAddress() failed for sardSetUserNameW. GetLastError = ", GetLastError(), "\n");
		}
	}


	void armour_guard::sard_set_user_id(const char* uid)
	{
		using func_ptr = void(*)(const char*);
		func_ptr sardSetUserIdPtr = reinterpret_cast<func_ptr> (GetProcAddress(armour_guard::armour_lib, "sardSetUserID"));
		if (sardSetUserIdPtr)
		{
			sardSetUserIdPtr(uid);
			//print_dbg1("s", "sardSetUserID() Called\n");
		}
		else
		{
			//print_dbg3("sus", "GetProcAddress() failed for sardSetUserID. GetLastError = ", GetLastError(), "\n");
		}
	}

	void armour_guard::sard_set_user_idW(const wchar_t* uid)
	{
		using func_ptr = void(*)(const wchar_t*);
		func_ptr sardSetUserIdWPtr = reinterpret_cast<func_ptr> (GetProcAddress(armour_guard::armour_lib, "sardSetUserWID"));
		if (sardSetUserIdWPtr)
		{
			sardSetUserIdWPtr(uid);
			//print_dbg1("s", "sardSetUserwID() Called\n");
		}
		else
		{
			//print_dbg3("sus", "GetProcAddress() failed for sardSetUserwID. GetLastError = ", GetLastError(), "\n");
		}
	}

	void armour_guard::sard_set_sess_id(const char* sid)
	{
		using func_ptr = void(*)(const char*);
		func_ptr sardSetSessionIdPtr = reinterpret_cast<func_ptr> (GetProcAddress(armour_guard::armour_lib, "sardSetSessionID"));
		if (sardSetSessionIdPtr)
		{
			sardSetSessionIdPtr(sid);
			//print_dbg1("s", "sardSetSessionID() Called\n");
		}
		else
		{
			//print_dbg3("sus", "GetProcAddress() failed for sardSetSessionID. GetLastError = ", GetLastError(), "\n");
		}
	}

	void armour_guard::sard_set_sess_idW(const wchar_t* sid)
	{
		using func_ptr = void(*)(const wchar_t*);
		func_ptr sardSetSessionWIdPtr = reinterpret_cast<func_ptr> (GetProcAddress(armour_guard::armour_lib, "sardSetSessionWID"));
		if (sardSetSessionWIdPtr)
		{
			sardSetSessionWIdPtr(sid);
			//print_dbg1("s", "sardSetSessionWID() Called\n");
		}
		else
		{
			//print_dbg3("sus", "GetProcAddress() failed for sardSetSessionWID. GetLastError = ", GetLastError(), "\n");
		}
	}


	const char* armour_guard::sard_get_sec_sess_id()
	{
		using func_ptr = const char*(*)();
		func_ptr sardGetSecSessIdPtr = reinterpret_cast<func_ptr> (GetProcAddress(armour_guard::armour_lib, "sardGetSecureSessionID"));
		if (sardGetSecSessIdPtr)
		{
			//print_dbg1("s", "sardGetSecureSessionID() Calling\n");
			return sardGetSecSessIdPtr();
		}
		else
		{
			//print_dbg3("sus", "GetProcAddress() failed for sardGetSecureSessionID. GetLastError = ", GetLastError(), "\n");
		}

		return NULL;
	}

	void armour_guard::sard_relogin(const char* uname, const char* sid)
	{
		using func_ptr = void(*)(const char*, const char*);
		func_ptr sardReloginPtr = reinterpret_cast<func_ptr> (GetProcAddress(armour_guard::armour_lib, "sardRelogin"));
		if (sardReloginPtr)
		{
			sardReloginPtr(uname, sid);
			//print_dbg1("s", "sardRelogin() Called\n");
		}
		else
		{
			//print_dbg3("sus", "GetProcAddress() failed for sardRelogin. GetLastError = ", GetLastError(), "\n");
		}
	}

	void armour_guard::sard_reloginW(const wchar_t* uname, const wchar_t* sid)
	{
		using func_ptr = void(*)(const wchar_t*, const wchar_t*);
		func_ptr sardReloginWPtr = reinterpret_cast<func_ptr> (GetProcAddress(armour_guard::armour_lib, "sardReloginW"));
		if (sardReloginWPtr)
		{
			sardReloginWPtr(uname, sid);
			//print_dbg1("s", "sardReloginW() Called\n");
		}
		else
		{
			//print_dbg3("sus", "GetProcAddress() failed for sardReloginW. GetLastError = ", GetLastError(), "\n");
		}
	}

	void armour_guard::sard_finalize()
	{
		using func_ptr = void(*)();
		func_ptr sardFinalizePtr = reinterpret_cast<func_ptr> (GetProcAddress(armour_guard::armour_lib, "sardFinalize"));
		if (sardFinalizePtr)
		{
			sardFinalizePtr();
			//print_dbg1("s", "sardFinalize() Called\n");
		}
		else
		{
			//print_dbg3("sus", "GetProcAddress() failed for sardFinalize. GetLastError = ", GetLastError(), "\n");
		}
	}


}

//API's

int sardInitialize(const wchar_t* armour_path, const char* sid)
{
	return armour_guard::init(armour_path, sid);
}

void sardSetUserName(const char* uname)
{
	armour_guard::sard_set_user_name(uname);
}

void sardSetUserNameW(const wchar_t* uname)
{
	armour_guard::sard_set_user_nameW(uname);
}

void sardSetUserId(const char* uid)
{
	armour_guard::sard_set_user_id(uid);
}

void sardSetUserIdW(const wchar_t* uid)
{
	armour_guard::sard_set_user_idW(uid);
}

void sardSetSessionId(const char* sid)
{
	armour_guard::sard_set_sess_id(sid);
}

void sardSetSessionIdW(const wchar_t* sid)
{
	armour_guard::sard_set_sess_idW(sid);
}

const char* sardGetSecureSessionId()
{
	return armour_guard::sard_get_sec_sess_id();
}

void sardRelogin(const char* uname, const char* sid)
{
	armour_guard::sard_relogin(uname, sid);
}

void sardReloginW(const wchar_t* uname, const wchar_t* sid)
{
	armour_guard::sard_reloginW(uname, sid);
}

void sardFinalize()
{
	armour_guard::sard_finalize();
}