#pragma once
#include <iostream>

enum Type
{
	Addres,
	Value
};
enum Command
{
	Mov,
	Syscall
};
enum Registers
{
	AX = -1,
	BX = -2,
	CX = -3,
	DX = -4,
	Error = -5
};

#pragma region System
int sizeCode;
char* MemoryCode;
int indexCode = 0;
long long registers[5] = { 0, 0, 0, 0, 0 };
HMODULE Core;
#pragma endregion

static int GetValue()
{
	char addr = MemoryCode[++indexCode];
	if (addr == Addres)
	{
		addr = MemoryCode[++indexCode];
		if (MemoryCode[++indexCode] > -5)
		{
			registers[4] = 0;
			return registers[MemoryCode[indexCode] - 1];
		}
		else
		{
			registers[4] = -1;
			return 0;
		}
	}
	else
	{
		registers[4] = 0;
		return MemoryCode[++indexCode];
	}
}

typedef void (*systemCall)(int);
systemCall SystemCall;

void InitVirtual(char* Code, int SizeCode)
{
	MemoryCode = Code;
	sizeCode = SizeCode;

	Core = LoadLibrary(L"CoreDLL.dll");
	if (Core == nullptr)
		exit(-1);

	SystemCall = (systemCall)GetProcAddress(Core, "SystemCall");
	if (SystemCall == nullptr)
		exit(-3);
}

void VirtualStart(char* Code, const int SizeCode)
{
	InitVirtual(Code, SizeCode);

	while (indexCode < sizeCode)
	{
		char OpCode = MemoryCode[indexCode];
		switch (OpCode)
		{
		case Mov:
		{
			++indexCode;
			int addr = MemoryCode[indexCode];
			int value = GetValue();
			registers[-addr - 1] = value;
		} break;
		case Syscall:
		{
			int systemCall = registers[0];
			SystemCall(systemCall);
		} break;
		}
		++indexCode;
	}

	FreeLibrary(Core);
}
