// $Id: Module2OldHtml.java,v 1.7 2004/08/23 15:54:44 m31 Exp $
//
// This file is part of the program suite "Principia Mathematica II"
// which is a working prototype for the main project:
// "Hilbert II" - http://www.qedeq.org
//
// Copyright 2001-2004  Michael Meyling <mime@qedeq.org>.
//
// "Principia Mathematica II" 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.

package com.meyling.principia.html;


import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import com.meyling.principia.argument.Argument;
import com.meyling.principia.argument.ArgumentException;
import com.meyling.principia.argument.Counter;
import com.meyling.principia.argument.CounterMarker;
import com.meyling.principia.argument.PatternVariable;
import com.meyling.principia.argument.Text;
import com.meyling.principia.io.Output;
import com.meyling.principia.io.ParsingException;
import com.meyling.principia.io.Utility;
import com.meyling.principia.logic.basic.BasicFormulaPatternVariable;
import com.meyling.principia.logic.basic.BasicSubjectVariablePatternVariable;
import com.meyling.principia.logic.basic.Conjunction;
import com.meyling.principia.logic.basic.Disjunction;
import com.meyling.principia.logic.basic.Equivalence;
import com.meyling.principia.logic.basic.ExistentialQuantifier;
import com.meyling.principia.logic.basic.Implication;
import com.meyling.principia.logic.basic.Negation;
import com.meyling.principia.logic.basic.PredicateVariable;
import com.meyling.principia.logic.basic.PropositionVariable;
import com.meyling.principia.logic.basic.SubjectVariable;
import com.meyling.principia.logic.basic.UniversalQuantifier;
import com.meyling.principia.logic.paragraph.Abbreviation;
import com.meyling.principia.logic.paragraph.Axiom;
import com.meyling.principia.logic.paragraph.LinkLabel;
import com.meyling.principia.logic.paragraph.Paragraph;
import com.meyling.principia.logic.paragraph.ParagraphCheck;
import com.meyling.principia.logic.paragraph.ProofLine;
import com.meyling.principia.logic.paragraph.Proposition;
import com.meyling.principia.logic.paragraph.RuleDeclaration;
import com.meyling.principia.logic.rule.AddAxiom;
import com.meyling.principia.logic.rule.AddSentence;
import com.meyling.principia.logic.rule.ApplyAxiom;
import com.meyling.principia.logic.rule.ApplySentence;
import com.meyling.principia.logic.rule.ElementaryEquivalence;
import com.meyling.principia.logic.rule.Generalization;
import com.meyling.principia.logic.rule.HypotheticalSyllogism;
import com.meyling.principia.logic.rule.LeftAddition;
import com.meyling.principia.logic.rule.LeftAdditionConjunction;
import com.meyling.principia.logic.rule.LeftAdditionEquivalence;
import com.meyling.principia.logic.rule.LeftAdditionImplication;
import com.meyling.principia.logic.rule.LinkReference;
import com.meyling.principia.logic.rule.ModusPonens;
import com.meyling.principia.logic.rule.Particularization;
import com.meyling.principia.logic.rule.RenameBoundSubjectVariable;
import com.meyling.principia.logic.rule.RenameFreeSubjectVariable;
import com.meyling.principia.logic.rule.ReplacePredicateVariable;
import com.meyling.principia.logic.rule.ReplacePropositionVariable;
import com.meyling.principia.logic.rule.ReverseAbbreviation;
import com.meyling.principia.logic.rule.ReverseImplication;
import com.meyling.principia.logic.rule.RightAddition;
import com.meyling.principia.logic.rule.RightAdditionConjunction;
import com.meyling.principia.logic.rule.RightAdditionEquivalence;
import com.meyling.principia.logic.rule.RightAdditionImplication;
import com.meyling.principia.logic.rule.Rule;
import com.meyling.principia.logic.rule.SubstLine;
import com.meyling.principia.logic.rule.UseAbbreviation;
import com.meyling.principia.module.Description;
import com.meyling.principia.module.Email;
import com.meyling.principia.module.Headline;
import com.meyling.principia.module.Import;
import com.meyling.principia.module.ImportList;
import com.meyling.principia.module.Module;
import com.meyling.principia.module.ModuleAddress;
import com.meyling.principia.module.ModuleContext;
import com.meyling.principia.module.Name;
import com.meyling.principia.module.ParagraphList;
import com.meyling.principia.module.Specification;
import com.meyling.principia.module.UsedbyList;
import com.meyling.principia.module.Version;


/**
 * This class converts an module into a html file.
 *
 * @version $Revision: 1.7 $
 * @author  Michael Meyling
 */
public final class Module2OldHtml {

    /**
     * for converting a <code>String</code> into an
     * (Argument) <code>class</code>
     */
    private Module module;

    /** address of module to convert */
    private final String moduleAddress;


    /**
     * Constructor.
     *
     * @param   moduleAddress   convert module at this address
     * @throws  ParsingException    if any parsing error occurs
     * @throws  IOException         if any file problem occurs
     */
    public Module2OldHtml(final String moduleAddress)
            throws ParsingException, IOException {
        super();
        this.moduleAddress = moduleAddress;
        this.module = ModuleContext.getInstance().loadModule(moduleAddress);
    }


    /**
     * Convert a {@link Module} (referenced by module address
     * in constructor) into html.
     *
     * @throws  ParsingException    if any parsing error occurs
     * @throws  IOException         if any file problem occurs
     */
    public final void writeModule()
        throws ParsingException, IOException {

        final StringBuffer buffer = new StringBuffer();
        final Output output = new Output(buffer);

        // write module header
        final Argument header = module.getArgument(0);
        output.writeln("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
        output.writeln("<html lang=\"en\">");
        output.writeln("<head>");
        output.writeln("<meta http-equiv=\"Content-Type\" content= \"text/html; charset=ISO-8859-1\">");
        output.writeln("<title>"
            + toHtml(((Headline) header.getArgument(1)).getText())
            + "</title>");
        output.writeln("<meta name=\"language\" content=\"us\">");

        final Argument authors = header.getArgument(4);
        for (int i=0; i < authors.getArgumentSize(); i++) {
            output.writeln("<meta name=\"author\" content=\""
                + toHtml(((Text) authors.getArgument(i).getArgument(0)).getText())
                + "\">");
        }
        output.writeln("<meta name=\"description\" content=\""
            +  stripTags(((Description) header.getArgument(2)).getText())
            + "\">");
        output.writeln("<meta name=\"keywords\" content=\"Hilbert II, principia mathematica, logic, logical, mathematic, mathematics, mathematical, logic, basic, conclusion, formal, proof, foundation, correctness, predicate, calculus, first order, language, russell, whitehead, hilbert, ackermann, bernays\">");
        output.writeln("<meta name=\"generator\" content=\"com.meyling.principia.html.Module2OldHtml\">");

        // Format the current time.
        final SimpleDateFormat formatter
          = new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ss");
        final String date = formatter.format(new Date());
        output.writeln("<meta name=\"date\" content=\""
            + date + "+00:00"
            + "\">");
        output.writeln("<meta name=\"revision\" content=\""
            + ((Version) header.getArgument(0).getArgument(1)).getText()
            + "\">");
        output.writeln("<meta content=\"text/html; charset=us-ascii\">");
        final String email = ((Email) header.getArgument(3)).getText();
        output.writeln("<link rev=\"made\" href=\"mailto:"
            + email
            + "\">");
        output.writeln("<meta name=\"rating\" content=\"mathematics\">");

        output.writeln("<style type=\"text/css\">");
        output.writeln("  body { font-family: Arial,Helvetica,sans-serif; background: #cccccc; }");
        output.writeln("  A:link { color: #cc6600; }");
        output.writeln("  A:hover { color: #ff4000; background: #ffffff; text-decoration: underline;}");
        output.writeln("  A:active { color: #ff6600; background: #ffffcc; text-decoration: none;}");
        output.writeln("  A:visited { color: #993300; }");
        output.writeln("  h1, h2, h3 { font-family: Arial,Helvetica,sans-serif; color:#d97d49; }");
        output.writeln("  h4, h5 { font-family: Arial,Helvetica,sans-serif; color:#d97d49;margin-top: 0pt; margin-bottom: 0pt}");
        output.writeln("  p, div { font-family: Arial,Helvetica,sans-serif; }");
        output.writeln("  td, th { font-family: Arial,Helvetica,sans-serif; }");
        output.writeln("</style>");

        output.writeln("</head>");
        output.writeln();
        output.writeln("<body text=\"#000000\" bgcolor=\"#cccccc\" link=\"#cc6600\" vlink=\"#993300\" alink=\"#ff6600\">");
        output.writeln("<div align=\"right\"><font face=\"Arial,Helvetica\" size=\"-1\">for questions or link request: <a href=\"mailto:"
            + email
            + "\">module admin</a></font></div>");
        output.writeln("<h1><font face=\"Arial,Helvetica\">");
        output.writeln(toHtml(((Headline) header.getArgument(1)).getText()));
        output.writeln("</font></h1>");
        output.writeln("<font face=\"Arial,Helvetica\" size=\"-1\">");
        final String ruleVersion = ((Version) header.getArgument(0)
            .getArgument(2)).getText();
        output.write("name: "
            + toHtml(((Name) header.getArgument(0).getArgument(0)).getText())
            + ", module version: "
            + toHtml(((Version) header.getArgument(0).getArgument(1)).getText())
            + ", rule version: "
            + (ruleVersion.equals("1.00.00") ? "<a href=\"http://www.qedeq.org/"
            + ModuleContext.getVersionDirectory() + "/rules_1.00.00.o.html\">" : "")
            + toHtml(ruleVersion)
            + "</a>");
        output.write(", original: <a href=\""
            + moduleAddress
            + "\">");
        output.write(((Name) header.getArgument(0).getArgument(0)).getText());
        output.write("</a>");
        if (authors.getArgumentSize() < 2) {
            output.write(", author of this module: ");
        } else {
            output.write(", authors of this module: ");
        }
        for (int i=0; i < authors.getArgumentSize(); i++) {
            if (i != 0) {
                output.write(", ");
            };
            output.write("<a href=\"mailto:"
                + toHtml(((Email) authors.getArgument(i).getArgument(1)).getText())
                + "\">"
                + toHtml(((Text) authors.getArgument(i).getArgument(0)).getText())
                + "</a>");
        }
        output.writeln();
        output.writeln("</font>");
        output.writeln("<h2><font face=\"Arial,Helvetica\">");
        output.writeln("Description");
        output.writeln("</font></h2>");
        output.writeln("<font face=\"Arial,Helvetica\">");
        output.writeln(
            Latex2OldHtml.convert(
                ((Description) header.getArgument(2)).getText()
            )
        );
        output.writeln("</font>");

        int position = 1;
        if (module.getArgument(position) instanceof ImportList) {

            output.writeln("<h2><font face=\"Arial,Helvetica\">");
            output.writeln("References");
            output.writeln("</font></h2>");
            output.writeln("<font face=\"Arial,Helvetica\">");
            output.writeln("This document uses the results of the following documents:");
            final ImportList imports
                = (ImportList) module.getArgument(position);
            final int lines = imports.getArgumentSize();
            output.writeln("<ul>");
            // step through all imports and get them
            for (int n = 0; n < lines; n++) {
                output.writeln("<li>");
                final Import imp = ((Import) imports.getArgument(n));
                final Module mod;
                try {
                    mod = ModuleContext.getInstance().loadModule(
                        this.module, (Specification) imp.getArgument(0));
                } catch (ArgumentException e) { // TODO ok?
                    throw new IllegalArgumentException(e.getDescription());
                }
                final String address = createLink(mod);
                output.writeln("<a href=\"" + address + "\">"
                    + "<font face=\"Arial,Helvetica\">"
                    + address + "</font></a>");

                output.writeln("</li>");
            }
            output.writeln("</ul>");
            output.writeln("</font>");
            position++;
        }
        UsedbyList usedby = null;
        if (module.getArgument(position) instanceof UsedbyList) {
            usedby
                = (UsedbyList) module.getArgument(position);
            position++;
        }
        if (module.getArgument(position) instanceof ParagraphList) {
            output.writeln("<h2><font face=\"Arial,Helvetica\">");
            output.writeln("Content");
            output.writeln("</font></h2>");
            final ParagraphList paragraphs
                = (ParagraphList) module.getArgument(position);
            writeParagraphList(paragraphs, output);
            position++;
        }

        if (usedby != null) {
            output.writeln("<p>");
            output.writeln("<h2><font face=\"Arial,Helvetica\">");
            output.writeln("Cross References");
            output.writeln("</font></h2>");
            output.writeln("<font face=\"Arial,Helvetica\">");
            output.writeln("This document is used by the following documents:");
            final int lines = usedby.getArgumentSize();
            // step through all specifications
            output.writeln("<ul>");
            for (int n = 0; n < lines; n++) {
                output.writeln("<li>");
                final Specification spec = ((Specification) usedby.getArgument(n));
                final Module mod;
                try {
                    mod = ModuleContext.getInstance().loadModule(module, spec);
                } catch (ArgumentException e) {     // TODO ok?
                    throw new IllegalArgumentException(e.getDescription());
                }
                final String address = createLink(mod);
                output.writeln("<a href=\"" + address + "\">"
                    + "<font face=\"Arial,Helvetica\">"
                    + address + "</font></a>");
                output.writeln("</li>");
            }
            output.writeln("</ul>");
            output.writeln("</font>");
        }

        output.writeln("</body>");
        output.writeln("</html>");

        String result = new ModuleAddress(moduleAddress).getGeneratedName("o.html");
//        String result = ModuleAddress.getLocalName(moduleAddress);
//        result = result.substring(0, result.lastIndexOf(".")) + ".html";
        final File f = new File(result).getParentFile();
        f.mkdirs();

        Utility.saveFile(result, buffer);
        System.out.println("created:\n  " + result);
    }


    /**
     * Convert a {@link ParagraphList} into html.
     *
     * @param   paragraphs  convert this
     * @param   output      destination for resulting html code
     */
    private final void writeParagraphList(final ParagraphList paragraphs,
            final Output output) {

        final int lines = paragraphs.getArgumentSize();
        // step through all paragraphs
        for (int n = 0; n < lines; n++) {
            if (n != 0) {
                output.writeln("<br>");
            }
            final Paragraph paragraph
                = (Paragraph) paragraphs.getArgument(n);
            String preText = "";
            String postText = "";
            int pos = 1;
            if (paragraph.getArgument(pos) instanceof Text) {
                preText = ((Text) paragraph.getArgument(pos)).getText();
                pos++;
            }
            if (preText.length() > 0) {
                output.writeln("<p>");
                output.writeln(Latex2OldHtml.convert(preText));
                output.writeln("</p>");
            }
            output.writeln("<p>");
            output.writeln("<font face=\"Arial,Helvetica\">");
            output.write("<strong>" + (n + 1) + ". ");
            final ParagraphCheck kind
                = (ParagraphCheck) paragraph.getArgument(pos);
            if (kind instanceof Abbreviation) {
                output.write("Abbreviation");
            } else if (kind instanceof Axiom) {
                output.write("Axiom");
            } else if (kind instanceof Proposition) {
                output.write("Proposition");
            } else if (kind instanceof RuleDeclaration) {
                output.write("Rule Declaration");
            }
            pos++;
            output.writeln("</strong>");
            output.writeln("<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
            final String label = ((LinkLabel) paragraph.getArgument(0)).getLabel();
            if (kind instanceof Axiom) {
                writeFormula(kind.getArgument(0), output);
                output.writeln("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font size=\"-1\"><a name=\""
                    + label
                    + "\">("
                    + label
                    + ")</a></font>");
                output.writeln("</font></p>");
            } else if (kind instanceof Abbreviation) {
                writeFormula(kind.getArgument(0), output);
/*                output.write(" := "); */
                output.write("</font><font face=\"Symbol\"> &#186; </font><font face=\"Arial,Helvetica\">");
                writeFormula(kind.getArgument(1), output);
                output.writeln("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font size=\"-1\"><a name=\""
                    + label
                    + "\">("
                    + label
                    + ")</a></font>");
                output.writeln("</font></p>");
            } else if (kind instanceof Proposition) {
                writeFormula(kind.getArgument(0).getArgument(0), output);
                output.writeln("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font size=\"-1\"><a name=\""
                    + label
                    + "\">("
                    + label
                    + ")</a></font>");
                output.writeln("</font>");
                output.writeln("</p>");
                output.writeln("<i>Proof:</i>");
//                output.writeln("<p>");
                output.writeln("<table border=\"0\" cellpadding=\"5\">");
                for (int i = 0; i < kind.getArgument(1).getArgumentSize(); i++) {
                    output.writeln("<tr>");
                    output.writeln("<td><font face=\"Arial,Helvetica\">"
                        + "<a name=\"" + label + "_" + (i + 1) + "\">"
                        + (i + 1) + "</a></font></td>");
                    writeProofLine((ProofLine) kind.getArgument(1).getArgument(i),
                        output, label);
                    output.writeln("</tr>");
                }
                output.writeln("<tr>");
                output.writeln("<td></td><td><font face=\"Arial,Helvetica\">"
                    + "qed</font></td>");
                output.writeln("</tr>");
                output.writeln("</table>");
            } else if (kind instanceof RuleDeclaration) {
//                output.write("&quot;" + ((Text) kind.getArgument(0)).getText() + "&quot;: "
//                    + ((Text) kind.getArgument(1)).getText());
                output.write(((Text) kind.getArgument(1)).getText());
                output.writeln("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font size=\"-1\"><a name=\""
                    + label
                    + "\">("
                    + label
                    + ")</a></font>");
                output.writeln("</font>");
                output.writeln("</p>");
                if (kind.getArgumentSize() > 2) {
                    output.writeln("<p>");
                    output.writeln("<font face=\"Arial,Helvetica\">");
                    output.writeln("<i>References, needed for declaration:</i><br>");
                    for (int i = 2; i < kind.getArgumentSize(); i++) {
                        if (2 < i) {
                            output.write(", ");
                        }
                        final String reference
                            = ((LinkReference) kind.getArgument(i))
                            .getReference();
                        output.write("<a href=\"");
                        final String address = createLink(this.module
                            .getLabelModule(reference));
                        output.write(address + "#" + reference);
                        output.writeln("\">" + reference + "</a>");
                    }
                    output.writeln("</font>");
                    output.writeln("</p>");
                }
            } else {
                output.writeln(kind.toString());
            }
            if (pos < paragraph.getArgumentSize()) {
                postText = ((Text) paragraph.getArgument(pos)).getText();
                output.writeln("<p>");
                output.writeln(Latex2OldHtml.convert(postText));
                output.writeln("</p>");
            }
        }
    }


    /**
     * Convert a {@link ProofLine} into html.
     *
     * @param   line    convert this
     * @param   output  destination for resulting html code
     * @param   label   for proof line references
     */
    public final void writeProofLine(final ProofLine line,
            final Output output, final String label) {
        output.writeln("<td>");
        output.writeln("<font face=\"Arial,Helvetica\">");
        writeFormula(line.getArgument(0), output);
        output.writeln("</font>");
        output.writeln("</td>");
        output.writeln("<td>");
        final Rule rule = (Rule) line.getArgument(1);
        output.writeln("<font face=\"Arial,Helvetica\">");
        if (rule instanceof ModusPonens) {
            output.write("<a href=\"rules_1.00.00.html#modusponens\">");
            output.write("modus ponens");
            output.write("</a> with ");
            output.write("<a href=\"#" + label + "_"
                + ((Counter) rule.getArgument(0)).getNumber()
                + "\">"
                + ((Counter) rule.getArgument(0)).getNumber()
                +"</a>");
            output.write(", ");
            output.write("<a href=\"#" + label + "_"
                + ((Counter) rule.getArgument(1)).getNumber()
                + "\">"
                + ((Counter) rule.getArgument(1)).getNumber()
                +"</a>");
            output.writeln();

        } else if (rule instanceof AddAxiom) {
            final String reference
                = ((LinkReference) rule.getArgument(0)).getReference();
            output.write("<a href=\"rules_1.00.00.html#addaxiom\">");
            output.write("add axiom");
            output.write("</a> ");
            output.write("<a href=\"");
            final String address = createLink(this.module
                .getLabelModule(reference));
            output.write(address + "#" + reference);
            output.writeln("\">" + reference + "</a>");
        } else if (rule instanceof AddSentence) {
            final String reference
                = ((LinkReference) rule.getArgument(0)).getReference();
            output.write("<a href=\"rules_1.00.00.html#addproposition\">");
            output.write("add proposition");
            output.write("</a> ");
            output.write("<a href=\"");
            final String address = createLink(this.module
                .getLabelModule(reference));
            output.write(address + "#" + reference);
            output.writeln("\">" + reference + "</a>");
        } else if (rule instanceof Generalization) {
            output.write("<a href=\"rules_1.00.00.html#generalization\">");
            output.write("generalization");
            output.write("</a>");
            output.write(" by ");
            writeFormula(rule.getArgument(1), output);
            output.write(" in ");
            output.write("<a href=\"#" + label + "_"
                + ((Counter) rule.getArgument(0)).getNumber()
                + "\">"
                + ((Counter) rule.getArgument(0)).getNumber()
                +"</a>");
            output.writeln();
        } else if (rule instanceof Particularization) {
            output.write("<a href=\"rules_1.00.00.html#particularization\">");
            output.write("particularization");
            output.write("</a>");
            output.write(" by ");
            writeFormula(rule.getArgument(1), output);
            output.write(" in ");
            output.write("<a href=\"#" + label + "_"
                + ((Counter) rule.getArgument(0)).getNumber()
                + "\">"
                + ((Counter) rule.getArgument(0)).getNumber()
                +"</a>");
            output.writeln();
        } else if (rule instanceof RenameBoundSubjectVariable) {
            output.write("<a href=\"rules_1.00.00.html#renameboundvar\">");
            output.write("rename bound variable");
            output.write("</a> ");
            writeFormula(rule.getArgument(1), output);
            output.write(" into ");
            writeFormula(rule.getArgument(2), output);
            output.write(" in ");
            output.write("<a href=\"#" + label + "_"
                + ((Counter) rule.getArgument(0)).getNumber()
                + "\">"
                + ((Counter) rule.getArgument(0)).getNumber()
                +"</a>");
            output.write(" at occurence ");
            output.write(((Counter) rule.getArgument(3)).getNumber());
            output.writeln();
        } else if (rule instanceof RenameFreeSubjectVariable) {
            output.write("<a href=\"rules_1.00.00.html#renamefreevar\">");
            output.write("rename free variable");
            output.write("</a> ");
            writeFormula(rule.getArgument(1), output);
            output.write(" into ");
            writeFormula(rule.getArgument(2), output);
            output.write(" in ");
            output.write("<a href=\"#" + label + "_"
                + ((Counter) rule.getArgument(0)).getNumber()
                + "\">"
                + ((Counter) rule.getArgument(0)).getNumber()
                +"</a>");
            output.writeln();
        } else if (rule instanceof ReplacePredicateVariable) {
            output.write("<a href=\"rules_1.00.00.html#replacepredicate\">");
            output.write("replace predicate variable");
            output.write("</a> ");
            writeFormula(rule.getArgument(1), output);
            output.write(" by ");
            writeFormula(rule.getArgument(2), output);
            output.write(" in ");
            output.write("<a href=\"#" + label + "_"
                + ((Counter) rule.getArgument(0)).getNumber()
                + "\">"
                + ((Counter) rule.getArgument(0)).getNumber()
                +"</a>");
            output.writeln();
        } else if (rule instanceof ReplacePropositionVariable) {
            output.write("<a href=\"rules_1.00.00.html#replaceprop\">");
            output.write("replace proposition variable");
            output.write("</a> ");
            writeFormula(rule.getArgument(1), output);
            output.write(" by ");
            writeFormula(rule.getArgument(2), output);
            output.write(" in ");
            output.write("<a href=\"#" + label + "_"
                + ((Counter) rule.getArgument(0)).getNumber()
                + "\">"
                + ((Counter) rule.getArgument(0)).getNumber()
                +"</a>");
            output.writeln();
        } else if (rule instanceof ReverseAbbreviation) {
            final String reference
                = ((LinkReference) rule.getArgument(1)).getReference();
            output.write("<a href=\"rules_1.00.00.html#reverseabbreviation\">");
            output.write("reverse abbreviation");
            output.write("</a> ");
            output.write("<a href=\"");
            final String address = createLink(this.module
                .getLabelModule(reference));
            output.write(address + "#" + reference);
            output.write("\">" + reference + "</a>");
            output.write(" in ");
            output.write("<a href=\"#" + label + "_"
                + ((Counter) rule.getArgument(0)).getNumber()
                + "\">"
                + ((Counter) rule.getArgument(0)).getNumber()
                +"</a>");
            output.write(" at occurence ");
            output.write(((Counter) rule.getArgument(2)).getNumber());
            output.writeln();
        } else if (rule instanceof UseAbbreviation) {
            final String reference
                = ((LinkReference) rule.getArgument(1)).getReference();
            output.write("<a href=\"rules_1.00.00.html#useabbreviation\">");
            output.write("use abbreviation");
            output.write("</a> ");
            output.write("<a href=\"");
            final String address = createLink(this.module
                .getLabelModule(reference));
                output.write(address + "#" + reference);
            output.write("\">" + reference + "</a>");
            output.write(" in ");
            output.write("<a href=\"#" + label + "_"
                + ((Counter) rule.getArgument(0)).getNumber()
                + "\">"
                + ((Counter) rule.getArgument(0)).getNumber()
                +"</a>");
            output.write(" at occurence ");
            output.write(((Counter) rule.getArgument(2)).getNumber());
            output.writeln();
        /*** new rules following ***/
        } else if (rule instanceof SubstLine) {
            final String reference
                = this.module.getRuleDeclarationLabel(rule.getClass());
// TODO
//            final RuleDeclaration declaration
//                = this.module.getRuleDeclaration(rule.getClass());
//            final String description = ((Text) declaration.getArgument(1)).getText();
            final String description = "substitute variables";
            output.write("<a href=\"");
            final String address = createLink(this.module
                .getLabelModule(reference));
            output.write(address + "#" + reference);
            output.write("\">" + description + "</a>");
            output.write(" in ");
            output.write("<a href=\"#" + label + "_"
                + ((Counter) rule.getArgument(0)).getNumber()
                + "\">"
                + ((Counter) rule.getArgument(0)).getNumber()
                +"</a>");
            output.writeln();
        } else if (rule instanceof ApplyAxiom) {
            String reference
                = this.module.getRuleDeclarationLabel(rule.getClass());
// TODO
//            final RuleDeclaration declaration
//                = this.module.getRuleDeclaration(rule.getClass());
//            final String description = ((Text) declaration.getArgument(1)).getText();
            final String description = "apply axiom";
            output.write("<a href=\"");
            String address = createLink(this.module
                .getLabelModule(reference));
            output.write(address + "#" + reference);
            output.write("\">" + description + "</a> ");
            reference
                = ((LinkReference) rule.getArgument(1)).getReference();
            output.write("<a href=\"");
            address = createLink(this.module
                .getLabelModule(reference));
            output.write(address + "#" + reference);
            output.write("\">" + reference + "</a>");
            output.write(" in ");
            output.write("<a href=\"#" + label + "_"
                + ((Counter) rule.getArgument(0)).getNumber()
                + "\">"
                + ((Counter) rule.getArgument(0)).getNumber()
                +"</a>");
            output.writeln();
        } else if (rule instanceof ApplySentence) {
            String reference
                = this.module.getRuleDeclarationLabel(rule.getClass());
// TODO
//           final RuleDeclaration declaration
//                = this.module.getRuleDeclaration(rule.getClass());
//            final String description = ((Text) declaration.getArgument(1)).getText();
            final String description = "apply proposition";
            output.write("<a href=\"");
            String address = createLink(this.module
                .getLabelModule(reference));
            output.write(address + "#" + reference);
            output.write("\">" + description + "</a> ");
            reference
                = ((LinkReference) rule.getArgument(1)).getReference();
            output.write("<a href=\"");
            address = createLink(this.module
                .getLabelModule(reference));
            output.write(address + "#" + reference);
            output.write("\">" + reference + "</a>");
            output.write(" in ");
            output.write("<a href=\"#" + label + "_"
                + ((Counter) rule.getArgument(0)).getNumber()
                + "\">"
                + ((Counter) rule.getArgument(0)).getNumber()
                +"</a>");
            output.writeln();
        } else if (rule instanceof HypotheticalSyllogism) {
            final String reference
                = this.module.getRuleDeclarationLabel(rule.getClass());
            final RuleDeclaration declaration
                = this.module.getRuleDeclaration(rule.getClass());
//            final String description = ((Text) declaration.getArgument(1)).getText();
            final String description = "hypothetical syllogism";
            output.write("<a href=\"");
            final String address = createLink(this.module
                .getLabelModule(reference));
            output.write(address + "#" + reference);
            output.write("\">" + description + "</a>");
            output.write(" with ");
            output.write("<a href=\"#" + label + "_"
                + ((Counter) rule.getArgument(0)).getNumber()
                + "\">"
                + ((Counter) rule.getArgument(0)).getNumber()
                +"</a>");
            output.write(" and ");
            output.write("<a href=\"#" + label + "_"
                + ((Counter) rule.getArgument(1)).getNumber()
                + "\">"
                + ((Counter) rule.getArgument(1)).getNumber()
                +"</a>");
            output.writeln();
        } else if (rule instanceof RightAddition) {
            final String reference
                = this.module.getRuleDeclarationLabel(rule.getClass());
            final RuleDeclaration declaration
                = this.module.getRuleDeclaration(rule.getClass());
//            final String description = ((Text) declaration.getArgument(1)).getText();
            final String description = "right disjunction addition";
            output.write("<a href=\"");
            final String address = createLink(this.module
                .getLabelModule(reference));
            output.write(address + "#" + reference);
            output.write("\">" + description + "</a>");
            output.write(" in ");
            output.write("<a href=\"#" + label + "_"
                + ((Counter) rule.getArgument(0)).getNumber()
                + "\">"
                + ((Counter) rule.getArgument(0)).getNumber()
                +"</a>");
            output.write(" with ");
            writeFormula(rule.getArgument(2), output);
            output.writeln();
        } else if (rule instanceof LeftAddition) {
            final String reference
                = this.module.getRuleDeclarationLabel(rule.getClass());
            final RuleDeclaration declaration
                = this.module.getRuleDeclaration(rule.getClass());
//            final String description = ((Text) declaration.getArgument(1)).getText();
            final String description = "left disjunction addition";
            output.write("<a href=\"");
            final String address = createLink(this.module
                .getLabelModule(reference));
            output.write(address + "#" + reference);
            output.write("\">" + description + "</a>");
            output.write(" in ");
            output.write("<a href=\"#" + label + "_"
                + ((Counter) rule.getArgument(0)).getNumber()
                + "\">"
                + ((Counter) rule.getArgument(0)).getNumber()
                +"</a>");
            output.write(" with ");
            writeFormula(rule.getArgument(2), output);
            output.writeln();
        } else if (rule instanceof RightAdditionImplication) {
            final String reference
                = this.module.getRuleDeclarationLabel(rule.getClass());
            final RuleDeclaration declaration
                = this.module.getRuleDeclaration(rule.getClass());
//            final String description = ((Text) declaration.getArgument(1)).getText();
            final String description = "right implication addition";
            output.write("<a href=\"");
            final String address = createLink(this.module
                .getLabelModule(reference));
            output.write(address + "#" + reference);
            output.write("\">" + description + "</a>");
            output.write(" in ");
            output.write("<a href=\"#" + label + "_"
                + ((Counter) rule.getArgument(0)).getNumber()
                + "\">"
                + ((Counter) rule.getArgument(0)).getNumber()
                +"</a>");
            output.write(" with ");
            writeFormula(rule.getArgument(2), output);
            output.writeln();
        } else if (rule instanceof LeftAdditionImplication) {
            final String reference
                = this.module.getRuleDeclarationLabel(rule.getClass());
            final RuleDeclaration declaration
                = this.module.getRuleDeclaration(rule.getClass());
//            final String description = ((Text) declaration.getArgument(1)).getText();
            final String description = "left implication addition";
            output.write("<a href=\"");
            final String address = createLink(this.module
                .getLabelModule(reference));
            output.write(address + "#" + reference);
            output.write("\">" + description + "</a>");
            output.write(" in ");
            output.write("<a href=\"#" + label + "_"
                + ((Counter) rule.getArgument(0)).getNumber()
                + "\">"
                + ((Counter) rule.getArgument(0)).getNumber()
                +"</a>");
            output.write(" with ");
            writeFormula(rule.getArgument(2), output);
            output.writeln();
        } else if (rule instanceof RightAdditionConjunction) {
            final String reference
                = this.module.getRuleDeclarationLabel(rule.getClass());
            final RuleDeclaration declaration
                = this.module.getRuleDeclaration(rule.getClass());
//            final String description = ((Text) declaration.getArgument(1)).getText();
            final String description = "right conjunction addition";
            output.write("<a href=\"");
            final String address = createLink(this.module
                .getLabelModule(reference));
            output.write(address + "#" + reference);
            output.write("\">" + description + "</a>");
            output.write(" in ");
            output.write("<a href=\"#" + label + "_"
                + ((Counter) rule.getArgument(0)).getNumber()
                + "\">"
                + ((Counter) rule.getArgument(0)).getNumber()
                +"</a>");
            output.write(" with ");
            writeFormula(rule.getArgument(2), output);
            output.writeln();
        } else if (rule instanceof LeftAdditionConjunction) {
            final String reference
                = this.module.getRuleDeclarationLabel(rule.getClass());
            final RuleDeclaration declaration
                = this.module.getRuleDeclaration(rule.getClass());
//            final String description = ((Text) declaration.getArgument(1)).getText();
            final String description = "left conjunction addition";
            output.write("<a href=\"");
            final String address = createLink(this.module
                .getLabelModule(reference));
            output.write(address + "#" + reference);
            output.write("\">" + description + "</a>");
            output.write(" in ");
            output.write("<a href=\"#" + label + "_"
                + ((Counter) rule.getArgument(0)).getNumber()
                + "\">"
                + ((Counter) rule.getArgument(0)).getNumber()
                +"</a>");
            output.write(" with ");
            writeFormula(rule.getArgument(2), output);
            output.writeln();
        } else if (rule instanceof RightAdditionEquivalence) {
            final String reference
                = this.module.getRuleDeclarationLabel(rule.getClass());
            final RuleDeclaration declaration
                = this.module.getRuleDeclaration(rule.getClass());
//            final String description = ((Text) declaration.getArgument(1)).getText();
            final String description = "right equivalence addition";
            output.write("<a href=\"");
            final String address = createLink(this.module
                .getLabelModule(reference));
            output.write(address + "#" + reference);
            output.write("\">" + description + "</a>");
            output.write(" in ");
            output.write("<a href=\"#" + label + "_"
                + ((Counter) rule.getArgument(0)).getNumber()
                + "\">"
                + ((Counter) rule.getArgument(0)).getNumber()
                +"</a>");
            output.write(" with ");
            writeFormula(rule.getArgument(2), output);
            output.writeln();
        } else if (rule instanceof LeftAdditionEquivalence) {
            final String reference
                = this.module.getRuleDeclarationLabel(rule.getClass());
            final RuleDeclaration declaration
                = this.module.getRuleDeclaration(rule.getClass());
//            final String description = ((Text) declaration.getArgument(1)).getText();
            final String description = "left equivalence addition";
            output.write("<a href=\"");
            final String address = createLink(this.module
                .getLabelModule(reference));
            output.write(address + "#" + reference);
            output.write("\">" + description + "</a>");
            output.write(" in ");
            output.write("<a href=\"#" + label + "_"
                + ((Counter) rule.getArgument(0)).getNumber()
                + "\">"
                + ((Counter) rule.getArgument(0)).getNumber()
                +"</a>");
            output.write(" with ");
            writeFormula(rule.getArgument(2), output);
            output.writeln();
        } else if (rule instanceof ReverseImplication) {
            final String reference
                = this.module.getRuleDeclarationLabel(rule.getClass());
            final RuleDeclaration declaration
                = this.module.getRuleDeclaration(rule.getClass());
//            final String description = ((Text) declaration.getArgument(1)).getText();
            final String description = "reverse implication";
            output.write("<a href=\"");
            final String address = createLink(this.module
                .getLabelModule(reference));
            output.write(address + "#" + reference);
            output.write("\">" + description + "</a>");
            output.write(" in ");
            output.write("<a href=\"#" + label + "_"
                + ((Counter) rule.getArgument(0)).getNumber()
                + "\">"
                + ((Counter) rule.getArgument(0)).getNumber()
                +"</a>");
            output.writeln();
        } else if (rule instanceof ElementaryEquivalence) {
            String reference
                = this.module.getRuleDeclarationLabel(rule.getClass());
            final RuleDeclaration declaration
                = this.module.getRuleDeclaration(rule.getClass());
//            final String description = ((Text) declaration.getArgument(1)).getText();
            final String description = "elementary equivalence";
            output.write("<a href=\"");
            String address = createLink(this.module
                .getLabelModule(reference));
            output.write(address + "#" + reference);
            output.write("\">" + description + "</a>");
            output.write(" in ");
            output.write("<a href=\"#" + label + "_"
                + ((Counter) rule.getArgument(0)).getNumber()
                + "\">"
                + ((Counter) rule.getArgument(0)).getNumber()
                +"</a>");
            output.write(" at ");
            output.write(((Counter) rule.getArgument(3)).getNumber());
            output.write(" of ");
            reference
                = ((LinkReference) rule.getArgument(1)).getReference();
            output.write("<a href=\"");
            address = createLink(this.module
                .getLabelModule(reference));
            output.write(address + "#" + reference);
            output.writeln("\">" + reference + "</a>");
            output.write(" with ");
            reference
                = ((LinkReference) rule.getArgument(2)).getReference();
            output.write("<a href=\"");
            address = createLink(this.module
                .getLabelModule(reference));
            output.write(address + "#" + reference);
            output.writeln("\">" + reference + "</a>");
            output.writeln();
        } else {
            output.writeln(rule);
        }
        output.writeln("</font>");
        output.writeln("</td>");
    }


    /**
     * Convert a {@link Formula} or its sub arguments into html.
     *
     * @param   argument    convert this
     * @param   output      destination for resulting html code
     */
    private final void writeFormula(final Argument argument,
            final Output output) {
/*
        if (argument instanceof Conjunction) {
            output.write("(");
            writeFormula(argument.getArgument(0), output);
            output.write(" &amp; ");
            writeFormula(argument.getArgument(1), output);
            output.write(")");
        } else if (argument instanceof Disjunction) {
            output.write("(");
            writeFormula(argument.getArgument(0), output);
            output.write(" v ");
            writeFormula(argument.getArgument(1), output);
            output.write(")");
        } else if (argument instanceof Implication) {
            output.write("(");
            writeFormula(argument.getArgument(0), output);
            output.write(" =&gt; ");
            writeFormula(argument.getArgument(1), output);
            output.write(")");
        } else if (argument instanceof Equivalence) {
            output.write("(");
            writeFormula(argument.getArgument(0), output);
            output.write(" &lt;=&gt; ");
            writeFormula(argument.getArgument(1), output);
            output.write(")");
        } else if (argument instanceof Negation) {
            output.write("-");
            writeFormula(argument.getArgument(0), output);
        } else if (argument instanceof ExistentialQuantifier) {
            output.write("A ");
            writeFormula(argument.getArgument(0), output);
            output.write("(");
            writeFormula(argument.getArgument(1), output);
            output.write(")");
        } else if (argument instanceof UniversalQuantifier) {
            output.write("A ");
            writeFormula(argument.getArgument(0), output);
            output.write("(");
            writeFormula(argument.getArgument(1), output);
            output.write(")");
*/
        if (argument instanceof Conjunction) {
            output.write("(");
            writeFormula(argument.getArgument(0), output);
            output.write("</font><font face=\"Symbol\"> &#217; </font><font face=\"Arial,Helvetica\">");
            writeFormula(argument.getArgument(1), output);
            output.write(")");
        } else if (argument instanceof Disjunction) {
            output.write("(");
            writeFormula(argument.getArgument(0), output);
            output.write("</font><font face=\"Symbol\"> &#218; </font><font face=\"Arial,Helvetica\">");
            writeFormula(argument.getArgument(1), output);
            output.write(")");
        } else if (argument instanceof Implication) {
            output.write("(");
            writeFormula(argument.getArgument(0), output);
//            output.write("</font><font face=\"Symbol\"> &#222; </font><font face=\"Arial,Helvetica\">");
            output.write("</font><font face=\"Symbol\"> &#174; </font><font face=\"Arial,Helvetica\">");
            writeFormula(argument.getArgument(1), output);
            output.write(")");
        } else if (argument instanceof Equivalence) {
            output.write("(");
            writeFormula(argument.getArgument(0), output);
//            output.write("</font><font face=\"Symbol\"> &#219; </font><font face=\"Arial,Helvetica\">");
            output.write("</font><font face=\"Symbol\"> &#171; </font><font face=\"Arial,Helvetica\">");
            writeFormula(argument.getArgument(1), output);
            output.write(")");
        } else if (argument instanceof Negation) {
            output.write("</font><font face=\"Symbol\">&#216;</font><font face=\"Arial,Helvetica\">");
            writeFormula(argument.getArgument(0), output);
        } else if (argument instanceof ExistentialQuantifier) {
            output.write("</font><font face=\"Symbol\">&#36; </font><font face=\"Arial,Helvetica\">");
            writeFormula(argument.getArgument(0), output);
            output.write(" (");
            writeFormula(argument.getArgument(1), output);
            output.write(")");
        } else if (argument instanceof UniversalQuantifier) {
            output.write("</font><font face=\"Symbol\">&#34; </font><font face=\"Arial,Helvetica\">");
            writeFormula(argument.getArgument(0), output);
            output.write(" (");
            writeFormula(argument.getArgument(1), output);
            output.write(")");
        } else if (argument instanceof SubjectVariable) {
            String var = "";
            final int n = ((CounterMarker)
                argument.getArgument(0)).getNumber();
            if (argument.getArgument(0) instanceof PatternVariable) {
                var = "x<sub>@" + n + "</sub>";
            } else {
                switch (n) {
                    case 1: var = "x";
                            break;
                    case 2: var = "y";
                            break;
                    case 3: var = "z";
                            break;
                    case 4: var = "u";
                            break;
                    case 5: var = "v";
                            break;
                    case 6: var = "w";
                            break;
                    case 7: var = "r";
                            break;
                    case 8: var = "s";
                            break;
                    case 9: var = "t";
                            break;
                    case 10: var = "a";
                            break;
                    case 11: var = "b";
                            break;
                    case 12: var = "c";
                            break;
                    case 13: var = "d";
                            break;
                    default:
                            var = "x<sub>" + n + "</sub>";
                }
            }
            output.write(var);
        } else if (argument instanceof PropositionVariable) {
            String var = "";
            final int n = ((CounterMarker)
                argument.getArgument(0)).getNumber();
            if (argument.getArgument(0) instanceof PatternVariable) {
                var = "P<sub>@" + n + "</sub>";
            } else {
                switch (n) {
                case 1: var = "P";
                        break;
                case 2: var = "Q";
                        break;
                case 3: var = "A";
                        break;
                case 4: var = "B";
                        break;
                case 5: var = "C";
                        break;
                case 6: var = "D";
                        break;
                default:
                        var = "P<sub>" + n + "</sub>";
                }
            }
            output.write(var);
        } else if (argument instanceof PredicateVariable) {
            String var = "";
            final int n = ((CounterMarker)
                argument.getArgument(0)).getNumber();
            if (argument.getArgument(0) instanceof PatternVariable) {
                var = "R<sub>@" + n + "</sub>";
            } else {
                switch (n) {
                case 1: var = "R";
                        break;
                case 2: var = "F";
                        break;
                case 3: var = "G";
                        break;
                case 4: var = "H";
                        break;
                case 5: var = "I";
                        break;
                case 6: var = "J";
                        break;
                default:
                        var = "R<sub>" + n + "</sub>";
                }
            }
            output.write(var + "(");
            Argument list = argument.getArgument(1);
            for (int i = 0; i < list.getArgumentSize(); i++) {
                if (i > 0) {
                    output.write(", ");
                }
                writeFormula(list.getArgument(i), output);
            }
            output.write(")");
        } else if (argument instanceof BasicSubjectVariablePatternVariable) {
            final int n = ((PatternVariable)
                argument).getNumber();
                output.write("@S" + n);
        } else if (argument instanceof BasicFormulaPatternVariable) {
            final int n = ((PatternVariable)
                argument).getNumber();
                output.write("@F" + n);
        }

    }


    /**
     * Get link address for referenced module.
     *
     * @param   referenced  link to this module
     * @return  link address
     */
    public final String createLink(final Module referenced) {
        return ModuleAddress.newEnding(
            this.module.getModuleAddress().createRelativeAddress(
            referenced.getModuleAddress()),
            "o.html");
    }


    /**
     * Escape certain control seqences: &quot;, &amp;.
     * Doesn't escape &lt: or &gt;!
     *
     * @param   text    excape this text
     * @return  escaped text
     */
    public final static String toHtml(final String text) {

        final StringBuffer buffer = new StringBuffer(text.length());
        for (int i = 0; i < text.length(); i++) {
            final char c = text.charAt(i);
            switch (c) {
            case '\"':  buffer.append("&quot;");
                break;
            case '&':   buffer.append("&amp;");
                break;
            default:
                buffer.append(c);
            }
        }
        return buffer.toString();
    }


    /**
     * Strip html tags out of text and mask certain characters.
     *
     * @param   text    strip this text
     * @return  striped text
     */
    public final static String stripTags(final String text) {

        final StringBuffer buffer = new StringBuffer(text.length());
        boolean quoted = false;
        for (int i = 0; i < text.length(); i++) {
            final char c = text.charAt(i);
            switch (c) {
            case '\"':  quoted = !quoted;
                break;
            case '<':
                if (!quoted) {
                    do {
                        i++;
                    } while (i < text.length() && text.charAt(i) != '>');
                } else {
                    buffer.append("&lt;");
                }
                break;
            case '>': buffer.append("&gt;");
                break;
            case '&': buffer.append("&amp;");
                break;
            default:
                buffer.append(c);
            }
        }
        return buffer.toString();
    }


}
