package stackprogramvisualiser;

import stackprogramvisualiser.exceptions.InvalidInstructionException;
import stackprogramvisualiser.exceptions.InvalidLabelException;
import stackprogramvisualiser.exceptions.ProgramExitException;

import java.util.EmptyStackException;

public class Instruction {

	private Command command;
	private Integer intArg = null;
	private String strArg = null;

	public Instruction(String command) throws InvalidInstructionException {
		setCommand(command);
	}

	public Instruction(String command, int intArg) throws InvalidInstructionException {
		setCommand(command);
		this.intArg = intArg;
	}

	public Instruction(String command, String strArg) throws InvalidInstructionException {
		setCommand(command);
		this.strArg = strArg;
	}

	private void setCommand(String command) throws InvalidInstructionException {
		try {
			this.command = Command.valueOf(command.toUpperCase());
		} catch (IllegalArgumentException iae) {
			throw new InvalidInstructionException(command);
		}
	}

	public void execute() throws NullPointerException, EmptyStackException, ProgramExitException, InvalidLabelException {
		// temporary holders
		Integer a1, a2;

		// switch on the command we're executing
		switch (command) {
			case INT:
				if (intArg == null) throw new NullPointerException();
				push(intArg);
				break;

			case ADD:
				a1 = pop();
				a2 = pop();
				push(a1 + a2);
				break;

			case SUB:
				a1 = pop();
				a2 = pop();
				push(a2 - a1);
				break;

			case JGE:
				a1 = peek();
				if (a1 >= 0) {
					// which arg to move to?
					if (intArg != null) {
						pcSet(intArg);
					} else {
						int newPC = StackProgramVisualiser.parsedCode.getPositionForLabel(strArg);
						if (newPC < 0) {
							throw new InvalidLabelException(strArg);
						}
						pcSet(newPC);
					}
					return;
				}
				break;

			case JEQ:
				a1 = peek();
				if (a1 == 0) {
					// which arg to move to?
					if (intArg != null) {
						pcSet(intArg);
					} else {
						int newPC = StackProgramVisualiser.parsedCode.getPositionForLabel(strArg);
						if (newPC < 0) {
							throw new InvalidLabelException(strArg);
						}
						pcSet(newPC);
					}
					return;
				}
				break;

			case EXIT:
				throw new ProgramExitException();

			case SWAP:
				a1 = pop();
				a2 = pop();
				push(a1);
				push(a2);
				break;

			case DUP:
				push(peek());
				break;

			case POP:
				pop();
				break;

			case PRINT:
				StackProgramVisualiser.gui.outputTerminalMessage(peek().toString());
				break;
		}

		// move on!
		pcAdvance();
	}

	/* shortcut methods */

	private void push(Integer i) {
		StackProgramVisualiser.dataStack.push(i);
	}

	private Integer pop() throws EmptyStackException {
		return StackProgramVisualiser.dataStack.pop();
	}

	private Integer peek() throws EmptyStackException {
		return StackProgramVisualiser.dataStack.peek();
	}

	private void pcAdvance() {
		StackProgramVisualiser.programCounter++;
	}

	private void pcSet(int pc) {
		StackProgramVisualiser.programCounter = pc;
	}

	public enum Command {
		// basic inputs
		INT,

		// arithmetic
		ADD,
		SUB,

		// control statements
		JGE,
		JEQ,
		EXIT,

		// stack manipulation
		SWAP,
		DUP,
		POP,

		// output
		PRINT,

		// not implemented yet
		CALL,
		RET,
	}

}

@@ -2190,32 +2190,366 @@
 %09%09%7D%0A%09%09%09%09break;%0A%0A
+%09%09%09case CALL:%0A%09%09%09%09push(pcGet() + 1);%0A%09%09%09%09if (intArg != null) %7B%0A%09%09%09%09%09pcSet(intArg);%0A%09%09%09%09%7D else %7B%0A%09%09%09%09%09int newPC = StackProgramVisualiser.parsedCode.getPositionForLabel(strArg);%0A%09%09%09%09%09if (newPC %3C 0) %7B%0A%09%09%09%09%09%09throw new InvalidLabelException(strArg);%0A%09%09%09%09%09%7D%0A%09%09%09%09%09pcSet(newPC);%0A%09%09%09%09%7D%0A%09%09%09%09return;%0A%0A%09%09%09case RET:%0A%09%09%09%09pcSet(pop());%0A%09%09%09%09return;%0A%0A
 %09%09%09case EXIT:%0A%09%09
@@ -3196,32 +3196,107 @@
 ack.peek();%0A%09%7D%0A%0A
+%09private int pcGet() %7B%0A%09%09return StackProgramVisualiser.programCounter;%0A%09%7D%0A%0A
 %09private void pc
@@ -3305,24 +3305,26 @@
 vance() %7B%0A%09%09
+++
 StackProgram
@@ -3348,18 +3348,16 @@
 mCounter
-++
 ;%0A%09%7D%0A%0A%09p
@@ -3552,16 +3552,31 @@
 %0A%09%09JEQ,%0A
+%09%09CALL,%0A%09%09RET,%0A
 %09%09EXIT,%0A
@@ -3647,49 +3647,8 @@
 INT,
-%0A%0A%09%09// not implemented yet%0A%09%09CALL,%0A%09%09RET,
 %0A%09%7D%0A

Implement CALL and RET