package interfaces;

import java.util.EmptyStackException;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
import java.util.function.BinaryOperator;

public class RPNCalc {
  // Using stack instead of Deque in order to get access to elementAt(i)
  private Stack<Double> stack = new Stack<>();
  private Map<Character, BinaryOperator<Double>> operators = new HashMap<>();

  public void push(double num) {
    this.stack.push(num);
  }

  public double pop() {
    try {
      return this.stack.pop();
    } catch (EmptyStackException e) {
      return Double.NaN;
    }
  }

  public double peek(int i) {
    return this.getSize() >= (i + 1) && i >= 0
         ? this.stack.elementAt(this.getSize() - 1 - i)
         : Double.NaN;
  }

  public int getSize() {
    return this.stack.size();
  }

  public boolean addOperator(char op, BinaryOperator<Double> opFunc) {
    if (this.operators.get(op) != null)
      return false;

    this.operators.put(op, opFunc);
    return true;
  }

  public void removeOperator(char op) {
    this.operators.remove(op);
  }

  public void performOperation(char op)
    throws UnsupportedOperationException, IllegalArgumentException {

    if (this.operators.get(op) == null)
      throw new UnsupportedOperationException("Operator " + op + " does not exist");

    double a, b;
    try {
      a = this.stack.pop();
      b = this.stack.pop();
    } catch (EmptyStackException e) {
      throw new IllegalArgumentException("Not enough numbers in the calculator");
    }

    this.stack.push(this.operators.get(op).apply(b, a));
  }
}