/*
 * EvolpProcessor.java
 *
 * Copyright (C) 2006 - 2007 Martin Slota
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 51
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/*
 * History:
 * v0.9.0 (2007-05-07):
 * - no version information kept before :o)
 *
 * TODO docs
 * PENDING create a junit test
 */

package lp.ui;

import java.io.Reader;
import lp.parse.EvolpParser;
import lp.trans.Consumer;
import lp.trans.EvolpSolver;
import lp.trans.EvolpTransformer;
import lp.unit.EvolpProgram;
import lp.unit.EvolutionStableModel;
import lp.unit.TransformedEvolp;

/**
 * A developer-friendly aggregation of {@link EvolpParser},
 * {@link EvolpTransformer} and {@link EvolpSolver}.
 *
 * @author Martin Slota
 * @version 0.9.0
 * @see EvolpParser
 * @see EvolpTransformer
 * @see EvolpSolver
 */
public abstract class EvolpProcessor extends AbstractProcessor {
	private final EvolpParser parser;
	
	private final EvolpTransformer transformer;
	
	private final EvolpSolver solver;
	
	private Reader input;
	
	private EvolpProgram evolp;
	
	private TransformedEvolp transformedEvolp;
	
	public EvolpProcessor(ConfigManager config) {
		super(config);
		parser = new EvolpParser();
		transformer = new EvolpTransformer();
		solver = new EvolpSolver();
		input = null;
		evolp = null;
		transformedEvolp = null;
	}
	
	public void setInput(Reader input) {
		this.input = input;
		evolp = null;
		transformedEvolp = null;
	}
	
	/**
	 *
	 * @throws IllegalArgumentException
	 * @throws IOException
	 * @throws LpParserException
	 */
	protected EvolpProgram getEvolp() {
		if (evolp == null) {
			transformedEvolp = null;
			getSW().setMessages("Reading input...", "Input parsed in");
			getSW().start();
			parser.setInput(input);
			evolp = parser.parseEvolp();
			getSW().stop();
		}
		return evolp;
	}
	
	protected TransformedEvolp getTransformedEvolp() {
		if (transformedEvolp == null) {
			// must do before getSW().start(), otherwise messages come out in wrong
			// order
			EvolpProgram tmp = getEvolp();
			getSW().setMessages("Transforming input...", "Transformation lasted");
			getSW().start();
			transformedEvolp = transformer.transform(tmp);
			getSW().stop();
		}
		return transformedEvolp;
	}
	
	protected void computeModels(Consumer<EvolutionStableModel> processor) {
		int maxModels;
		try {
			maxModels = Integer.parseInt(getConfig().getProperty("maxModels"));
		} catch (NumberFormatException e) {
			maxModels = 0;
		}
		
		solver.setLparsePath(getConfig().getProperty("location.lparse"));
		solver.setSmodelsPath(getConfig().getProperty("location.smodels"));
		solver.setModelLimit(maxModels);
		solver.setModelLength(getEvolp().getEvents().size());
		
		// must do before getSW().start(), otherwise messages come out in wrong order
		TransformedEvolp tmp = getTransformedEvolp();
		
		getSW().setMessages("Calling Smodels...",
				"Evolution stable models computed in");
		getSW().start();
		processor.beforeConsuming();
		try {
			solver.solve(tmp, processor);
		} finally {
			processor.afterConsuming();
		}
		int n = solver.getModelCount();
		switch (n) {
			case 0:
				showMessage("No evolution stable model exists");
				break;
			case 1:
				showMessage("1 evolution stable model computed");
				break;
			default:
				showMessage(n + " evolution stable models computed");
		}
		
		getSW().stop();
	}
}