
#include <windows.h>
#include <psapi.h>
#include <shlwapi.h>

#include <map>
#include <string>

#include "RedoBlHooks.cpp"

char moduleDir[MAX_PATH];

std::map<std::string, HMODULE> moduleTable;

bool rblDetachModule(std::string name){
	HMODULE module = moduleTable[name];
	if(!module) return false;
	
	BlPrintf("    " "Detaching module \"%s\"", name.c_str());
	
	if(!FreeLibrary(module)){
		BlPrintf("    \x03" "FreeLibrary failed to detach module. Error: %i", GetLastError());
		return false;
	}
	
	moduleTable[name] = NULL;
	return true;
}

HMODULE rblAttachModule(std::string name){
	rblDetachModule(name);
	
	BlPrintf("    " "Attaching module \"%s\"", name.c_str());
	
	char filename[MAX_PATH];
	strcpy_s(filename, moduleDir);
	PathAppend(filename, name.c_str());
	
	HMODULE module = LoadLibraryA(filename);
	if (module == NULL)
		BlPrintf("    \x03" "LoadLibrary failed to attach module. Error: %i", GetLastError());
	else
		moduleTable[name] = module;
	
	return module;
}

void rblLoad(){
	BlPrintf("RedBlocklandLoader Init:");
	
	if(!GetModuleFileNameA(NULL, moduleDir, MAX_PATH)){
		BlPrintf("    \x03" "Failed to determine game file location. Error: %i", GetLastError());
		return;
	}
	PathRemoveFileSpec(moduleDir);
	PathAppend(moduleDir, "modules");
	
	bool foundAny = false;
	
	char moduleSearch[MAX_PATH];
	strcpy_s(moduleSearch, moduleDir);
	PathAppend(moduleSearch, "*.dll");
	
	BlPrintf("    " "Searching for modules in: \"%s\"", moduleSearch);
	
	WIN32_FIND_DATAA finddata;
	HANDLE hFind = FindFirstFileA(moduleSearch, &finddata);
	
	if(hFind!=INVALID_HANDLE_VALUE){
		do{
			if(finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
				continue;
			
			foundAny = true;
			rblAttachModule(finddata.cFileName);
			
		} while(FindNextFileA(hFind, &finddata));
	}
	
	if(!foundAny){
		BlPrintf("    \x03" "No modules found");
	}
	
	BlPrintf("    ");
}

BlFunctionDef(void, __cdecl, InitGame);
void __cdecl InitGameHook();
BlFunctionHookDef(InitGame);

void __cdecl InitGameHook(){
	rblLoad();
	
	InitGameHookOff();
	InitGame();
	InitGameHookOn();
}

bool rblInit(){
	BlInit;
	
	BlScanFunctionHex(InitGame, "55 8B EC 6A FF 68 ? ? ? ? 64 A1 ? ? ? ? 50 83 EC 08 56 57 A1 ? ? ? ? 33 C5 50 8D 45 F4 64 A3 ? ? ? ? C7 05 ? ? ? ? ? ? ? ? C7 05 ? ? ? ? ? ? ? ? C7 05 ? ? ? ? ? ? ? ? C7 05 ? ? ? ? ? ? ? ? E8 ? ? ? ? B9 ? ? ? ? E8 ? ? ? ? 8B F0 89 75 F0 85 F6 74 29 8B CE E8 ? ? ? ? 8D 46 34 C7 06 ? ? ? ? 89 45 F0 C7 40 ? ? ? ? ? C7 00 ? ? ? ? C7 40 ? ? ? ? ? EB 02");
	
	InitGameHookOn();
	
	return true;
}

bool rblDenit(){
	InitGameHookOff();
	BlPrintf("RedBlocklandLoader: Successfully removed");
	
	return true;
}

bool __stdcall DllMain(HINSTANCE hinstance, unsigned int reason, void* reserved){
	switch(reason){
		case DLL_PROCESS_ATTACH:
			return rblInit();
		case DLL_PROCESS_DETACH:
			return rblDenit();
		default:
			return true;
	}
}

extern "C" void __declspec(dllexport) __cdecl RedBlocklandLoader(){}
