/*
 * DlpProcessor.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.1 (2007-02-17): initial version
 * v0.1.1 (2007-02-17):
 * - initial implementation inspired by the evolp-prop project
 * v0.9.0 (2007-05-07):
 * - lots of changes :o)
 *
 * TODO docs
 * PENDING create a junit test
 */

package lp.ui;

import java.io.Reader;
import java.util.List;
import lp.parse.DlpParser;
import lp.trans.Consumer;
import lp.trans.DlpGrounder;
import lp.trans.DlpSolver;
import lp.trans.DlpTransformer;
import lp.trans.GrounderMessage;
import lp.unit.DynamicLogicProgram;
import lp.unit.StableModel;
import lp.unit.TransformedDlp;

/**
 * A developer-friendly aggregation of {@link DlpParser}, {@link DlpGrounder},
 * {@link DlpTransformer} and {@link DlpSolver}. 
 *
 * @author Martin Slota
 * @version 0.9.0
 * @see DlpParser
 * @see DlpGrounder
 * @see DlpTransformer
 * @see DlpSolver
 */
public abstract class DlpProcessor extends AbstractProcessor {
	private final DlpParser parser;
	
	private final DlpGrounder grounder;
	
	private final DlpTransformer transformer;
	
	private final DlpSolver solver;
	
	private Reader input;
	
	private DynamicLogicProgram dlp;
	
	private DynamicLogicProgram groundedDlp;
	
	private TransformedDlp transformedDlp;
	
	public DlpProcessor(ConfigManager config) {
		super(config);
		parser = new DlpParser();
		grounder = new DlpGrounder();
		transformer = new DlpTransformer();
		solver = new DlpSolver();
		input = null;
		dlp = null;
		groundedDlp = null;
		transformedDlp = null;
	}
	
	public void setInput(Reader input) {
		this.input = input;
		dlp = null;
		groundedDlp = null;
		transformedDlp = null;
	}
	
	/**
	 *
	 * @throws IllegalArgumentException
	 * @throws IOException
	 * @throws LpParserException
	 */
	public DynamicLogicProgram getDlp() {
		if (dlp == null) {
			getSW().setMessages("Reading input...", "Input parsed in");
			getSW().start();
			parser.setInput(input);
			dlp = parser.parseDlp();
			getSW().stop();
		}
		return dlp;
	}
	
	public DynamicLogicProgram getGroundedDlp() {
		if (groundedDlp == null) {
			// must do before getSW().start(), otherwise messages come out in wrong
			// order
			DynamicLogicProgram tmp = getDlp();
			
			getSW().setMessages("Grounding the DLP...", "Grounding took");
			getSW().start();
			grounder.setLparsePath(getConfig().getProperty("location.lparse"));
			groundedDlp = grounder.ground(tmp);
			getSW().stop();
		}
		return groundedDlp;
	}
	
	public List<GrounderMessage> getGrounderWarnings() {
		return grounder.getWarnings();
	}
	
	public TransformedDlp getTransformedDlp() {
		if (transformedDlp == null) {
			// must do before getSW().start(), otherwise messages come out in wrong
			// order
			DynamicLogicProgram tmp = getGroundedDlp();
			getSW().setMessages("Transforming input...", "Transformation lasted");
			getSW().start();
			transformedDlp = transformer.transform(tmp);
			getSW().stop();
		}
		return transformedDlp;
	}
	
	public void computeModels(Consumer<StableModel> 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);
		
		// must do before getSW().start(), otherwise messages come out in wrong order
		TransformedDlp tmp = getTransformedDlp();
		
		getSW().setMessages("Calling Smodels...",
				"Dynamic 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 dynamic stable model exists");
				break;
			case 1:
				showMessage("1 dynamic stable model computed");
				break;
			default:
				showMessage(n + " dynamic stable models computed");
		}
		
		getSW().stop();
	}
}