/**
 * The MIT License
 * Copyright (c) 2014 Ilkka Seppälä
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.iluwatar.interpreter;

import java.util.Stack;

/**
 * 
 * The Interpreter pattern is a design pattern that specifies how to evaluate sentences in a
 * language. The basic idea is to have a class for each symbol (terminal or nonterminal) in a
 * specialized computer language. The syntax tree of a sentence in the language is an instance of
 * the composite pattern and is used to evaluate (interpret) the sentence for a client.
 * <p>
 * In this example we use the Interpreter pattern to break sentences into expressions (
 * {@link Expression}) that can be evaluated and as a whole form the result.
 * 
 */
public class App {

  /**
   * 
   * Program entry point.
   * <p>
   * Expressions can be evaluated using prefix, infix or postfix notations This sample uses postfix,
   * where operator comes after the operands
   * 
   * @param args command line args
   * 
   */
  public static void main(String[] args) {
    String tokenString = "4 3 2 - 1 + *";
    Stack<Expression> stack = new Stack<>();

    String[] tokenList = tokenString.split(" ");
    for (String s : tokenList) {
      if (isOperator(s)) {
        Expression rightExpression = stack.pop();
        Expression leftExpression = stack.pop();
        System.out.println(String.format("popped from stack left: %d right: %d",
            leftExpression.interpret(), rightExpression.interpret()));
        Expression operator = getOperatorInstance(s, leftExpression, rightExpression);
        System.out.println(String.format("operator: %s", operator));
        int result = operator.interpret();
        NumberExpression resultExpression = new NumberExpression(result);
        stack.push(resultExpression);
        System.out.println(String.format("push result to stack: %d", resultExpression.interpret()));
      } else {
        Expression i = new NumberExpression(s);
        stack.push(i);
        System.out.println(String.format("push to stack: %d", i.interpret()));
      }
    }
    System.out.println(String.format("result: %d", stack.pop().interpret()));
  }

  public static boolean isOperator(String s) {
    return s.equals("+") || s.equals("-") || s.equals("*");
  }

  /**
   * Get expression for string
   */
  public static Expression getOperatorInstance(String s, Expression left, Expression right) {
    switch (s) {
      case "+":
        return new PlusExpression(left, right);
      case "-":
        return new MinusExpression(left, right);
      case "*":
        return new MultiplyExpression(left, right);
      default:
        return new MultiplyExpression(left, right);
    }
  }
}
