package org.nfunk.jep;

import java.util.Stack;
import java.util.Vector;
import org.nfunk.jep.function.PostfixMathCommandI;
import org.nfunk.jep.function.SpecialEvaluationI;

public class EvaluatorVisitor implements ParserVisitor {
  protected Stack stack = new Stack();
  
  protected Vector errorList = null;
  
  protected SymbolTable symTab = null;
  
  protected boolean errorFlag;
  
  private static final boolean debug = false;
  
  protected void addToErrorList(String paramString) {
    if (this.errorList != null)
      this.errorList.addElement(paramString); 
  }
  
  public Object getValue(Node paramNode, Vector paramVector, SymbolTable paramSymbolTable) throws Exception {
    if (paramNode == null)
      throw new IllegalArgumentException("topNode parameter is null"); 
    this.errorList = paramVector;
    this.symTab = paramSymbolTable;
    this.errorFlag = false;
    this.stack.removeAllElements();
    try {
      paramNode.jjtAccept(this, null);
    } catch (ParseException parseException) {
      addToErrorList(parseException.getMessage());
      throw parseException;
    } 
    if (this.errorFlag || this.stack.size() != 1)
      throw new Exception("EvaluatorVisitor.getValue(): Error during evaluation"); 
    return this.stack.pop();
  }
  
  public Object visit(SimpleNode paramSimpleNode, Object paramObject) throws ParseException {
    throw new ParseException("No visit method for " + paramSimpleNode.getClass().toString());
  }
  
  public Object visit(ASTStart paramASTStart, Object paramObject) throws ParseException {
    throw new ParseException("Start node encountered during evaluation");
  }
  
  public Object visit(ASTFunNode paramASTFunNode, Object paramObject) throws ParseException {
    if (paramASTFunNode == null)
      return null; 
    PostfixMathCommandI postfixMathCommandI = paramASTFunNode.getPFMC();
    if (postfixMathCommandI == null)
      throw new ParseException("No function class associated with " + paramASTFunNode.getName()); 
    if (postfixMathCommandI instanceof SpecialEvaluationI)
      return ((SpecialEvaluationI)paramASTFunNode.getPFMC()).evaluate(paramASTFunNode, paramObject, this, this.stack); 
    paramObject = paramASTFunNode.childrenAccept(this, paramObject);
    if (postfixMathCommandI.getNumberOfParameters() == -1)
      postfixMathCommandI.setCurNumberOfParameters(paramASTFunNode.jjtGetNumChildren()); 
    postfixMathCommandI.run(this.stack);
    return paramObject;
  }
  
  public Object visit(ASTVarNode paramASTVarNode, Object paramObject) throws ParseException {
    Variable variable = paramASTVarNode.getVar();
    if (variable == null) {
      String str = "Could not evaluate " + paramASTVarNode.getName() + ": ";
      throw new ParseException(str + " variable not set");
    } 
    Object object = variable.getValue();
    if (object == null) {
      String str = "Could not evaluate " + paramASTVarNode.getName() + ": ";
      throw new ParseException(str + "the variable was not found in the symbol table");
    } 
    this.stack.push(object);
    return paramObject;
  }
  
  public Object visit(ASTConstant paramASTConstant, Object paramObject) {
    this.stack.push(paramASTConstant.getValue());
    return paramObject;
  }
}
