package lab04;

public class Instruction {
	
	private static final String[] opNames= { "NOP", "LOD", "STO", "ADD", "SUB", "MUL", "DIV", "HLT" } ;
	private static final String[] modeNames = { "IMM", "DIR" };
	
	// Fields
	String opName;
	int opcode;
	String modeName;
	int mode;
	int argument;
	
	public Instruction(String opName,String modeName,int argument) {
		this.opName = opName;
		this.opcode = findOpcode(opName);
		this.modeName = modeName;
		this.mode = findMode(modeName);
		this.argument = argument;
	}
	
	public Instruction(int binInstr) {
		opcode=getEncodedOpcode(binInstr);
		if (opcode<opNames.length) opName=opNames[opcode];
		else opName="???";
		mode=getEncodedMode(binInstr);
		if (mode<modeNames.length) modeName=modeNames[mode];
		else modeName="???";
		argument=getEncodedArg(binInstr);
	}
	
	public void store(Memory mem,int loc) {
		mem.set(loc,encodeOpModeArg(opcode,mode,argument));
	}
	
	public String getOpName() { return opName; }

	public int getOpcode() { return opcode; }

	public String getModeName() { return modeName; }

	public int getMode() { return mode; }

	public int getArgument() { return argument; }

	public static int findOpcode(String name) {
		for(int i=0;i<opNames.length;i++) {
			if (name.equals(opNames[i])) return i;
		}
		return -1;
	}
	
	public static int findMode(String name) {
		for(int i=0;i<modeNames.length;i++) {
			if (name.equals(modeNames[i])) return i;
		}
		return -1;
	}
	
	public static int encodeOpModeArg(int opcode,int mode,int arg) {
		int opMode= (opcode*10 + mode) << 24;
		int binInst = opMode | (arg & 0xFFFFFF);
		return binInst;
	}
	
	public static int getEncodedOpcode(int binInstr) {
		int opMode=(binInstr>>24) & 0xFF; // Get last 8 bits
		return opMode/10;
	}
	
	public static int getEncodedMode(int binInstr) {
		int opMode=(binInstr>>24) & 0xFF;
		return opMode%10; // Remainder operation discards the opcode
	}
	
	public static int getEncodedArg(int binInstr) {
		int arg = binInstr<<8; // Shift off leftmost 8 bits
		arg = arg>>8; // And shift back, propagating sign bit
		return arg;
	}

	@Override
	public String toString() {
		return "[" + opName + ", mode=" + modeName
				+ ", argument=" + argument + "]";
	}
	
}