/**
 * PDDL Graph Planner
 * Zeyn Saigol <zeyn@zeyn.net>
 * School of Computer Science
 * University of Birmingham
 *
 * $Id: ComparisonGoalDesc.java 33 2007-02-23 15:45:34Z zas $
 */
package uk.ac.bham.cs.zas.pddl.goalseffects;

import java.util.*;
import uk.ac.bham.cs.zas.pddl.domain.*;

/**
 * Binary comparison goal. Available operators are '>', '<', '=', '>=', and '<='.
 */
public class ComparisonGoalDesc implements GoalDesc
{
    private final boolean evaluable;
    
    // binaryComp : '>' | '<' | '=' | '>=' | '<=' ;
    private final String operator;
    private final NumericExpr firstOperand;
    private final NumericExpr secondOperand;
    
    public ComparisonGoalDesc(final String operator, final NumericExpr firstOperand, final NumericExpr secondOperand) {
        if (!">".equals(operator) && !"<".equals(operator) 
                && !"=".equals(operator) && !">=".equals(operator) && !"<=".equals(operator)) {
            throw new IllegalArgumentException("Unknown operator '" + operator + "'");
        }
        this.operator = operator;
        this.firstOperand = firstOperand;
        this.secondOperand = secondOperand;
        
        evaluable = (firstOperand.isEvaluable() && secondOperand.isEvaluable());
    }

    public boolean isEvaluable() {
        return evaluable;
    }
    
    public GoalDesc instantiate(Map<FormalArgument, PDDLObject> parameters, Set<PDDLObject> objects) {
        if (evaluable) {
            return this;
        } else {
            return new ComparisonGoalDesc(operator, 
                    (NumericExpr) firstOperand.instantiate(parameters, objects),
                    (NumericExpr) secondOperand.instantiate(parameters, objects));
        }
    }
    
    /* (non-Javadoc)
     * @see uk.ac.bham.cs.zas.pddl.domain.GoalDesc#evaluate()
     */
    public boolean evaluate(ConsistentLiteralSet literals) {
        if (">".equals(operator)) {
            return firstOperand.evaluate(literals) > secondOperand.evaluate(literals);
            
        } else if ("<".equals(operator)) {
            return  firstOperand.evaluate(literals) < secondOperand.evaluate(literals);
            
        } else if ("=".equals(operator)) {
            return firstOperand.evaluate(literals) == secondOperand.evaluate(literals);
            
        } else if (">=".equals(operator)) {
            return firstOperand.evaluate(literals) >= secondOperand.evaluate(literals);
            
        } else if ("<=".equals(operator)) {
            return firstOperand.evaluate(literals) <= secondOperand.evaluate(literals);
        
        } else {
            throw new IllegalStateException("Illegal operator " + operator);
        }
    }
    
    public void getLiteralsUsed(Set<LiteralInstance> resultSet)
    {
        if (!evaluable) {
            throw new IllegalStateException("Attempt to get literals used by non-evaluable goal desc");
        }
        firstOperand.getLiteralsUsed(resultSet);
        secondOperand.getLiteralsUsed(resultSet);
    }
    
    public String toString()
    {
        return firstOperand + " " + operator + " " + secondOperand;
    }
}
