package formulaVisited;


/**
  A visitor that evaluates each formula, returning
  Boolean.TRUE  if the formula is true,
  Boolean.FALSE if the formula is false, and
  null if its value cannot be determined.
  The presence of undefined logical values,
  or predicates whose value is not defined
  for every domain entity,
  can result in formulas whose logical values
  that cannot be determined.
*/
public class VisitorEvaluate implements Visitor {

  Environment env;
  /**
    Construct a VisitorEvaluate that evaluates formulas
    in the given environment.
    @param _env The environment.
  */
  public VisitorEvaluate(Environment _env) {
    env = _env;
  }

  /**
    {@inheritDoc}
    A conjunction is true if both its subformulas are true,
    false if either of its subformulas is false,
    and unknown otherwise.
  */
  public Object visit(Conjunction _f) {
    Boolean leftValue  = (Boolean) _f.left .accept(this);
    Boolean rightValue = (Boolean) _f.right.accept(this);
    if /**/ (!leftValue .booleanValue()) {
      return Boolean.FALSE;
    }
    else if (!rightValue.booleanValue()) {
      return Boolean.FALSE;
    }
    else if ( leftValue .booleanValue() &&
              rightValue.booleanValue()) {
      return Boolean.TRUE;
    }
    else {
      return null;
    }
  }

  /**
    {@inheritDoc}
    A disjunction is false if both its subformulas are false,
    true if either of its subformulas is true,
    and unknown otherwise.
  */
  public Object visit(Disjunction _f) {
    Boolean leftValue  = (Boolean) _f.left .accept(this);
    Boolean rightValue = (Boolean) _f.right.accept(this);
    if /**/ ( leftValue .booleanValue()) {
      return Boolean.TRUE;
    }
    else if ( rightValue.booleanValue()) {
      return Boolean.TRUE;
    }
    else if (!leftValue .booleanValue() &&
             !rightValue.booleanValue()) {
      return Boolean.FALSE;
    }
    else {
      return null;
    }
  }

  /**
    {@inheritDoc}
    The value of
    {@link LogicalConstant#one  LogicalConstant.one() }
    is true, and
    the value of
    {@link LogicalConstant#zero LogicalConstant.zero()}
    is false.
  */
  public Object visit(LogicalConstant _f) {
    if (LogicalConstant.one().equals(_f)) {
      return "1";
    }
    else {
      return "0";
    }
  }

  /**
    {@inheritDoc}
    The value of a logical variable is
    the value the variable is bound to in the environment,
    and unknown if the variable is bound to no value.
    The environment used is the one with which this visitor
    was constructed.
  */
  public Object visit(LogicalVariable _f) {
    return env.get(_f);
  }

  /**
    {@inheritDoc}
    A negation is false if its subformula is true,
    false if its subformula is true,
    and unknown if its subformula's value is unknown.
  */
  public Object visit(Negation _f) {
    Boolean subformulaValue =
        (Boolean) _f.subformula.accept(this);
    if /**/ (null == subformulaValue) {
      return null;
    }
    else if (subformulaValue.booleanValue()) {
      return Boolean.FALSE;
    }
    else {
      return Boolean.TRUE;
    }
  }

}
