package edu.unl.consystlab.sudokuSolver.consistencyAlgorithms;


import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import edu.unl.consystlab.sudokuSolver.constraintProblem;
import edu.unl.consystlab.sudokuSolver.problemConstraint;
import edu.unl.consystlab.sudokuSolver.problemVariable;
import edu.unl.consystlab.sudokuSolver.sudokuBoard;
import edu.unl.consystlab.sudokuSolver.variableIndexAndValueGrouping;

public class shavingGAC extends consistencyAlgorithm {

	private nonBinaryMAC myNonBinaryMAC;
	
	public shavingGAC(constraintProblem newProblem, sudokuBoard board) {
		super(newProblem, board);
		myNonBinaryMAC = new nonBinaryMAC(newProblem, board);
		//shaving should never break a constraint
		brokenConstraint = null;
		setEncounteredError(false);
	}

	//always returns true because it never breaks a constraint
	public boolean runAlgorithm() throws InterruptedException
    {
		//collect every variable
		// take a variable
		// assign it a value
		// run mac, if there is no error leave the value
		// if there is an error remove the value
		// move to the next value
		// move to the next variable

		variableReductions = new LinkedList();
		boolean runAgain = true;

		
		while(runAgain)
		{
			Iterator i = ((Collection)parentProblem.getAllVariables()).iterator();
            runAgain = false;
			while(i.hasNext())
			{
				problemVariable currentVariable = (problemVariable)i.next();
				//if it is assigned then there is no shaving to do
				if(!currentVariable.isAssigned())
				{
					List originalDomain = new LinkedList(currentVariable.getEntireDomain());
					Iterator j = originalDomain.iterator();
					while(j.hasNext())
					{
                        if(Thread.interrupted())
                        {
                            throw new InterruptedException();
                        }
						String currentValue = (String)j.next();
						List tempDomain = new LinkedList(currentVariable.getEntireDomain());
						currentVariable.setAssigned(currentValue);
						//run GAC
						if(!myNonBinaryMAC.runAlgorithm())
						{
							//remove it from the domain
							tempDomain.remove(currentValue);
							runAgain = true;
							//keep track of all the values removed here because we can't trust the problem itself
							// since non binary arc consistency removes a lot of variables that come back
							variableIndexAndValueGrouping myReduction = new variableIndexAndValueGrouping(currentVariable.getIndex(), currentValue);
							variableReductions.add(myReduction);
						}
		
						//undo Assignment
						currentVariable.unSetAssigned();
						currentVariable.setCurrentDomain(tempDomain);
						//undo GAC
						Iterator k = myNonBinaryMAC.getVariableReductions().iterator();
						while(k.hasNext())
						{
							variableIndexAndValueGrouping currentReduction = (variableIndexAndValueGrouping)k.next();
							parentProblem.getVariable(currentReduction.getVariableIndex()).addToCurrentDomain(currentReduction.getValue());
						}
						
						//check to see if a variable's domain is squashed.
						if(tempDomain.size() == 0)
						{
							//just pick the first arc consistent constraint to make broken
							brokenConstraint = (problemConstraint)currentVariable.getNonBinaryIntensiveConstraints().get(0);
							setEncounteredError(true);
							return false;								
						}
					}
				}
			}
		}
		
		return true;
	}
	
}
