package edu.uky.ai.csp.kr;

/**
 * <p>A constraint specifies requirements that any solution to the problem must
 * meet. This is the abstract superclass of all constraints.</p>
 * 
 * <p>For simplicity, we assume that all constraints are binary.</p>
 * 
 * <p>Constraints are not symmetric. In other words, for two variable V1 and V2
 * and some relation *, (V1 * V2) does not imply (V2 * V1).</p> 
 * 
 * @author Stephen G. Ware
 */
public abstract class Constraint {

	/** The left hand side of the constraint */
	public final Variable left;
	
	/** The right hand side of the constraint */
	public final Variable right;
	
	/**
	 * Constructs a new constraint object.
	 * 
	 * @param left the left hand side of the constraint
	 * @param right the right hand side of the constraint
	 */
	public Constraint(Variable left, Variable right) {
		this.left = left;
		this.right = right;
	}
	
	/**
	 * Given a candidate solution and candidate values for the variables in
	 * this constraint, this method checks if the values would violate the
	 * constraint.
	 * 
	 * @param solution the candidate solution, which provides context for the test
	 * @param left the value for the left variable
	 * @param right the value for the right variable
	 * @return false if these values would violate the constraint, true otherwise
	 */
	final boolean test(Solution solution, Object left, Object right) {
		if(!solution.getDomain(this.left).contains(left))
			return false;
		if(!solution.getDomain(this.right).contains(right))
			return false;
		return testValues(solution, left, right);
	}
	
	/**
	 * A helper method for testing values which is defined for each new kind of
	 * constraint.
	 * 
	 * @param solution the candidate solution, which provides context for the test
	 * @param left the value for the left variable
	 * @param right the value for the right variable
	 * @return false if these values would violate the constraint, true otherwise
	 */
	protected abstract boolean testValues(Solution solution, Object left, Object right);
}
