#pragma once
#include "opcode_info.hpp"

namespace opcode {
/** this utility map AddressingMode to some infomation.*/
class AddressingModeType
{
public:
	AddressingMode mode;
	
	AddressingModeType(AddressingMode addressing_mode)
			:mode(addressing_mode)
	{
	}
	unsigned bytelength()const
	{
		switch (mode){
		case opcode::ABS: case opcode::ABS_X: case opcode::ABS_Y:
		case opcode::IND:
			return 3;
		case opcode::IMM: case opcode::REL:
		case opcode::ZERO: case opcode::ZERO_X: case opcode::ZERO_Y:
		case opcode::PRE_IND: case opcode::POST_IND:
			return 2;
		default:
			return 1;
		}
	}
	
};

/** This utility class tells type of Operation.
 * Usage:
 opcode::OperationType optype(op);
 if (optype.is_conditional) {
 branch = parameter;
 }
*/
class OperationType
{
public:
	bool is_conditional;
	bool is_jump;
	bool is_return;
	bool is_call;
	
	OperationType()
	{
		clear();
	}
	OperationType(Operation operation)
	{
		set(operation);
	}
	void clear()
	{
		is_conditional = false;
		is_jump = false;
		is_return = false;
		is_call = false;
	}
	void set(Operation operation)
	{
		clear();
		
		switch (operation) {
		case opcode::BCC: case opcode::BCS:
		case opcode::BEQ: case opcode::BNE:
		case opcode::BMI: case opcode::BPL:
		case opcode::BVC: case opcode::BVS:
			is_jump = true;
			is_conditional = true;
			break;
		case opcode::RTI: case opcode::RTS:
			is_jump = true;
			is_return = true;
			break;
		case opcode::JSR:
			is_jump = true;
			is_call = true;
			break;
		case opcode::JMP: case opcode::BRK:
			is_jump = true;
			break;
		default:
			break;
		}
	}
};

}
