#ifndef STHOOK_H
#define STHOOK_H

class HookBase;

class gzHookManager {
public:
	static aVector<HookBase *> m_list;
};

class HookCallClass;
class HookJumpClass;
class PatchByteClass;
class HookBase {
protected:
	void Write(unsigned long Address, void *Bytes, int Size)
	{
		unsigned long PID = GetCurrentProcessId();
		HANDLE PHandle = OpenProcess(PROCESS_ALL_ACCESS, false, PID);
		WriteProcessMemory(PHandle, (void *)Address, Bytes, Size, NULL);
		CloseHandle(PHandle);
	}
	void Read(unsigned long Address, int Size, void *buf)
	{
		unsigned long PID = GetCurrentProcessId();
		HANDLE PHandle = OpenProcess(PROCESS_ALL_ACCESS, false, PID);
		ReadProcessMemory(PHandle,(void *)Address,(void *)buf,Size,NULL);
		CloseHandle(PHandle);
	}

	const char *m_name;
	unsigned long m_address;
	unsigned long m_func;
public:
	HookBase(const char *name, unsigned long Address, void *Function)
	{
		this->m_name = name;
		this->m_address = Address;
		this->m_func = (int)*&Function;
		//gzHookManager::m_list.Add(this);
	};
	virtual ~HookBase()
	{
		if (gzHookManager::m_list.Index(this))
			gzHookManager::m_list.Delete(gzHookManager::m_list.Index(this));
	};
	virtual HookCallClass *As_CallHookClass()
	{
		return NULL;
	}
	virtual HookJumpClass *As_JumpHookClass()
	{
		return NULL;
	}
	virtual PatchByteClass *As_PatchByteClass()
	{
		return NULL;
	};
};

class HookCallClass : public HookBase {
public:
	HookCallClass(const char *name, unsigned long Address, void *Function)
		: HookBase(name, Address, Function)
	{
		this->Read(Address,5,this->origBytes);
		unsigned char call = 0xE8;
		int offset = (int)*&Function - Address -5;
		this->Write(Address,&call,1);
		this->Write(Address +1,&offset,4);
	}
	~HookCallClass()
	{
		for (int i = 0; i <= 4; i++)
			this->Write(this->m_address + i,&this->origBytes[i],1);
	}
	HookCallClass *As_CallHook()
	{
		return this;
	}
	unsigned char origBytes[5];
};

class HookJumpClass : public HookBase {
public:
	HookJumpClass(const char *name, unsigned long Address, void *Function)
		: HookBase(name, Address, Function)
	{
		this->Read(Address,5,this->origBytes);
		unsigned char jmp = 0xE9;
		int offset = (int)*&Function - Address -5;
		this->Write(Address,&jmp,1);
		this->Write(Address +1,&offset,4);
	}
	~HookJumpClass()
	{
		for (int i = 0; i <= 4; i++)
			this->Write(this->m_address + i,&this->origBytes[i],1);
	}
	HookJumpClass *As_JumpHook()
	{
		return this;
	};
	unsigned char origBytes[5];
};

class PatchByteClass : public HookBase {
public:
	PatchByteClass(const char *name, unsigned long Address, unsigned char Byte, int patchLength)
		: HookBase(name, Address, NULL)
	{
		this->Byte = Byte;
		//this->origBytes = new unsigned char[patchLength +1];
		//this->Read(Address,patchLength,this->origBytes);
		this->patchedSize = patchLength;
		for (int i = 0; i < patchLength; i++)
			this->Write(Address + i,&Byte,1);
	}
	PatchByteClass(const char *name, unsigned long Address, unsigned char *Bytes[], int patchLength)
		: HookBase(name, Address, NULL)
	{
		this->patchedSize = patchLength;
		this->Write(Address,Bytes,patchLength);
	}
	~PatchByteClass()
	{
		//if (this->origBytes)
		//	delete this->origBytes;
	}
	PatchByteClass *As_PatchByteClass()
	{
		return this;
	}
	int patchedSize;
	unsigned char Byte;
	unsigned char *origBytes;
};

#endif
