/*
 * EvolpWebappHelper.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.io.Writer;

import java.util.Iterator;

import javax.servlet.jsp.JspWriter;

import lp.struct.LpAtom;
import lp.struct.LpPredicate;
import lp.struct.LpRule;
import lp.struct.util.LpHtmlPrinter;

import lp.trans.Consumer;

import lp.unit.EvolpProgram;
import lp.unit.EvolutionStableModel;
import lp.unit.StableModel;
import lp.unit.TransEvolpRuleType;
import lp.unit.TransformedEvolp;

/**
 * A helper class for the web application that computes evolution stable models
 * of propositional evolving logic programs
 *
 * @author Martin Slota
 * @version 0.9.0
 */
public class EvolpWebappHelper extends EvolpProcessor {
	private final JspPrinter printer;
	
	private final TransEvolpHtmlPrinter<Writer> transPrinter;
	
	private final EvolpModelProcessor processor;
	
	private boolean error;
	
	public EvolpWebappHelper(ConfigManager config, JspWriter out) {
		super(config);
		printer = new JspPrinter(out);
		transPrinter = new TransEvolpHtmlPrinter<Writer>(out);
		processor = new EvolpModelProcessor();
		error = false;
	}
	
	@Override
	public void setInput(Reader input) {
		super.setInput(input);
		error = false;
	}
	
	protected void showMessage(String message) {
		printer.showMessage(message);
	}
	
	public boolean isError() {
		return error;
	}
	
	protected void showError(String comment, Exception e) {
		printer.showError(comment, e);
		error = true;
	}
	
	public void writeEvolp() {
		if (!error) {
			try {
				EvolpProgram tmp = getEvolp();
				if (!error) {
					printer.append("<div class=\"code\">\n");
					printer.append(tmp);
					printer.append("</div>\n\n");
				}
			} catch (Exception e) {
				showError("Couldn't parse input program!", e);
			}
		}
	}
	
	public void writeTransformedEvolp() {
		if (!error) {
			try {
				TransformedEvolp tmp = getTransformedEvolp();
				if (!error) {
					transPrinter.append("<div class=\"code\">\n");
					transPrinter.append(tmp);
					transPrinter.append("</div>\n");
				}
			} catch (Exception e) {
				showError("Couldn't transform the input program!", e);
			}
		}
	}
	
	public void writeModels() {
		if (!error) {
			try {
				chmod("location.lparse");
				chmod("location.smodels");
				computeModels(processor);
			} catch (Exception e) {
				showError("Couldn't compute the stable models!", e);
			}
		}
	}
	
	private class TransEvolpHtmlPrinter<W extends Writer>
			extends LpHtmlPrinter<W> {
		public TransEvolpHtmlPrinter(W out) {
			super(out, ":-", true);
		}
		
		public void append(TransformedEvolp transEvolp) {
			for (int group = 1; group <= transEvolp.getMaxGroup(); group++) {
				for (TransEvolpRuleType t : TransEvolpRuleType.values()) {
					append("<div class=\"ruleGroup\">\n");
					append("<p class=\"comment\">% ");
					append(t.toString());
					append(" in the ");
					append(Integer.toString(group));
					switch (group) {
						case 1: append("st"); break;
						case 2: append("nd"); break;
						case 3: append("rd"); break;
						default: append("th");
					}
					append(" DLP</p>\n");
					for (LpRule r : transEvolp.getGroup(group, t)) {
						append(r);
					}
					append("</div>\n\n");
				}
			}
		}
		
		@Override
		public void visit(LpPredicate pred) {
			String name = pred.getName();
			if (name.startsWith("_N")) {
				append("<span class=\"negLitPrefix\">_N</span>");
				name = name.substring(2);
			}
			append("<span class=\"predicate\">");
			append(name);
			append("</span>");
		}
	}
	
	private class EvolpModelProcessor implements Consumer<EvolutionStableModel> {
		private int n;
		
		public EvolpModelProcessor() {
			n = 0;
		}
		
		public void beforeConsuming() {
			n = 0;
		}
		
		public void afterConsuming() {
			// no action needed
		}
		
		public void consume(EvolutionStableModel model) {
			n++;
			showMessage("Evolution stable model no. " + n + ":");
			
			printer.println("<div class=\"code\">");
			int i = 1;
			for (StableModel m : model) {
				printer.append("<p class=\"model\">M<sub>" + i + "</sub> = {");
				Iterator<LpAtom> iter = m.iterator();
				if (iter.hasNext()) {
					printer.append(iter.next());
				}
				while (iter.hasNext()) {
					printer.append(", ");
					printer.append(iter.next());
				}
				printer.append("}</p>\n");
				i++;
			}
			printer.println("</div>\n");
		}
	}
}