package edu.unl.consystlab.sudokuConstructor.consistencyAlgorithms;

import edu.unl.consystlab.sudokuSolver.constraintProblem;
import edu.unl.consystlab.sudokuSolver.graphNode;
import edu.unl.consystlab.sudokuSolver.nonBinaryIntensiveConstraint;
import edu.unl.consystlab.sudokuSolver.problemVariable;

import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

public class nonBinaryMAC extends consistencyAlgorithm {

	public nonBinaryMAC(constraintProblem newProblem) {
		super(newProblem);
	}

	
	//returns true if it doesn't hit an error,
	//returns false if it does encounter an error
	public boolean runAlgorithm()
	{
		//1.Put all of the constraints into a set to avoid duplicates
		//2. Run MAC on the first one.
		//3. Take the list of reductions and add back other constraints connected
		// to those variables
		//4. keep looping to 1.
		
		variableReductions = new LinkedList();
		parentProblem.registerDomainReductionListener(variableReductions);
		
		Set myConstraintList;// = new HashSet();
		//1.Put all of the constraints into a set to avoid duplicates
		myConstraintList = new HashSet(parentProblem.getAllNonBinaryIntensiveConstraints());

		while(!myConstraintList.isEmpty())
		{
			//don't remove it now so that it doesn't get added back.
			nonBinaryIntensiveConstraint topConstraint = (nonBinaryIntensiveConstraint)(myConstraintList.iterator().next());
			
			//2. Run MAC on the first one.
			List removedValueVariablePairs = topConstraint.updateGraph();
			
			//if removedValueVariablePairs is null there was an error
			if(removedValueVariablePairs == null)
			{
				brokenConstraint = topConstraint;
				parentProblem.unregisterDomainReductionList(variableReductions);
				setEncounteredError(true);
				return false;
			}
			
			//3. Take the list of reductions and add back other constraints connected
			while(!removedValueVariablePairs.isEmpty())
			{
				List topVariableValuePair = (LinkedList)removedValueVariablePairs.get(0);
				removedValueVariablePairs.remove(0);
				
				if( ((graphNode)topVariableValuePair.get(0)).isVariable() )
				{
					//add back constraints
					List changedConstraints = (((problemVariable)((graphNode)topVariableValuePair.get(0)).getVariable()).getNonBinaryIntensiveConstraints());
					Iterator i = changedConstraints.iterator();
					while(i.hasNext())
					{
						myConstraintList.add(i.next());
					}
				}
				else
				{
					//add back constraints
					List changedConstraints = (((problemVariable)((graphNode)topVariableValuePair.get(1)).getVariable()).getNonBinaryIntensiveConstraints());
					Iterator i = changedConstraints.iterator();
					while(i.hasNext())
					{
						myConstraintList.add(i.next());
					}
				}
			}
			
			//now remove it
			myConstraintList.remove(topConstraint);
			
		}
		brokenConstraint = null;
		parentProblem.unregisterDomainReductionList(variableReductions);
		setEncounteredError(false);
		return true;
	}
}
