#include "common/stdafx.h"
#include "common/util.h"

#include "tinsel/script.h"
#include "tinsel/opcodes.h"

namespace Tinsel {

Script::Script(uint8 *buf, uint32 len) {
	_buf = (uint8 *)calloc(len, sizeof(uint8));
	memcpy(_buf, buf, len);
	_buflen = len;
}

Script::~Script(void) {
	free(_buf);
}

void Script::run(void) {
	uint8 opcode, op8;
	uint16 op16;
	uint32 i = 0, op32;
	const char *text;

	while(i < _buflen)
	{
		opcode = _buf[i ++];

		if(opcode > OP_MAX)
		{
			warning("opcode > OP_MAX (0x%02X)", opcode);
			break;
		}

		OpcodeDesc desc = opcode_descriptions[opcode];

		if(desc.description == NULL)
		{
			warning("unknown opcode 0x%02X", opcode);
			break;
		}

		text = desc.description.c_str();

		switch(desc.numArgs)
		{
			case 0:
				debug(1, "OP: %02X (%s)", opcode, text);
				break;

			case 1:
				op8 = _buf[i];
				debug(1, "OP: %02X 0x%02x (%s)", opcode, op8, text);
				i ++;
				break;

			case 2:
				op16 = get_uint16(i);
				debug(1, "OP: %02X 0x%04x (%s)", opcode, op16, text);
				i += 2;
				break;

			case 4:
				op32 = get_uint32(i);
				debug(1, "OP: %02X 0x%08x (%s)", opcode, op32, text);
				i += 4;
				break;

			default:
				break;
		}
	}
}

uint16 Script::get_uint16(uint32 pos)
{
	return _buf[pos] + (_buf[pos + 1] << 8);
}

uint32 Script::get_uint32(uint32 pos)
{
	return get_uint16(pos) + (get_uint16(pos + 2) << 16);
}

} // namespace Tinsel

