#include "oyagame.h"

// The main routine
void DynaCallMain(void* Address, int StackNum, int* Stack, int *eax, int *edx){
   //Prepare the stack and call API
	int i=StackNum+1;
	int j=(int)&Stack[StackNum-1];
	_asm mov ecx,i;    //Number of parameters
	_asm mov ebx,j;    //Address of last parameter
	_asm mov i,esp;    //cdecl support

	_asm jmp label2;   //Begin stack making process
label1:
	_asm push [ebx];
	_asm dec ebx;      // for (ecx=data->StackNum;0<ecx;ecx--) {
	_asm dec ebx;      //   _asm push data->Stack[ecx-1];
	_asm dec ebx;      // }
	_asm dec ebx;
label2:
	_asm loop label1;

	_asm call Address; //call the API here

	_asm mov esp,i;    //cdecl support
	_asm mov i,eax;    //Store the return codes from API
	_asm mov j,edx;

	//return eax and edx
	if (eax) *eax=i;
	if (edx) *edx=j;

}

// General SDL-function calling routines to be used in this program.
COMDATA* DataWithSDL=NULL; // See COMDATA::LoadDLL() for the setting this pointer.
DWORD CallSDL(LPWSTR funcname, VARIANTARG* rgvarg, int cArgs, int *eax /* =NULL */, int *edx /* =NULL */){
	if (!DataWithSDL) throw TYPE_E_DLLFUNCTIONNOTFOUND;// Must call SDL.Init() first.
	return DataWithSDL->DynaCall(funcname, rgvarg, cArgs, eax, edx );
}
int CallSDL(LPWSTR funcname, int cArgs, int* Stack){
	if (!DataWithSDL) throw TYPE_E_DLLFUNCTIONNOTFOUND;
	int eax;
	DataWithSDL->DynaCall(funcname, cArgs, Stack, &eax);
	return eax;
}
int CallSDL(LPWSTR funcname){
	int Stack[1];
	return CallSDL(funcname,0,Stack);
}
int CallSDL(LPWSTR funcname, int p1){
	int Stack[1]={p1};
	return CallSDL(funcname,1,Stack);
}
int CallSDL(LPWSTR funcname, int p1, int p2){
	int Stack[2]={p1,p2};
	return CallSDL(funcname,2,Stack);
}
int CallSDL(LPWSTR funcname, int p1, int p2, int p3){
	int Stack[3]={p1,p2,p2};
	return CallSDL(funcname,3,Stack);
}
int CallSDL(LPWSTR funcname, int p1, int p2, int p3, int p4){
	int Stack[4]={p1,p2,p3,p4};
	return CallSDL(funcname,4,Stack);
}
int CallSDL(LPWSTR funcname, int p1, int p2, int p3, int p4, int p5){
	int Stack[5]={p1,p2,p3,p3,p4};
	return CallSDL(funcname,5,Stack);
}

// Load the DLL file here.
DWORD COMDATA::LoadDLL(LPWSTR filename, LPWSTR prefix, bool useUnicode){
	// Initialize COMDATA
	if (prefix) FuncPrefix=CopySTR(prefix);
	UseUnicodeForDynaCall=useUnicode;
	// Try to load DLL from current directory or system32 directory
	TempMemory temp;
	LPSTR DllFileName=temp.TempANSI(filename);
	hDLL=LoadLibraryA(DllFileName);
	if (!hDLL) {
		// Try to load DLL from oyagame directory
		char buffer[_MAX_PATH];
		_getcwd( buffer, _MAX_PATH );
		_chdir(ModuleDir()); // Move to oyagame directory.
		hDLL=LoadLibraryA(DllFileName);
		_chdir(buffer); // Go back to original directory.
		if (!hDLL) {
			throw TYPE_E_CANTLOADLIBRARY;
			return TYPE_E_CANTLOADLIBRARY;
		}
	}
	if ((!lstrcmpiW(filename,L"SDL.dll")) && !lstrcmpiW(prefix,L"SDL_")) DataWithSDL=this;
	return S_OK;
}

DWORD COMDATA::DynaCall(LPWSTR funcname, int cArgs, int* Stack, int *eax /* =NULL */, int *edx /* =NULL */){
	TempMemory temp;
	// Load library if not yet loaded
	if (!hDLL) LoadDLL(L"SDL.dll",L"SDL_",false);
	// GetProcAddress
	LPSTR funcFullName;
	if (FuncPrefix) funcFullName=temp.TempANSI(temp.TempUNI(FuncPrefix,funcname));
	else funcFullName=temp.TempANSI(funcname);
	void* Address=GetProcAddress(hDLL,funcFullName);
	if (!Address) throw TYPE_E_DLLFUNCTIONNOTFOUND;
	// Call the function
	DynaCallMain(Address,cArgs,Stack,eax,edx);
	return S_OK;
}
DWORD COMDATA::DynaCall(LPWSTR funcname, VARIANTARG* rgvarg, int cArgs, int *eax /* =NULL */, int *edx /* =NULL */){
	TempMemory temp;
	// Prepare the stack
	int* Stack=temp.TempIntArray(cArgs);
	for(int i=0;i<cArgs;i++){
		LPWSTR s=ResolveSTR(&rgvarg[cArgs-i-1]);
		if (s) Stack[i]=UseUnicodeForDynaCall ? (int)s : (int)temp.TempANSI(s);
		else Stack[i]=CopyINT(&rgvarg[cArgs-i-1]);
	}
	return DynaCall(funcname,cArgs,Stack,eax,edx);
}

HWND GetHWND (){
	SDL_SysWMinfo info ;
	SDL_VERSION(&info.version);
	int Stack[1]={(int)&info};
	if (!CallSDL(L"GetWMInfo", 1, Stack )) return NULL;
	return info.window ;
}

