#pragma once

#include "binary_data.hpp"		// MemoryAddress, Word, Byte

#include "opcode_info.hpp"
#include "operand_info.hpp"

#include <vector>
#include <map>

#include <boost/shared_ptr.hpp>

/** This <<entity>> object represents low level intermediate code.
 *  It can translate to assembly language
 *                  and three-address code(quadruple).
 *  Use InstructionOutput to convert readable form.
 */
class Instruction
{
public:
	typedef boost::shared_ptr<Instruction> shared_ptr;
private:
	enum ConstInt{
		VALID_SIGNATURE = 0x1234, INVALID_SIGNATURE,
	};
	/** legal signature to check uninitialized pointer.*/
	int m_signature;
	
	const opcode::OpcodeInfo* m_info;
	
	MemoryAddress m_address;
	Word m_parameter;
	std::vector<Byte> m_bytecode;

	/** result := first op second.*/
	Operand m_result;
	Operand m_first;
	Operand m_second;
	
	/** Instruction is invalid by default.*/
	Instruction();
public:
	/** construct by address and opcode.*/
	Instruction(MemoryAddress address, Byte opcode);
	
	bool isValid()const;
	
	/** set parameter.*/
	void setByteParameter(Byte byte);
	void setLowHighParameter(Byte low, Byte high);
	
	/** returns operation of instruction.*/
	const opcode::Operation& op()const;
	const opcode::OperationInfo* operation()const;
	const char* mnemonic()const;
	
	opcode::AddressingMode addressingMode()const;
	unsigned bytelength()const;
	opcode::AccessType accessType()const;

	MemoryAddress address()const;
	MemoryAddress next()const;
	
	Word parameter()const;
	const std::vector<Byte>* bytecode()const;
	
	/** get result of the instruction operation.*/
	const Operand& result()const;
	const Operand& first()const;
	const Operand& second()const;
	
	/** get invalid object.*/
	static shared_ptr getInvalid();
private:
	/** setup operand infomations.*/
	void setupOperand();
	inline void invariant()const;
};

/** This map contain instructions by the address.*/
class InstructionMap
{
private:
	InstructionMap(){};
public:
	typedef std::map<MemoryAddress, Instruction::shared_ptr> map;
	typedef boost::shared_ptr<InstructionMap::map> shared_ptr;
	typedef InstructionMap::map::iterator iterator;
};

