#pragma once
#pragma warning(disable: 4482) // nonstandard extension used: enum 'name' used in qualified name (C++11)

namespace sfall
{

enum CodeType : BYTE {
	Ret       = 0xC3,
	Call      = 0xE8,
	Jump      = 0xE9,
	Nop       = 0x90,
	JumpShort = 0xEB, // 0xEB [jmp short ...]
	JumpNZ    = 0x75, // 0x75 [jnz short ...]
	JumpZ     = 0x74, // 0x74 [jz  short ...]
};

// Macros for quick replacement of assembler opcodes pushad/popad
#define pushadc __asm push eax __asm push edx __asm push ecx
#define popadc __asm pop ecx __asm pop edx __asm pop eax

template <typename T>
void __stdcall SafeWrite(DWORD addr, T data) {
	DWORD oldProtect;
	VirtualProtect((void*)addr, sizeof(T), PAGE_EXECUTE_READWRITE, &oldProtect);
	*((T*)addr) = data;
	VirtualProtect((void*)addr, sizeof(T), oldProtect, &oldProtect);
}

template <typename T, class ForwardIteratorType>
void __stdcall SafeWriteBatch(T data, ForwardIteratorType begin, ForwardIteratorType end) {
	for (ForwardIteratorType it = begin; it != end; ++it) {
		SafeWrite<T>(*it, data);
	}
}

template <class T, size_t N>
void __stdcall SafeWriteBatch(T data, const DWORD (&addrs)[N]) {
	SafeWriteBatch<T>(data, std::begin(addrs), std::end(addrs));
}

void __stdcall SafeWrite8(DWORD addr, BYTE data);
void __stdcall SafeWrite16(DWORD addr, WORD data);
void __stdcall SafeWrite32(DWORD addr, DWORD data);
void __stdcall SafeWriteStr(DWORD addr, const char* data);

void SafeMemSet(DWORD addr, BYTE val, size_t len);
void SafeWriteBytes(DWORD addr, BYTE* data, size_t count);

void HookCall(DWORD addr, void* func);
void MakeCall(DWORD addr, void* func);
void MakeCall(DWORD addr, void* func, size_t len);
void MakeJump(DWORD addr, void* func);
void MakeJump(DWORD addr, void* func, size_t len);
void BlockCall(DWORD addr);

// emulation of 4.x HookCalls/MakeCalls/MakeJumps

template <class ForwardIteratorType>
void HookCalls(void* func, ForwardIteratorType begin, ForwardIteratorType end) {
	for (ForwardIteratorType it = begin; it != end; ++it) {
		HookCall(*it, func);
	}
}

template <size_t N>
void HookCalls(void* func, const DWORD (&addrs)[N]) {
	HookCalls(func, std::begin(addrs), std::end(addrs));
}

template <class ForwardIteratorType>
void MakeCalls(void* func, ForwardIteratorType begin, ForwardIteratorType end) {
	for (ForwardIteratorType it = begin; it != end; ++it) {
		MakeCall(*it, func);
	}
}

template <size_t N>
void MakeCalls(void* func, const DWORD (&addrs)[N]) {
	MakeCalls(func, std::begin(addrs), std::end(addrs));
}

template <class ForwardIteratorType>
void MakeJumps(void* func, ForwardIteratorType begin, ForwardIteratorType end) {
	for (ForwardIteratorType it = begin; it != end; ++it) {
		MakeJump(*it, func);
	}
}

template <size_t N>
void MakeJumps(void* func, const DWORD (&addrs)[N]) {
	MakeJumps(func, std::begin(addrs), std::end(addrs));
}

}
