#include <stdio.h>
#include <stdlib.h>
#include <gccore.h>
#include <string.h>
//#include <sys/unistd.h>

#include "patchcode.h"
#include "codecmp.h"

extern void patchhook(u32 address, u32 len);

// Hook found in freedom source
const u32 vigchooks[4] = {
	0x906402E4, 0x38000000, 0x900402E0, 0x909E0004
};

// Hook found by Nicksasa
const u32 GC_gxdrawdone_hooks[8] = {
	0x28000000, 0x4182FFF0, 0x7FE3FB78, 0x4BFE7CE5, 0x8001001C, 0x83E10014, 0x38210018, 0x7C0803A6
};

// Hook found by Nicksasa
const u32 GC_OSSleepthread_hooks[6] = {
	0x7FE3FB78, 0x4BFFC449, 0x8001001C, 0x83E10014, 0x83C10010, 0x38210018
};

u32 hookselect = 0;
u32 hook2select = 0;
u32 ocarinaselect = 0;
u32 debuggerselect = 0;

void set_codes_settings(u8 hook, u8 ocarina, u8 debugger, u8 hook2)
{
	hookselect = hook;
	ocarinaselect = ocarina;
	debuggerselect = debugger;
	hook2select = hook2;
}

void copy_2nd_hook(void *hookoffset)
{
	memset(hookoffset, 0, 32);
	switch (hook2select)
	{
		case 0x01:
			memcpy(hookoffset, (u32 *)vigchooks, sizeof(vigchooks));
		break;

		case 0x02:
			memcpy(hookoffset, (u32 *)GC_OSSleepthread_hooks, sizeof(GC_OSSleepthread_hooks));
		break;

		case 0x03:	
			memcpy(hookoffset, (u32 *)GC_gxdrawdone_hooks, sizeof(GC_gxdrawdone_hooks));
		break;
		
		default:
		break;
	}
}


//---------------------------------------------------------------------------------
bool dogamehooks(void *addr, u32 len)
//---------------------------------------------------------------------------------
{
	void *addr_start = addr;
	void *addr_end = addr+len;
	bool hookpatched = false;

	while(addr_start < addr_end)
	{
		switch (hookselect)
		{
			case 0x01:
				if (codecmp(addr_start, (u32 *)vigchooks, sizeof(vigchooks))==0)
				{
					patchhook((u32)addr_start, len);
					hookpatched = true;
				}
			break;

			case 0x02:
				if (codecmp(addr_start, (u32 *)GC_OSSleepthread_hooks, sizeof(GC_OSSleepthread_hooks)) == 0)
				{
					patchhook((u32)addr_start, len);
					hookpatched = true;
				}
			break;

			case 0x03:	
				if (codecmp(addr_start, (u32 *)GC_gxdrawdone_hooks, sizeof(GC_gxdrawdone_hooks)) == 0)
				{
					patchhook((u32)addr_start, len);
					hookpatched = true;
				}
			break;
		
			case 0x00:
			default:
				//hookpatched = true;
			break;

		}
		addr_start += 4;
	}
	return hookpatched;
}



