/**
 * PDDL Graph Planner
 * Zeyn Saigol <zeyn@zeyn.net>
 * School of Computer Science
 * University of Birmingham
 *
 * $Id: PredicateEffect.java 32 2007-02-21 16:29:39Z zas $
 */
package uk.ac.bham.cs.zas.pddl.goalseffects;

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

/**
 * Effect that just adds a predicate (or the negation of a predicate).
 */
public class PredicateEffect implements Effect
{
    private final boolean applicable;
    
    private final GoalDesc target; // Must be PredicateHeader or PredicateInstance
    private final boolean value;

    public PredicateEffect(final GoalDesc target, final boolean value) 
    {
        if (!(target instanceof PredicateHeader) && !(target instanceof PredicateInstance)) {
            throw new IllegalArgumentException("Invalid predicate target " + target);
        }
        this.target = target;
        this.value = value;
        applicable = target.isEvaluable();
    }

    public void apply(ConsistentLiteralSet startState,
                      ConsistentLiteralSet endState) 
    {
        if (!applicable) {
            throw new IllegalStateException("Attempt to apply non-evaluable predicate " + target);
        }
        
        endState.addOrReplacePredicate(new PredicateLiteral((PredicateInstance) target, value));
    }

    public Effect instantiate(Map<FormalArgument, PDDLObject> parameters,
                              Set<PDDLObject> objects) 
    {
        if (applicable) {
            return this;
        } else {
            return new PredicateEffect((GoalDesc) target.instantiate(parameters, objects), 
                                       value);
        }
    }
    
    public void getLiteralsUsed(Set<LiteralInstance> resultSet)
    {
        if (!applicable) {
            throw new IllegalStateException("Attempt to get literals used by non-applicable effect");
        }
        target.getLiteralsUsed(resultSet);
    }

    public boolean isEvaluable() {
        return applicable;
    }
    
    public String toString()
    {
        return (value ? "" : "not ") + target;
    }
}
