package code.instr;

import code.space.Computation;
import code.space.Space;
import code.stuff.Logger;
import code.stuff.Tracer;
import code.symbols.DataSymbol;
import code.term.Term;

/**
 * Execute a <I>goto</I> -like instruction of the virtual machine code. This
 * instruction tests the root symbol of the register of the virtual machine.
 * The next instruction to be executed depends on whether the root symbol is a
 * variable, a defined operation or a data constructor.
 *
 * @author Sergio Antoy
 * @since June 17, 2003
 */

public class Branch implements Instruction {

    private final Instruction[][] dispatch;

    /**
     * Constructor for the Branch object
     *
     * @param dispatch An array of arrays of instructions.  Either (1)
     * one of the nested array of instructions will be executed
     * depending on the root symbol of the term contained in the
     * register (current) of the virtual machine, or (2) if the root
     * symbol is an operation, the term in the register must be
     * evaluated instead.
     */
    public Branch(Instruction[][] dispatch) { this.dispatch = dispatch; }


    public void execute(Computation computation) {
        Term current = Space.instance.current;
        if (Tracer.instruction) {
            Logger.logln(computation.getIdString() + ": Branch: " + current);
        }
        byte kind = current.getKind();
        switch (kind) {
            case DataSymbol.UnboundVariable:
                computation.execute(dispatch[0]);
                break;
            case DataSymbol.Operation:
                computation.push(current);
                break;
            default:
		try {
		    // kind is the constructor number
		    computation.execute(dispatch[kind]);
		} catch (java.lang.ArrayIndexOutOfBoundsException ex) {
		    System.err.println("Branch error on "+current+
				       " kind="+kind);
		    System.err.println("This is due to incorrectly compiled bytecode or an internal error");
		    System.err.println("Please inform the developers <antoy@cs.pdx.edu>");
		    printAsTxtLoadable();
		    computation.stackDebug();		    
		    throw ex;
		}
                break;
        }
    }

    /**
     * data to help the PrintAsTxtLoadable method.
     */
    private static int numSpace = 1;

    public String printAsTxtLoadable() {
        StringBuffer sb = new StringBuffer() ;
        sb.append ("Branch\n" + indent()+ "{\n") ;
        ++numSpace;
        for (int i = 0; i < dispatch.length; ++i) {
            sb.append( indent() + "{\n" ) ;
            ++numSpace;
            for (int j = 0; j < dispatch[i].length; ++j) {
                sb.append( indent() + dispatch[i][j].printAsTxtLoadable() + "\n") ;
            }
            --numSpace;
            sb.append( indent() + "}\n");
        }
        --numSpace;
        sb.append(indent() + "}");

        return sb.toString();
    }

    private String indent() {
        String form;
        int k;
        for (form = "", k = 0; k < numSpace; ++k)
            form = form + " ";
	return form;
    }

    // I should really just have this return an iterator for all of
    // the instructions contained in dispatch to keep coupling down.
    public Instruction[][] getDispatch() {
        return dispatch;
    }

}
