/**
 * <copyright>
 * Copyright (c) 2010-2014 Henshin developers. All rights reserved. 
 * This program and the accompanying materials are made available 
 * under the terms of the Eclipse Public License v1.0 which 
 * accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * </copyright>
 */
package org.eclipse.emf.henshin.interpreter.matching.constraints;

import java.util.Map;

import org.eclipse.emf.henshin.interpreter.ApplicationMonitor;
import org.eclipse.emf.henshin.interpreter.EGraph;
import org.eclipse.emf.henshin.interpreter.matching.conditions.ApplicationCondition;
import org.eclipse.emf.henshin.interpreter.matching.conditions.ConditionHandler;

/**
 * Solution finder. This is the internal realization of the match finder.
 * 
 * @author Enrico Biermann, Christian Krause
 */
public class SolutionFinder extends ApplicationCondition {
	
	// Attribute condition handler:
	protected final ConditionHandler conditionHandler;

	// Started flag:
	protected boolean started;
	
	// Next solution:
	protected Solution nextSolution;
		
	/**
	 * Default constructor.
	 * @param graph Target graph.
	 * @param variableDomainMap Variable domain map.
	 * @param conditionHandler Attribute condition handler.
	 * @param monitor Monitor to collect performance data
	 */
	public SolutionFinder(EGraph graph, 
			Map<Variable, DomainSlot> variableDomainMap,
			ConditionHandler conditionHandler,ApplicationMonitor monitor) {
		super(graph, variableDomainMap,monitor); //added monitor
		this.conditionHandler = conditionHandler;
		this.started = false;
	}
	
	/**
	 * Find a new solution.
	 * @return <code>true</code> if a new solution was found.
	 */
	public boolean findSolution() {
		
		boolean matchIsPossible = false;
		if (!started) {
			started = true;
			matchIsPossible = true;
		} else {
			int varCount = variables.size();
			for (int i=varCount-1; i>=0; i--) {
				Variable var = variables.get(i);
				if (domainMap.get(var).unlock(var)) {
					matchIsPossible = true;
					break;
				} else {
					domainMap.get(var).clear(var);
				}
			}
		}
		
		if (matchIsPossible) {
			boolean success = findGraph();
			if (success) {
				nextSolution = new Solution(variables, domainMap, conditionHandler);
			}
			return success;
		}
		
		// No solution found.
		return false;
		
	}
	
	/**
	 * Returns the next solution. On consecutive calls other matches will be returned.
	 * @return A solution or <code>null</code> if no match exists.
	 */
	public Solution getNextSolution() {
		if (findSolution()) {
			return nextSolution;
		}
		return null;
	}
	
}
