/**************************************************************************
  * MiniPro: Interpreter for a miniature programming language.
  * 
  * COS 126, Princeton University, Fall 2013, Programming Midterm 2 Part 1
  * 
  * Dependencies: ST, StdOut
  * 
  * Compilation: javac-introcs MiniPro.java
  * 
  * Execution:
  * % java-introcs MiniPro
  * false
  * 0
  * currently x is 13
  * 39
  * 13
  * true
  **************************************************************************/

public class MiniPro {
    private int pc;                       // the program counter
    private String[][] program;           // the program itself
    private ST<String, Integer> varTable; // values of all defined variables
    
    // Create interpreter for this program. Don't execute it yet!
    public MiniPro(String[][] program) {
        this.program = program;
        pc = 0; // line 0 is always the first to execute
        varTable = new ST<String, Integer>();
    }

    // Return the current value of the variable named v. If no
    // such variable is currently defined, throw a RuntimeException.
    public int valueOf(String v) {
        if (!varTable.contains(v))
            throw new RuntimeException("Variable named " + v + " not defined");
        return varTable.get(v);
    }

    // Return the number of the line that will execute next.
    public int programCounter() {
        return pc;
    }

    // Execute the line whose number equals the value of the
    // program counter. Then, increment the program counter.
    public void step() {
        String[] line = program[pc]; // current line (1d piece of 2d array)
        String command = line[1]; 

        // assignment statement
        if (command.equals("=")) {
            // look at token on right-hand side, evaluate it
            String rhsToken = line[2];
            int rhsValue;
            
            if (rhsToken.matches("[a-z]+"))       // it's a variable name
                rhsValue = varTable.get(rhsToken);
            else                                  // it's an integer
                rhsValue = Integer.parseInt(rhsToken);
            
            // save value in variable
            varTable.put(line[0], rhsValue);
        }
        
        // println statement
        else if (command.equals("println")) {
            // get value of desired variable, then print it
            int value = varTable.get(line[0]);
            StdOut.println(value);
        }
        
        // increment the program counter
        pc++;
    }

    // Is the program done?
    public boolean isDone() {
        return pc == program.length;
    }

 /*************************
  * sample test main for COS 126 F13 Midterm 2 (MiniPro, part 1)
  *************************/
    public static void main(String[] args) {

        // the program in a format ready for the interpreter:
        String[][] sampleProgram =  
            {{"x", "=", "13"},     // line 0
             {"y", "=", "x"},      // line 1
             {"x", "=", "39"},     // line 2
             {"x", "println"},     // line 3
             {"y", "println"}};    // line 4
        
        MiniPro mp = new MiniPro(sampleProgram);
        StdOut.println(mp.isDone());         // false 
        StdOut.println(mp.programCounter()); // 0 (always start w/ line 0)
        
        // run thru program
        mp.step();                          // line 0 sets x = 13
        // next command prints: currently x is 13
        StdOut.println("currently x is " + mp.valueOf("x")); 
        mp.step();                          // line 1 sets y = 13
        mp.step();                          // line 2 sets x = 39
        mp.step();                          // line 3 prints x value, 39
        mp.step();                          // line 4 prints y value, 13
        
        StdOut.println(mp.isDone());        // true (program is finished)
    }
}