/*
 * DlpWebappHelper.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.DynamicLogicProgram;
import lp.unit.StableModel;
import lp.unit.TransDlpRuleType;
import lp.unit.TransformedDlp;

/**
 * A helper class for the web application that computes refined dynamic stable
 * models.
 *
 * @author Martin Slota
 * @version 0.9.0
 */
public class DlpWebappHelper extends DlpProcessor {
	private final JspPrinter printer;
	
	private final TransDlpHtmlPrinter<Writer> transPrinter;
	
	private final DlpModelProcessor processor;
	
	private boolean error;
	
	public DlpWebappHelper(ConfigManager config, JspWriter out) {
		super(config);
		printer = new JspPrinter(out);
		transPrinter = new TransDlpHtmlPrinter<Writer>(out);
		processor = new DlpModelProcessor();
		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 writeDlp() {
		if (!error) {
			try {
				DynamicLogicProgram tmp = getDlp();
				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 writeGroundedDlp() {
		if (!error) {
			try {
				chmod("location.lparse");
				DynamicLogicProgram tmp = getGroundedDlp();
				if (!error) {
					printer.append("<div class=\"code\">\n");
					printer.append(tmp);
					printer.append("</div>\n");
				}
			} catch (Exception e) {
				showError("Couldn't ground the input program!", e);
			}
		}
	}
	
	public void writeTransformedDlp() {
		if (!error) {
			try {
				chmod("location.lparse");
				TransformedDlp tmp = getTransformedDlp();
				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);
			}
		}
	}
	
	/*
	public static void main (String [] args) {
		StringBuilder sb = new StringBuilder();
		new DlpWebappHelper(null, null, null).appendLiteralAsHtml(sb, "not assert(a <- not b, c, d)");
		System.out.println(sb);
	}*/
	
	private class TransDlpHtmlPrinter<W extends Writer> extends LpHtmlPrinter<W> {
		public TransDlpHtmlPrinter(W out) {
			super(out, ":-", true);
		}
		
		public void append(TransformedDlp transDlp) {
			for (TransDlpRuleType t : TransDlpRuleType.values()) {
				append("<div class=\"ruleGroup\">\n");
				append("<p class=\"comment\">% " + t);
				append("</p>\n");
				for (LpRule r : transDlp.getGroup(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 DlpModelProcessor implements Consumer<StableModel> {
		private int n;
		
		public DlpModelProcessor() {
			n = 0;
		}
		
		public void beforeConsuming() {
			n = 0;
			printer.println("<div class=\"code\">");
		}
		
		public void afterConsuming() {
			printer.println("</div>\n");
		}
		
		public void consume(StableModel model) {
			n++;
			
			printer.append("<p class=\"model\">M<sub>" + n + "</sub> = {");
			Iterator<LpAtom> i = model.iterator();
			if (i.hasNext()) {
				printer.append(i.next());
			}
			while (i.hasNext()) {
				printer.append(", ");
				printer.append(i.next());
			}
			printer.append("}</p>\n");
		}
	}
}