package edu.unl.consystlab.sudokuSolver.consistencyAlgorithms;

import java.util.LinkedList;
import java.util.List;

import edu.unl.consystlab.sudokuSolver.binaryIntensiveConstraint;
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 binaryForwardCheckOnVariable extends consistencyAlgorithm {

	private problemVariable masterVariable;
	
	public binaryForwardCheckOnVariable(constraintProblem newProblem, sudokuBoard board, problemVariable newMasterVariable) {
		super(newProblem, board);
		masterVariable = newMasterVariable;
	}

	public boolean runAlgorithm()
	{
		String masterVariableIndex = masterVariable.getIndex();
		List variablesReduced = new LinkedList();
		List constraints = masterVariable.getBinaryConstraints();
		List constraintScope;
		String variableToReduceIndex;
		//boolean boolConsistent = true;
		
		String masterVariableValue;
		if(masterVariable.isAssigned())
		{
			masterVariableValue = masterVariable.getAssigned();
		}
		//you actually only forward check on values that are assigned
		else if(masterVariable.getCurrentDomainSize() == 1)
		{
			brokenConstraint = null;
			setEncounteredError(false);
			return(true);
			//masterVariableValue = masterVariable.getCurrentDomainFirstValue();
		}
		else if(masterVariable.getCurrentDomainSize() > 1)
		{
			brokenConstraint = null;
			setEncounteredError(false);
			return(true);	
		}
		else  //if it is 0 then it will encounter an error later
			
		{
			masterVariableValue = null;
		}
		parentProblem.registerDomainReductionListener(variableReductions);
		
		//go through every constraint
		for(int i=0; i < constraints.size(); i++)
		{
			//take the scope of every constraint that the master variable is involved in
			constraintScope = (LinkedList)((problemConstraint)constraints.get(i)).getScope();
			//only take the variable that is not the current one.

			int scopeIndex =0;
			do{
				variableToReduceIndex = ((problemVariable)constraintScope.get(scopeIndex)).getIndex();
				scopeIndex++;
			}while(variableToReduceIndex.compareTo(masterVariableIndex) == 0);

			//make sure the constraint is not already broken
			if(!((binaryIntensiveConstraint)constraints.get(i)).isViolated())
			{
				//check every value in the variableToReduces' domain for consistency with
				//the current variable
				List variableToReduceDomain = (parentProblem.getVariable(variableToReduceIndex)).getEntireDomain();
				for(int domainIndex = variableToReduceDomain.size() -1; domainIndex >=0; domainIndex--)
				{
					//if it is not consistent
					if(!((binaryIntensiveConstraint)constraints.get(i)).check(
							(String)variableToReduceDomain.get(domainIndex), masterVariableValue))
					{
						//remove this variable's value from the current domain
						(parentProblem.getVariable(variableToReduceIndex)).removeFromCurrentDomain(
								(String)variableToReduceDomain.get(domainIndex));
						
						//if it leaves nothing left in the domain make it inconsistent.
						if(parentProblem.getVariable(variableToReduceIndex).getCurrentDomainSize() == 0)
						{
							brokenConstraint = (binaryIntensiveConstraint)constraints.get(i);
							//there is an interesting little problem when running binaryForwardCheckAll:
								//its variablereduction will equal this variable reduction so we may delete the wrong one
								//to prevent this we will add an element to make it unique, then unregister it then delete the element.
							variableReductions.add("deleteme");
							parentProblem.unregisterDomainReductionList(variableReductions);
							variableReductions.remove("deleteme");
							setEncounteredError(true);
							return false;
						}
					}
				}
			}
			else
			{
				//the constraint was already broken
				brokenConstraint = (binaryIntensiveConstraint)constraints.get(i);
				variableReductions.add("deleteme");
				parentProblem.unregisterDomainReductionList(variableReductions);
				variableReductions.remove("deleteme");
				setEncounteredError(true);
				return false;
			}
		}

		brokenConstraint = null;
		variableReductions.add("deleteme");
		parentProblem.unregisterDomainReductionList(variableReductions);
		variableReductions.remove("deleteme");
		setEncounteredError(false);
		return(true);
	}
}
