package edu.uky.ai.csp.kr;

import java.util.ArrayList;
import java.util.LinkedHashMap;

/**
 * A constraint satisfaction problem is composed of variables (each with a set
 * of potential values called a domain) and constraints on the values those
 * variable can be assigned.
 * 
 * @author Stephen G. Ware
 */
public class Problem {

	/** A mapping of variables to their domains in the initial state of the problem */
	private final LinkedHashMap<Variable, Domain> _variables = new LinkedHashMap<>();
	
	/** A set of all the variables defined for this problem */
	public final Iterable<Variable> variables = _variables.keySet();
	
	/** A set of all the constraints that a solution to this problem must meet */
	public final Iterable<Constraint> constraints = new ArrayList<>();
	
	/**
	 * Defines a new variable, along with all the possible values it can be
	 * assigned, for this problem.
	 * 
	 * @param variable the new variable to be defined
	 * @param domain the possible values that variable can be assigned
	 */
	public void addVariable(Variable variable, Domain domain) {
		this._variables.put(variable, domain.clone());
	}
	
	/**
	 * Returns the set of possible values that a given variable can be assigned
	 * in the initial state of this problem.
	 * 
	 * @param variable the variable
	 * @return the domain of that varaible in the initial state of the problem
	 */
	public Domain getDomain(Variable variable) {
		if(!_variables.containsKey(variable))
			throw new IllegalArgumentException("Variable " + variable + " not defined");
		return _variables.get(variable);
	}
	
	/**
	 * Adds a new constraint to the problem.
	 * 
	 * @param constraint the constraint
	 */
	public void addConstraint(Constraint constraint) {
		((ArrayList<Constraint>) constraints).add(constraint);
	}
	
	/**
	 * Returns a problem-specific string representation of a potential solution.
	 * 
	 * @param solution the solution to be rendered as a string
	 * @return a string
	 */
	public String toString(Solution solution) {
		String str = "";
		for(Variable variable : variables)
			str += solution.getDomain(variable) + "\n";
		return str.trim();
	}
}
