package de.duehl.basics.zzzunused.text.html.generation;

/*
 * Copyright 2018 Christian Dühl. All rights reserved.
 *
 * This program is free software. You can redistribute it and/or
 * modify it under the same terms as perl:
 *
 * general:  http://dev.perl.org/licenses/
 * GPL:      http://dev.perl.org/licenses/gpl1.html
 * artistic: http://dev.perl.org/licenses/artistic.html
 */

import de.duehl.basics.text.Text;
import de.duehl.basics.text.html.HtmlTool;
import de.duehl.basics.text.html.generation.HtmlHeader;
import de.duehl.basics.text.html.generation.HtmlHeaderType;

import static de.duehl.basics.text.html.generation.HtmlHeaderType.H1;
import static de.duehl.basics.text.html.generation.HtmlHeaderType.H2;
import static de.duehl.basics.text.html.generation.HtmlHeaderType.H3;
import static de.duehl.basics.text.html.generation.HtmlHeaderType.H4;
import static de.duehl.basics.text.html.generation.HtmlHeaderType.H5;
import static de.duehl.basics.text.html.generation.HtmlHeaderType.H6;

import java.util.ArrayList;
import java.util.List;

/**
 * Diese Klasse stellt einen StringBuilder zum Erstellen von HTML-Seiten dar.
 *
 * @version 1.01     2018-09-19
 * @author Christian Dühl
 */

public class ManualIndentationHtmlBuilder {

    /** Intern verwendeter StringBuilder. */
    protected final StringBuilder builder;

    private int numberOfH1 = 0;
    private int numberOfH2 = 0;
    private int numberOfH3 = 0;
    private int numberOfH4 = 0;
    private int numberOfH5 = 0;
    private int numberOfH6 = 0;

    private List<HtmlHeader> headers;

    private boolean hasContents;

    /** Konstruktor. */
    public ManualIndentationHtmlBuilder() {
        builder = new StringBuilder();
        headers = new ArrayList<>();
        hasContents = false;
    }

    /** Löscht den Inhalt des HtmlBuilders. */
    public ManualIndentationHtmlBuilder clear() {
        builder.setLength(0);
        return this;
    }

    /**
     * Fügt einen Kopf mit selbst erzeugtem CSS für body, p und die Überschriften hinzu.
     *
     * @param pageTitle
     *            Titel der Seite.
     */
    public ManualIndentationHtmlBuilder appendHeadWithOwnCss(String pageTitle) {
        boolean useUtf8 = false;
        appendHeadWithOwnCssInternal(pageTitle, useUtf8);
        return this;
    }

    /**
     * Fügt einen Kopf mit selbst erzeugtem CSS für body, p und die Überschriften hinzu, wobei eine
     * Metainformation ergänzt wird, dass der Inhalt in UTF-8 vorliegt.
     *
     * @param pageTitle
     *            Titel der Seite.
     */
    public ManualIndentationHtmlBuilder appendHeadWithOwnCssUtf8(String pageTitle) {
        boolean useUtf8 = true;
        appendHeadWithOwnCssInternal(pageTitle, useUtf8);
        return this;
    }

    /**
     * Fügt einen Kopf mit selbst erzeugtem CSS für body, p und die Überschriften hinzu.
     *
     * @param pageTitle
     *            Titel der Seite.
     * @param useUtf8
     *            Gibt an, ob eine Metainformation ergänzt wird, dass der Inhalt in UTF-8 vorliegt.
     */
    private ManualIndentationHtmlBuilder appendHeadWithOwnCssInternal(String pageTitle, boolean useUtf8) {
        appendUpperHeadPart(pageTitle);
        if (useUtf8) {
            appendMetaUtf8();
        }
        appendOwnCssToHead();
        appendLowerHeadPart();
        return this;
    }

    /**
     * Fügt einen Kopf mit der CSS-Datei format.css im gleichen Verzeichnis hinzu.
     *
     * Das macht natürlich nur Sinn, wenn der Inhalt des Builders anschließend gespeichert wird.
     *
     * @param pageTitle
     *            Titel der Seite.
     */
    public ManualIndentationHtmlBuilder appendHeadWithFormatCssInSameDirectory(String pageTitle) {
        boolean useUtf8 = false;
        appendHeadWithFormatCssInSameDirectoryInternal(pageTitle, useUtf8);
        return this;
    }

    /**
     * Fügt einen Kopf mit der CSS-Datei format.css im gleichen Verzeichnis hinzu, wobei eine
     * Metainformation ergänzt wird, dass der Inhalt in UTF-8 vorliegt.
     *
     * Das macht natürlich nur Sinn, wenn der Inhalt des Builders anschließend gespeichert wird.
     *
     * @param pageTitle
     *            Titel der Seite.
     */
    public ManualIndentationHtmlBuilder appendHeadWithFormatCssInSameDirectoryUtf8(String pageTitle) {
        boolean useUtf8 = true;
        appendHeadWithFormatCssInSameDirectoryInternal(pageTitle, useUtf8);
        return this;
    }

    /**
     * Fügt einen Kopf mit der CSS-Datei format.css im gleichen Verzeichnis hinzu.
     *
     * Das macht natürlich nur Sinn, wenn der Inhalt des Builders anschließend gespeichert wird.
     *
     * @param pageTitle
     *            Titel der Seite.
     * @param useUtf8
     *            Gibt an, ob eine Metainformation ergänzt wird, dass der Inhalt in UTF-8 vorliegt.
     */
    private ManualIndentationHtmlBuilder appendHeadWithFormatCssInSameDirectoryInternal(
            String pageTitle, boolean useUtf8) {
        appendUpperHeadPart(pageTitle);
        if (useUtf8) {
            appendMetaUtf8();
        }
        appendFormatInSameDirectoryCssToHead();
        appendLowerHeadPart();
        return this;
    }

    /**
     * Fügt einen Kopf mit der CSS-Datei format.css im darüberliegendem Verzeichnis hinzu.
     *
     * Das macht natürlich nur Sinn, wenn der Inhalt des Builders anschließend gespeichert wird.
     *
     * @param pageTitle
     *            Titel der Seite.
     */
    public ManualIndentationHtmlBuilder appendHeadWithFormatCssInUpperDirectory(String pageTitle) {
        boolean useUtf8 = false;
        appendHeadWithFormatCssInUpperDirectoryInternal(pageTitle, useUtf8);
        return this;
    }

    /**
     * Fügt einen Kopf mit der CSS-Datei format.css im darüberliegendem Verzeichnis hinzu, wobei
     * eine Metainformation ergänzt wird, dass der Inhalt in UTF-8 vorliegt.
     *
     * Das macht natürlich nur Sinn, wenn der Inhalt des Builders anschließend gespeichert wird.
     *
     * @param pageTitle
     *            Titel der Seite.
     */
    public ManualIndentationHtmlBuilder appendHeadWithFormatCssInUpperDirectoryUtf8(String pageTitle) {
        boolean useUtf8 = true;
        appendHeadWithFormatCssInUpperDirectoryInternal(pageTitle, useUtf8);
        return this;
    }

    /**
     * Fügt einen Kopf mit der CSS-Datei format.css im darüberliegendem Verzeichnis hinzu.
     *
     * Das macht natürlich nur Sinn, wenn der Inhalt des Builders anschließend gespeichert wird.
     *
     * @param pageTitle
     *            Titel der Seite.
     * @param useUtf8
     *            Gibt an, ob eine Metainformation ergänzt wird, dass der Inhalt in UTF-8 vorliegt.
     */
    private ManualIndentationHtmlBuilder appendHeadWithFormatCssInUpperDirectoryInternal(
            String pageTitle, boolean useUtf8) {
        appendUpperHeadPart(pageTitle);
        if (useUtf8) {
            appendMetaUtf8();
        }
        appendFormatInUpperDirectoryCssToHead();
        appendLowerHeadPart();
        return this;
    }

    /**
     * Erzeugt den Anfang des HTML-Kopfes.
     *
     * @param pageTitle
     *            Titel der Seite.
     */
    private ManualIndentationHtmlBuilder appendUpperHeadPart(String pageTitle) {
        append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" ");
        appendLn("\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">");
        appendLineBreak();
        appendLn("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"de\" lang=\"de\">");
        appendLn("<head>");
        appendLn("    <title>" + pageTitle + "</title>");
        return this;
    }

    /**
     * Fügt einen Kopf für HTML 5 hinzu.
     *
     * @param pageTitle
     *            Titel der Seite.
     */
    public ManualIndentationHtmlBuilder appendHtml5HeadWithTitle(String pageTitle) {
        appendUpperHeadPartHtml5(pageTitle);
        appendLowerHeadPart();
        return this;
    }

    /**
     * Fügt einen Kopf für HTML 5 hinzu.
     *
     * @param pageTitle
     *            Titel der Seite.
     * @param cssFilename
     *            Name der CSS-Datei.
     */
    public ManualIndentationHtmlBuilder appendHtml5HeadWithTitleAndCssFilename(String pageTitle, String cssFilename) {
        appendUpperHeadPartHtml5(pageTitle);
        appendMetaCssFilename(cssFilename);
        appendLowerHeadPart();
        return this;
    }

    /**
     * Fügt einen Kopf für HTML 5 hinzu.
     *
     * @param pageTitle
     *            Titel der Seite.
     * @param cssFilename
     *            Name der CSS-Datei.
     * @param javaScript
     *            JavaScript, welches in den Kopf eingebettet wird. Hier kann auch sonstiges
     *            "fertiges" HTML mitgegeben werden, das im Kopf-Bereich eingefügt werden soll.
     */
    public ManualIndentationHtmlBuilder appendHtml5HeadWithTitleCssFilenameAndJavaScript(String pageTitle,
            String cssFilename, String javaScript) {
        appendUpperHeadPartHtml5(pageTitle);
        appendMetaCssFilename(cssFilename);
        append(javaScript);
        appendLowerHeadPart();
        return this;
    }

    /**
     * Fügt einen Kopf für HTML 5 hinzu.
     *
     * @param pageTitle
     *            Titel der Seite.
     * @param cssFilenames
     *            Liste mit Namen von CSS-Dateien.
     * @param javaScript
     *            JavaScript, welches in den Kopf eingebettet wird. Hier kann auch sonstiges
     *            "fertiges" HTML mitgegeben werden, das im Kopf-Bereich eingefügt werden soll.
     */
    public ManualIndentationHtmlBuilder appendHtml5HeadWithTitleMultipleCssFilenameAndJavaScript(String pageTitle,
            List<String> cssFilenames, String javaScript) {
        appendUpperHeadPartHtml5(pageTitle);
        for (String cssFilename : cssFilenames) {
            appendMetaCssFilename(cssFilename);
        }
        append(javaScript);
        appendLowerHeadPart();
        return this;
    }

    /**
     * Fügt einen Kopf für HTML 5 hinzu.
     *
     * @param pageTitle
     *            Titel der Seite.
     * @param javaScript
     *            JavaScript, welches in den Kopf eingebettet wird. Hier kann auch sonstiges
     *            "fertiges" HTML mitgegeben werden, das im Kopf-Bereich eingefügt werden soll.
     * @param cssFilenames
     *            Mehrere Namen von CSS-Dateien.
     */
    public ManualIndentationHtmlBuilder appendHtml5HeadWithTitleJavaScriptAndMultipleCssFilenames(String pageTitle,
            String javaScript, String ... cssFilenames) {
        appendUpperHeadPartHtml5(pageTitle);
        for (String cssFilename : cssFilenames) {
            appendMetaCssFilename(cssFilename);
        }
        append(javaScript);
        appendLowerHeadPart();
        return this;
    }

    /**
     * Erzeugt den Anfang des HTML5-Kopfes.
     *
     * @param pageTitle
     *            Titel der Seite.
     */
    private ManualIndentationHtmlBuilder appendUpperHeadPartHtml5(String pageTitle) {
        appendLn("<!DOCTYPE html>");
        appendLn("<html>");
        appendLn("<head>");
        appendLn("    <title>" + pageTitle + "</title>");
        return this;
    }

    /** Ergänzt eine Metainformation, dass der Inhalt in UTF-8 vorliegt. */
    private ManualIndentationHtmlBuilder appendMetaUtf8() {
        appendLn("        <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">");
        return this;
    }

    /**
     * Ergänzt eine Metainformation zur einzubindenden CSS-Datei.
     *
     * @param cssFilename
     *            Name der CSS-Datei.
     */
    private ManualIndentationHtmlBuilder appendMetaCssFilename(String cssFilename) {
        appendLn("        "
                + "<link href=\"" + cssFilename + "\" rel=\"stylesheet\" type=\"text/css\" />");
        return this;
    }

    /** Erzeugt den Abschluss des HTML-Kopfes. */
    private ManualIndentationHtmlBuilder appendLowerHeadPart() {
        appendLn("</head>");
        appendLineBreak();
        appendLineBreak();
        appendLn("<body>");
        return this;
    }

    /** Erzeugt das eigene CSS für body, p und die Überschriften. */
    private ManualIndentationHtmlBuilder appendOwnCssToHead() {
        appendLn("    <style>");
        appendLn("        body {");
        appendLn("               background-color:#E6E6FF;");
        appendLn("               color:#000096;");
        appendLn("               font-family:Verdana, sans-serif;");
        appendLn("               font-size:14pt;");
        appendLn("               margin-left:3%;");
        appendLn("               margin-right:3%;");
        appendLn("               color:#000096;");
        appendLn("             }");
        appendLn("        p    {");
        appendLn("               font-size:1em;");
        appendLn("               font-family:Verdana, sans-serif;");
        appendLn("               color:#000096;");
        appendLn("             }");
        appendLn("        h1   {");
        appendLn("               text-align: left;");
        appendLn("               font-size: 36pt;");
        appendLn("               font-weight: bold;");
        appendLn("               color:#000096;");
        appendLn("             }");
        appendLn("        h2   {");
        appendLn("               text-align: left;");
        appendLn("               font-size: 24pt;");
        appendLn("               font-weight: bold;");
        appendLn("               color:#000096;");
        appendLn("               margin-bottom:8;");
        appendLn("               margin-top:15;");
        appendLn("             }");
        appendLn("        h3   {");
        appendLn("               font-size: 20pt;");
        appendLn("               color:#000096;");
        appendLn("               margin-bottom:0;");
        appendLn("             }");
        appendLn("        h4   {");
        appendLn("               font-size: 18pt;");
        appendLn("               color:#000096;");
        appendLn("               margin-bottom:0;");
        appendLn("             }");
        appendLn("        h5   {");
        appendLn("               font-size: 16pt;");
        appendLn("               color:#000096;");
        appendLn("               margin-bottom:0;");
        appendLn("             }");
        appendLn("        h6   {");
        appendLn("               font-size: 15pt;");
        appendLn("               color:#000096;");
        appendLn("               margin-bottom:0;");
        appendLn("             }");
        appendLn("        .monospace { font-family: monospace; }");
        appendLn("    </style>");
        appendLineBreak();
        return this;
    }

    /** Ergänzt den Hinweis auf die CSS-Datei format.css im gleichen Verzeichnis. */
    private ManualIndentationHtmlBuilder appendFormatInSameDirectoryCssToHead() {
        appendLn("    <link href=\"format.css\" rel=\"stylesheet\" type=\"text/css\" />");
        return this;
    }

    /** Ergänzt den Hinweis auf die CSS-Datei format.css im darüberliegendem Verzeichnis. */
    private ManualIndentationHtmlBuilder appendFormatInUpperDirectoryCssToHead() {
        appendLn("    <link href=\"./format.css\" rel=\"stylesheet\" type=\"text/css\" />");
        return this;
    }

    /** Fügt beliebigen Text hinzu. */
    public ManualIndentationHtmlBuilder append(String text) {
        builder.append(text);
        return this;
    }

    /** Fügt beliebigen Text und einen Zeilenumbruch hinzu. */
    public ManualIndentationHtmlBuilder appendLn(String text) {
        append(text);
        appendLineBreak();
        return this;
    }

    /**
     * Fügt beliebigen Text und einen Zeilenumbruch hinzu. Vor dem Text werden Leerzeichen in der
     * gewünschten Anzahl ausgegeben.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem öffnenden ol-Tag.
     * @param text Auszugebender Text.
     */
    public ManualIndentationHtmlBuilder appendLn(int frontSpaceSize, String text) {
        appendSpaces(frontSpaceSize);
        return appendLn(text);
    }

    /** Fügt eine Zahl hinzu. */
    public ManualIndentationHtmlBuilder append(int number) {
        builder.append(Integer.toString(number));
        return this;
    }

    /** Schreibt einen öffnenden div-Tag in die Ausgabe. */
    public ManualIndentationHtmlBuilder appendOpeningDiv() {
        append("<div>");
        appendLineBreak();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten öffnenden div-Tag in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem öffnenden div-Tag.
     */
    public ManualIndentationHtmlBuilder appendOpeningDiv(int frontSpaceSize) {
        appendSpaces(frontSpaceSize);
        appendOpeningDiv();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten öffnenden div-Tag in die Ausgabe.
     *
     * @param cssClass
     *            CSS-Klasse.
     */
    public ManualIndentationHtmlBuilder appendOpeningDiv(String cssClass) {
        append("<div class=\"" + cssClass + "\">");
        appendLineBreak();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten öffnenden div-Tag in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem öffnenden div-Tag.
     * @param cssClass
     *            CSS-Klasse.
     */
    public ManualIndentationHtmlBuilder appendOpeningDiv(int frontSpaceSize, String cssClass) {
        appendSpaces(frontSpaceSize);
        appendOpeningDiv(cssClass);
        return this;
    }

    /** Schreibt einen schließenden div-Tag in die Ausgabe. */
    public ManualIndentationHtmlBuilder appendClosingDiv() {
        append("</div>");
        appendLineBreak();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten schließenden div-Tag in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem schließenden div-Tag.
     */
    public ManualIndentationHtmlBuilder appendClosingDiv(int frontSpaceSize) {
        appendSpaces(frontSpaceSize);
        appendClosingDiv();
        return this;
    }

    /** Schreibt einen öffnenden ol-Tag in die Ausgabe. */
    public ManualIndentationHtmlBuilder appendOpeningOl() {
        append("<ol>");
        appendLineBreak();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten öffnenden ol-Tag in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem öffnenden ol-Tag.
     */
    public ManualIndentationHtmlBuilder appendOpeningOl(int frontSpaceSize) {
        appendSpaces(frontSpaceSize);
        appendOpeningOl();
        return this;
    }

    /**
     * Schreibt einen öffnenden ol-Tag in die Ausgabe, der bei der angegebenen Nummer beginnt.
     *
     * @param min
     *            Erste Zahl in der Aufzählung.
     */
    public ManualIndentationHtmlBuilder appendOpeningOlStart(int min) {
        append("<ol start=\"" + min + "\">");
        appendLineBreak();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten öffnenden ol-Tag in die Ausgabe, der bei der angegebenen
     * Nummer beginnt.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem öffnenden ol-Tag.
     * @param min
     *            Erste Zahl in der Aufzählung.
     */
    public ManualIndentationHtmlBuilder appendOpeningOlStart(int frontSpaceSize, int min) {
        appendSpaces(frontSpaceSize);
        appendOpeningOlStart(min);
        return this;
    }

    /** Schreibt einen schließenden ol-Tag in die Ausgabe. */
    public ManualIndentationHtmlBuilder appendClosingOl() {
        append("</ol>");
        appendLineBreak();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten schließenden ol-Tag in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem schließenden ol-Tag.
     */
    public ManualIndentationHtmlBuilder appendClosingOl(int frontSpaceSize) {
        appendSpaces(frontSpaceSize);
        appendClosingOl();
        return this;
    }

    /** Schreibt einen öffnenden ul-Tag in die Ausgabe. */
    public ManualIndentationHtmlBuilder appendOpeningUl() {
        append("<ul>");
        appendLineBreak();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten öffnenden ul-Tag in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem öffnenden ul-Tag.
     */
    public ManualIndentationHtmlBuilder appendOpeningUl(int frontSpaceSize) {
        appendSpaces(frontSpaceSize);
        appendOpeningUl();
        return this;
    }

    /** Schreibt einen schließenden ul-Tag in die Ausgabe. */
    public ManualIndentationHtmlBuilder appendClosingUl() {
        append("</ul>");
        appendLineBreak();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten schließenden ul-Tag in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem schließenden ul-Tag.
     */
    public ManualIndentationHtmlBuilder appendClosingUl(int frontSpaceSize) {
        appendSpaces(frontSpaceSize);
        appendClosingUl();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten öffnenden li-Tag in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem öffnenden li-Tag.
     */
    public ManualIndentationHtmlBuilder appendOpeningLi(int frontSpaceSize) {
        appendSpaces(frontSpaceSize);
        appendOpeningLi();
        return this;
    }

    /** Schreibt einen öffnenden li-Tag in die Ausgabe. */
    public ManualIndentationHtmlBuilder appendOpeningLi() {
        append("<li>");
        appendLineBreak();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten schließenden li-Tag in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem schließenden li-Tag.
     */
    public ManualIndentationHtmlBuilder appendClosingLi(int frontSpaceSize) {
        appendSpaces(frontSpaceSize);
        appendClosingLi();
        return this;
    }

    /** Schreibt einen schließenden li-Tag in die Ausgabe. */
    public ManualIndentationHtmlBuilder appendClosingLi() {
        append("</li>");
        appendLineBreak();
        return this;
    }

    /**
     * Schreibt einen einzeiligen li-Tag in die Ausgabe.
     *
     * @param text
     *            Inhalt des li-Tags.
     */
    public ManualIndentationHtmlBuilder appendLi(String text) {
        append("<li>");
        append(text);
        appendLn("</li>");
        return this;
    }

    /**
     * Schreibt einen passend eingerückten einzeiligen li-Tag in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem li-Tag.
     * @param text
     *            Inhalt des li-Tags.
     */
    public ManualIndentationHtmlBuilder appendLi(int frontSpaceSize, String text) {
        appendSpaces(frontSpaceSize);
        appendLi(text);
        return this;
    }

    /**
     * Schreibt einen passend eingerückten einzeiligen li-Tag in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem li-Tag.
     * @param number
     *            Inhalt des li-Tags in Form einer Zahl.
     */
    public ManualIndentationHtmlBuilder appendLi(int frontSpaceSize, int number) {
        appendLi(frontSpaceSize, Integer.toString(number));
        return this;
    }

    /**
     * Schreibt einen passend eingerückten öffnenden table-Tag in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem öffnenden table-Tag.
     */
    public ManualIndentationHtmlBuilder appendOpeningTable(int frontSpaceSize) {
        appendSpaces(frontSpaceSize);
        appendOpeningTable();
        return this;
    }

    /** Schreibt einen öffnenden table-Tag in die Ausgabe. */
    public ManualIndentationHtmlBuilder appendOpeningTable() {
        append("<table>");
        appendLineBreak();
        return this;
    }

    /**
     * Schreibt einen öffnenden table-Tag mit Rahmen in die Ausgabe.
     *
     * @param borderWidth
     *            Breite des Rahmens um die Tabelle.
     */
    public ManualIndentationHtmlBuilder appendOpeningTableWithBorder(int borderWidth) {
        append("<table border=\"" + borderWidth + "\">");
        appendLineBreak();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten öffnenden table-Tag mit Rahmen in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem öffnenden table-Tag.
     * @param borderWidth
     *            Breite des Rahmens um die Tabelle.
     */
    public ManualIndentationHtmlBuilder appendOpeningTableWithBorderWidth(int frontSpaceSize,
            int borderWidth) {
        appendSpaces(frontSpaceSize);
        appendOpeningTableWithBorder(borderWidth);
        return this;
    }

    /**
     * Schreibt einen öffnenden table-Tag mit Rahmen mit spezieller CSS-Klasse in die Ausgabe.
     *
     * @param cssClass
     *            Name der CSS-Klasse.
     */
    private ManualIndentationHtmlBuilder appendOpeningTableWithClass(String cssClass) {
        append("<table class=\"" + cssClass + "\">");
        appendLineBreak();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten öffnenden table-Tag mit spezieller CSS-Klasse in die
     * Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem öffnenden table-Tag.
     * @param cssClass
     *            Name der CSS-Klasse.
     */
    public ManualIndentationHtmlBuilder appendOpeningTableWithClass(int frontSpaceSize, String cssClass) {
        appendSpaces(frontSpaceSize);
        appendOpeningTableWithClass(cssClass);
        return this;
    }

    /**
     * Schreibt einen öffnenden table-Tag mit Rahmen mit spezieller CSS-ID in die Ausgabe.
     *
     * @param cssId
     *            Name der CSS-ID.
     */
    private ManualIndentationHtmlBuilder appendOpeningTableWithId(String cssId) {
        append("<table id=\"" + cssId + "\">");
        appendLineBreak();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten öffnenden table-Tag mit spezieller CSS-ID in die
     * Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem öffnenden table-Tag.
     * @param cssId
     *            Name der CSS-ID.
     */
    public ManualIndentationHtmlBuilder appendOpeningTableWithId(int frontSpaceSize, String cssId) {
        appendSpaces(frontSpaceSize);
        appendOpeningTableWithId(cssId);
        return this;
    }

    /**
     * Schreibt einen öffnenden table-Tag in die Ausgabe.
     *
     * @param borderWidth
     *            Breite des Rahmens um die Tabelle.
     */
    public ManualIndentationHtmlBuilder appendOpeningTableWithBorderWidth(int borderWidth) {
        append("<table border=\"" + borderWidth + "\">");
        appendLineBreak();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten schließenden table-Tag in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem schließenden table-Tag.
     */
    public ManualIndentationHtmlBuilder appendClosingTable(int frontSpaceSize) {
        appendSpaces(frontSpaceSize);
        appendClosingTable();
        return this;
    }

    /** Schreibt einen schließenden table-Tag in die Ausgabe. */
    public ManualIndentationHtmlBuilder appendClosingTable() {
        append("</table>");
        appendLineBreak();
        return this;
    }

    /** Schreibt einen öffnenden thead-Tag in die Ausgabe. */
    public ManualIndentationHtmlBuilder appendOpeningThead() {
        append("<thead>");
        appendLineBreak();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten öffnenden thead-Tag in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem öffnenden thead-Tag.
     */
    public ManualIndentationHtmlBuilder appendOpeningThead(int frontSpaceSize) {
        appendSpaces(frontSpaceSize);
        appendOpeningThead();
        return this;
    }

    /** Schreibt einen schließenden thead-Tag in die Ausgabe. */
    public ManualIndentationHtmlBuilder appendClosingThead() {
        append("</thead>");
        appendLineBreak();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten schließenden thead-Tag in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem schließenden thead-Tag.
     */
    public ManualIndentationHtmlBuilder appendClosingThead(int frontSpaceSize) {
        appendSpaces(frontSpaceSize);
        appendClosingThead();
        return this;
    }

    /** Schreibt einen öffnenden tbody-Tag in die Ausgabe. */
    public ManualIndentationHtmlBuilder appendOpeningTbody() {
        append("<tbody>");
        appendLineBreak();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten öffnenden tbody-Tag in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem öffnenden tbody-Tag.
     */
    public ManualIndentationHtmlBuilder appendOpeningTbody(int frontSpaceSize) {
        appendSpaces(frontSpaceSize);
        appendOpeningTbody();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten öffnenden tbody-Tag mit eigenem CSS-Style in die
     * Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem öffnenden tbody-Tag.
     * @param css
     *            Stil des tbody-Tags.
     */
    public ManualIndentationHtmlBuilder appendOpeningTbody(int frontSpaceSize, String css) {
        appendSpaces(frontSpaceSize);
        appendOpeningTbody(css);
        return this;
    }

    /**
     * Schreibt einen öffnenden tbody-Tag mit eigenem CSS-Style in die Ausgabe.
     *
     * @param css
     *            Stil des tbody-Tags.
     */
    public ManualIndentationHtmlBuilder appendOpeningTbody(String css) {
        append("<tbody style=\"" + css + "\">");
        appendLineBreak();
        return this;
    }

    /** Schreibt einen schließenden tbody-Tag in die Ausgabe. */
    public ManualIndentationHtmlBuilder appendClosingTbody() {
        append("</tbody>");
        appendLineBreak();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten schließenden tbody-Tag in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem schließenden tbody-Tag.
     */
    public ManualIndentationHtmlBuilder appendClosingTbody(int frontSpaceSize) {
        appendSpaces(frontSpaceSize);
        appendClosingTbody();
        return this;
    }

    /** Schreibt einen öffnenden tfoot-Tag in die Ausgabe. */
    public ManualIndentationHtmlBuilder appendOpeningTfoot() {
        append("<tfoot>");
        appendLineBreak();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten öffnenden tfoot-Tag in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem öffnenden tfoot-Tag.
     */
    public ManualIndentationHtmlBuilder appendOpeningTfoot(int frontSpaceSize) {
        appendSpaces(frontSpaceSize);
        appendOpeningTfoot();
        return this;
    }

    /** Schreibt einen schließenden tfoot-Tag in die Ausgabe. */
    public ManualIndentationHtmlBuilder appendClosingTfoot() {
        append("</tfoot>");
        appendLineBreak();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten schließenden tfoot-Tag in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem schließenden tfoot-Tag.
     */
    public ManualIndentationHtmlBuilder appendClosingTfoot(int frontSpaceSize) {
        appendSpaces(frontSpaceSize);
        appendClosingTfoot();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten öffnenden tr-Tag in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem öffnenden tr-Tag.
     */
    public ManualIndentationHtmlBuilder appendOpeningTr(int frontSpaceSize) {
        appendSpaces(frontSpaceSize);
        appendOpeningTr();
        return this;
    }

    /** Schreibt einen öffnenden tr-Tag in die Ausgabe. */
    public ManualIndentationHtmlBuilder appendOpeningTr() {
        append("<tr>");
        appendLineBreak();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten schließenden tr-Tag in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem schließenden tr-Tag.
     */
    public ManualIndentationHtmlBuilder appendClosingTr(int frontSpaceSize) {
        appendSpaces(frontSpaceSize);
        appendClosingTr();
        return this;
    }

    /** Schreibt einen schließenden tr-Tag in die Ausgabe. */
    public ManualIndentationHtmlBuilder appendClosingTr() {
        append("</tr>");
        appendLineBreak();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten th-Tag mit Inhalt in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem th-Tag.
     * @param headerText
     *            Text der in den th-Tag kommt.
     */
    public ManualIndentationHtmlBuilder appendTh(int frontSpaceSize, String headerText) {
        appendSpaces(frontSpaceSize);
        appendInTag("th", headerText);
        return this;
    }

    /**
     * Schreibt einen passend eingerückten th-Tag mit Inhalt und der angegebenen Klasse in die
     * Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem th-Tag.
     * @param headerText
     *            Text der in den th-Tag kommt.
     * @param cssClass
     *            CSS-Klasse.
     */
    public ManualIndentationHtmlBuilder appendTh(int frontSpaceSize, String headerText, String cssClass) {
        appendSpaces(frontSpaceSize);
        appendInTag("th", headerText, cssClass);
        return this;
    }

    /**
     * Schreibt einen passend eingerückten linksbündigen th-Tag mit Inhalt in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem th-Tag.
     * @param text
     *            Text der in den th-Tag kommt.
     */
    public ManualIndentationHtmlBuilder appendLeftAlignedTh(int frontSpaceSize, String text) {
        appendSpaces(frontSpaceSize);

        append("<th align=\"left\">");
        append(text);
        append("</th>");

        appendLineBreak();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten linksbündigen th-Tag mit Inhalt und spezieller
     * CSS-Klasse in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem th-Tag.
     * @param text
     *            Text der in den th-Tag kommt.
     * @param cssClass
     *            Name der CSS-Klasse.
     */
    public ManualIndentationHtmlBuilder appendLeftAlignedThWithClass(int frontSpaceSize, String text,
            String cssClass) {
        appendSpaces(frontSpaceSize);

        append("<th class=\"" + cssClass + "\" align=\"left\">");
        append(text);
        append("</th>");

        appendLineBreak();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten rechtsbündigen th-Tag mit Inhalt in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem th-Tag.
     * @param headerText
     *            Text der in den th-Tag kommt.
     */
    public ManualIndentationHtmlBuilder appendRightAlignedTh(int frontSpaceSize, String text) {
        appendSpaces(frontSpaceSize);

        append("<th align=\"right\">");
        append(text);
        append("</th>");

        appendLineBreak();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten td-Tag mit Inhalt in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem td-Tag.
     * @param dataText
     *            Text der in den td-Tag kommt.
     * @param cssClass
     *            Name der CSS-Klasse.
     */
    public ManualIndentationHtmlBuilder appendTd(int frontSpaceSize, String dataText, String cssClass) {
        appendSpaces(frontSpaceSize);
        appendInTag("td", dataText, cssClass);
        return this;
    }

    /**
     * Schreibt einen passend eingerückten td-Tag mit Inhalt in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem td-Tag.
     * @param dataText
     *            Text der in den td-Tag kommt.
     */
    public ManualIndentationHtmlBuilder appendTd(int frontSpaceSize, String dataText) {
        appendSpaces(frontSpaceSize);
        appendInTag("td", dataText);
        return this;
    }

    /**
     * Schreibt einen passend eingerückten rechtsbündigen td-Tag mit Inhalt in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem th-Tag.
     * @param headerText
     *            Text der in den th-Tag kommt.
     */
    public ManualIndentationHtmlBuilder appendRightAlignedTd(int frontSpaceSize, String text) {
        appendSpaces(frontSpaceSize);

        append("<td align=\"right\">");
        append(text);
        append("</td>");

        appendLineBreak();
        return this;
    }

    /**
     * Schreibt einen passend eingerückten td-Tag mit Inhalt in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem td-Tag.
     * @param number
     *            Zahl die in den td-Tag kommt.
     */
    public ManualIndentationHtmlBuilder appendTd(int frontSpaceSize, int number) {
        appendTd(frontSpaceSize, Integer.toString(number));
        return this;
    }

    /**
     * Fügt einen passend eingerückten, öffnenden blockquote-Tag hinzu.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem blockquote-Tag.
     */
    public ManualIndentationHtmlBuilder appendOpeningQuote(int frontSpaceSize) {
        appendSpaces(frontSpaceSize);
        append("<blockquote>");
        appendLineBreak();
        return this;
    }

    /**
     * Fügt einen passend eingerückten, schließenden blockquote-Tag hinzu.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem blockquote-Tag.
     */
    public ManualIndentationHtmlBuilder appendClosingQuote(int frontSpaceSize) {
        appendSpaces(frontSpaceSize);
        append("</blockquote>");
        appendLineBreak();
        return this;
    }

    /**
     * Fügt Leerzeichen hinzu.
     *
     * @param numberOfSpaces
     *            Anzahl der hinzuzufügenden Leerzeichen.
     */
    public ManualIndentationHtmlBuilder appendSpaces(int numberOfSpaces) {
        append(Text.multipleString(" ", numberOfSpaces));
        return this;
    }

    /**
     * Fügt eine Überschrift erster Ordnung hinzu.
     *
     * @param text
     *            Überschrift.
     */
    public ManualIndentationHtmlBuilder appendH1(String text) {
        return appendH1(0, text);
    }

    /**
     * Fügt eine um die angegebene Anzahl Leerzeichen eingerückte Überschrift erster Ordnung hinzu.
     *
     * @param text
     *            Überschrift.
     * @param frontSpaceSize
     *            Anzahl der hinzuzufügenden Leerzeichen.
     */
    public ManualIndentationHtmlBuilder appendH1(int frontSpaceSize, String text) {
        ++numberOfH1;
        return appendHeader(frontSpaceSize, H1, text);
    }

    /**
     * Fügt eine Überschrift zweiter Ordnung hinzu.
     *
     * @param text
     *            Überschrift.
     */
    public ManualIndentationHtmlBuilder appendH2(String text) {
        return appendH2(0, text);
    }

    /**
     * Fügt eine um die angegebene Anzahl Leerzeichen eingerückte Überschrift zweiter Ordnung hinzu.
     *
     * @param text
     *            Überschrift.
     * @param frontSpaceSize
     *            Anzahl der hinzuzufügenden Leerzeichen.
     */
    public ManualIndentationHtmlBuilder appendH2(int frontSpaceSize, String text) {
        ++numberOfH2;
        return appendHeader(frontSpaceSize, H2, text);
    }

    /**
     * Fügt eine Überschrift dritter Ordnung hinzu.
     *
     * @param text
     *            Überschrift.
     */
    public ManualIndentationHtmlBuilder appendH3(String text) {
        return appendH3(0, text);
    }

    /**
     * Fügt eine um die angegebene Anzahl Leerzeichen eingerückte Überschrift dritter Ordnung hinzu.
     *
     * @param text
     *            Überschrift.
     * @param frontSpaceSize
     *            Anzahl der hinzuzufügenden Leerzeichen.
     */
    public ManualIndentationHtmlBuilder appendH3(int frontSpaceSize, String text) {
        ++numberOfH3;
        return appendHeader(frontSpaceSize, H3, text);
    }

    /**
     * Fügt eine Überschrift vierter Ordnung hinzu.
     *
     * @param text
     *            Überschrift.
     */
    public ManualIndentationHtmlBuilder appendH4(String text) {
        return appendH4(0, text);
    }

    /**
     * Fügt eine um die angegebene Anzahl Leerzeichen eingerückte Überschrift vierter Ordnung hinzu.
     *
     * @param text
     *            Überschrift.
     * @param frontSpaceSize
     *            Anzahl der hinzuzufügenden Leerzeichen.
     */
    public ManualIndentationHtmlBuilder appendH4(int frontSpaceSize, String text) {
        ++numberOfH4;
        return appendHeader(frontSpaceSize, H4, text);
    }

    /**
     * Fügt eine Überschrift fünfter Ordnung hinzu.
     *
     * @param text
     *            Überschrift.
     */
    public ManualIndentationHtmlBuilder appendH5(String text) {
        return appendH5(0, text);
    }

    /**
     * Fügt eine um die angegebene Anzahl Leerzeichen eingerückte Überschrift fünfter Ordnung hinzu.
     *
     * @param text
     *            Überschrift.
     * @param frontSpaceSize
     *            Anzahl der hinzuzufügenden Leerzeichen.
     */
    public ManualIndentationHtmlBuilder appendH5(int frontSpaceSize, String text) {
        ++numberOfH5;
        return appendHeader(frontSpaceSize, H5, text);
    }

    /**
     * Fügt eine Überschrift sechster Ordnung hinzu.
     *
     * @param text
     *            Überschrift.
     */
    public ManualIndentationHtmlBuilder appendH6(String text) {
        return appendH6(0, text);
    }

    /**
     * Fügt eine um die angegebene Anzahl Leerzeichen eingerückte Überschrift sechster Ordnung hinzu.
     *
     * @param text
     *            Überschrift.
     * @param frontSpaceSize
     *            Anzahl der hinzuzufügenden Leerzeichen.
     */
    public ManualIndentationHtmlBuilder appendH6(int frontSpaceSize, String text) {
        ++numberOfH6;
        return appendHeader(frontSpaceSize, H6, text);
    }

    private ManualIndentationHtmlBuilder appendHeader(int frontSpaceSize, HtmlHeaderType headerType, String text) {
        if (headerType == H1 && numberOfH1 > 1) {
            appendToTopLink();
        }

        String id = generateHeaderId(headerType);

        headers.add(new HtmlHeader(headerType, text, id));

        appendLineBreak();
        appendInTagWithParameters(frontSpaceSize, headerType.getHtmlTagName(), text,  "id=\"" + id + "\"");

        appendLineBreak();
        return this;
    }

    /** Fügt einen Link zum Seitenanfang hinzu. */
    public ManualIndentationHtmlBuilder appendToTopLink() {
        append("    <a href=\"#top\">Zum Seitenanfang</a>").appendLineBreak();
        return this;
    }

    private String generateHeaderId(HtmlHeaderType headerType) {
        String id;

        if (headerType == H1) {
            id = "id" + numberOfH1;
        }
        else if (headerType == H2) {
            id = "id" + numberOfH1 + "_" + numberOfH2;
        }
        else if (headerType == H3) {
            id = "id" + numberOfH1 + "_" + numberOfH2 + "_" + numberOfH3;
        }
        else if (headerType == H4) {
            id = "id" + numberOfH1 + "_" + numberOfH2 + "_" + numberOfH3 + "_" + numberOfH4;
        }
        else if (headerType == H5) {
            id = "id" + numberOfH1 + "_" + numberOfH2 + "_" + numberOfH3 + "_" + numberOfH4 + "_"
                    + numberOfH5;
        }
        else if (headerType == H6) {
            id = "id" + numberOfH1 + "_" + numberOfH2 + "_" + numberOfH3 + "_" + numberOfH4 + "_"
                    + numberOfH5 + "_" + numberOfH6;
        }
        else {
            throw new RuntimeException("Unknown header type '" + headerType + "'!");
        }

        return id;
    }

    /**
     * Schreibt einen Paragraphen mit dem übergebenen Text in die Ausgabe.
     *
     * @param text
     *            Text innerhalb des p-Tags.
     */
    public ManualIndentationHtmlBuilder appendP(String text) {
        appendInTag("p", text);
        return this;
    }

    /**
     * Schreibt einen passend eingerückten Paragraphen mit dem übergebenen Text in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem öffnenden p-Tag.
     * @param text
     *            Text innerhalb des p-Tags.
     */
    public ManualIndentationHtmlBuilder appendP(int frontSpaceSize, String text) {
        appendSpaces(frontSpaceSize);
        appendP(text);
        return this;
    }

    /**
     * Schreibt einen Paragraphen mit dem übergebenen Text in einem Monospace-Font in die Ausgabe.
     *
     * @param text
     *            Text innerhalb des p-Tags.
     */
    public ManualIndentationHtmlBuilder appendPTT(String text) {
        appendInTagWithParameters("p", text, "class=\"monospace\"");
        return this;
    }

    /**
     * Schreibt einen passend eingerückten Paragraphen mit dem übergebenen Text in einem
     * Monospace-Font in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem öffnenden p-Tag.
     * @param text
     *            Text innerhalb des p-Tags.
     */
    public ManualIndentationHtmlBuilder appendPTT(int frontSpaceSize, String text) {
        appendSpaces(frontSpaceSize);
        appendPTT(text);
        return this;
    }

    /**
     * Schreibt einen passend eingerückten Paragraphen in kleiner Schriftgröße mit dem übergebenen
     * Text in die Ausgabe.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem öffnenden p-Tag.
     * @param text
     *            Text innerhalb des p-Tags.
     */
    public ManualIndentationHtmlBuilder appendSmallP(int frontSpaceSize, String text) {
        appendSpaces(frontSpaceSize);
        appendSmallP(text);
        return this;
    }

    /**
     * Schreibt einen Paragraphen in kleiner Schriftgröße mit dem übergebenen Text in die Ausgabe.
     *
     * @param text
     *            Text innerhalb des p-Tags.
     */
    public ManualIndentationHtmlBuilder appendSmallP(String text) {
        append("<p style=\"font-size:x-small\">");
        append(text);
        append("</p>");

        appendLineBreak();
        return this;
    }

    /**
     * Schreibt einen grün gefärbten Absatz
     *
     * @param text
     *            Text des Absatzes.
     */
    public ManualIndentationHtmlBuilder appendPGreen(String text) {
        appendP(HtmlTool.green(text));  // TODO ggf. andere Einfärbung nötig in HtmlTool ?
        return this;
    }

    /**
     * Schreibt einen passend eingerückten grün gefärbten Absatz
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem öffnenden p-Tag.
     * @param text
     *            Text des Absatzes.
     */
    public ManualIndentationHtmlBuilder appendPGreen(int frontSpaceSize, String text) {
        appendSpaces(frontSpaceSize);
        appendPGreen(text);
        return this;
    }

    /**
     * Schreibt einen rot gefärbten Absatz
     *
     * @param text
     *            Text des Absatzes.
     */
    public ManualIndentationHtmlBuilder appendPRed(String text) {
        appendP(HtmlTool.red(text));
        return this;
    }

    /**
     * Schreibt einen passend eingerückten rot gefärbten Absatz
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem öffnenden p-Tag.
     * @param text
     *            Text des Absatzes.
     */
    public ManualIndentationHtmlBuilder appendPRed(int frontSpaceSize, String text) {
        appendSpaces(frontSpaceSize);
        appendPRed(text);
        return this;
    }

    /**
     * Schreibt einen orange gefärbten Absatz
     *
     * @param text
     *            Text des Absatzes.
     */
    public ManualIndentationHtmlBuilder appendPOrange(String text) {
        appendP(HtmlTool.orange(text));
        return this;
    }

    /**
     * Schreibt einen passend eingerückten orange gefärbten Absatz
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem öffnenden p-Tag.
     * @param text
     *            Text des Absatzes.
     */
    public ManualIndentationHtmlBuilder appendPOrange(int frontSpaceSize, String text) {
        appendSpaces(frontSpaceSize);
        appendPOrange(text);
        return this;
    }

    /**
     * Fügt einen Link hinzu.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem öffnenden a-Tag.
     * @param url
     *            URL des Links.
     * @param description
     *            Beschreibung des Links.
     */
    public void appendLink(int frontSpaceSize, String url, String description) {
        appendSpaces(frontSpaceSize);
        appendInTagWithParameters("a", description, "href=\"" + url + "\"");
        appendLineBreak();
    }

    /**
     * Fügt einen Text umgeben von einem Tag (öffnender Tag vorn, schließender Tag hinten) ein.
     *
     * @param tag
     *            Name des Tags.
     * @param text
     *            Text innerhalb des Tags.
     */
    public ManualIndentationHtmlBuilder appendInTag(String tag, String text) {
        append("<");
        append(tag);
        append(">");

        append(text);

        append("</");
        append(tag);
        append(">");

        appendLineBreak();
        return this;
    }

    /**
     * Fügt einen Text umgeben von einem Tag (öffnender Tag vorn, schließender Tag hinten) ein.
     *
     * @param tag
     *            Name des Tags.
     * @param text
     *            Text innerhalb des Tags.
     * @param cssClass
     *            CSS-Klasse.
     */
    public ManualIndentationHtmlBuilder appendInTag(String tag, String text, String cssClass) {
        append("<");
        append(tag);
        append(" class=\"");
        append(cssClass);
        append("\"");
        append(">");

        append(text);

        append("</");
        append(tag);
        append(">");

        appendLineBreak();
        return this;
    }

    /**
     * Fügt einen Text umgeben von einem Tag (öffnender Tag vorn, schließender Tag hinten) ein,
     * samt Parameter für den Tag.
     *
     * @param tag
     *            Name des Tags.
     * @param text
     *            Text innerhalb des Tags.
     * @param params
     */
    public ManualIndentationHtmlBuilder appendInTagWithParameters(String tag, String text, String ... params) {
        append("<");
        append(tag);
        for (String param : params) {
            append(" ").append(param);
        }
        append(">");

        append(text);

        append("</");
        append(tag);
        append(">");
        return this;
    }

    /**
     * Fügt einen Text umgeben von einem Tag (öffnender Tag vorn, schließender Tag hinten) ein,
     * samt Parameter für den Tag.
     *
     * @param frontSpaceSize
     *            Anzahl Leerzeichen vor dem blockquote-Tag.
     * @param tag
     *            Name des Tags.
     * @param text
     *            Text innerhalb des Tags.
     * @param params
     */
    public ManualIndentationHtmlBuilder appendInTagWithParameters(int frontSpaceSize, String tag, String text,
            String... params) {
        appendSpaces(frontSpaceSize);
        return appendInTagWithParameters(tag, text, params);
    }

    /** Erzeugt den Abschluss des HTML-Dokuments mit schließendem body- und html-Tag. */
    public ManualIndentationHtmlBuilder appendFoot() {
        appendLineBreak();
        if (hasContents) {
            appendToTopLink();
        }

        append("</body>");
        appendLineBreak();
        append("</html>");
        appendLineBreak();
        return this;
    }

    /** Fügt einen Zeilenumbruch im Dokument, aber nicht im HTML hinzu. */
    public ManualIndentationHtmlBuilder appendLineBreak() {
        append(Text.LINE_BREAK);
        return this;
    }

    /** Fügt einen Zeilenumbruch im HTML und im Dokument hinzu. */
    public ManualIndentationHtmlBuilder appendHtmlLineBreak() {
        append("<br />");
        appendLineBreak();
        return this;
    }

    /** Fügt eine Trennlinie mit etwas Luft nach oben und unten in den Report ein. */
    public ManualIndentationHtmlBuilder appendSeparatoringLine() {
        appendP("");
        appendP("");
        appendLine();
        appendP("");
        return this;
    }

    /** Fügt eine Trennlinie hinzu. */
    public ManualIndentationHtmlBuilder appendLine() {
        append("<hr />");
        appendLineBreak();
        return this;
    }

    /** Fügt den Inhalt eines StringBuilders hinzu. */
    public ManualIndentationHtmlBuilder append(StringBuilder otherBuilder) {
        builder.append(otherBuilder);
        return this;
    }

    /** Fügt den Inhalt eines anderen HtmlBuilders ein. */
    public ManualIndentationHtmlBuilder append(ManualIndentationHtmlBuilder otherBuilder) {
        builder.append(otherBuilder.toString());
        return this;
    }

    /** Gibt die Länge des bisherigen Texts im Builder zurück. */
    public int length() {
        return builder.length();
    }

    /** Fügt einen nicht als HTML interpretieren Abschnitt hinzu. */
    public void appendPre(String text) {
        appendInTag("pre", text);
    }

    /** Fügt ein Inhaltsverzeichnis oben in das HTML-Dokument ein. */
    public ManualIndentationHtmlBuilder insertContent() {
        String body = "<body>";
        int bodyStartIndex = builder.indexOf(body);
        if (bodyStartIndex == -1) {
            throw new RuntimeException("Kein Body-Tag im Html gefunden!");
        }

        int bodyEndIndex = bodyStartIndex + body.length();
        builder.insert(bodyEndIndex, buildContents());
        hasContents = true;
        return this;
    }

    /** Fügt ein Inhaltsverzeichnis unten in das HTML-Dokument ein. */
    public ManualIndentationHtmlBuilder insertContentAtEnd() {
        String body = "</body>";
        int bodyStartIndex = builder.indexOf(body);
        if (bodyStartIndex == -1) {
            throw new RuntimeException("Kein Body-Tag im Html gefunden!");
        }

        builder.insert(bodyStartIndex, buildContents() + Text.LINE_BREAK);
        hasContents = true;
        return this;
    }

    private String buildContents() {
        ManualIndentationHtmlBuilder contentBuilder = new ManualIndentationHtmlBuilder();

        contentBuilder.appendLineBreak()
                .append("    ")
                .appendInTag("h1", "Inhalt");

        for (HtmlHeader header : headers) {
            contentBuilder.append("    ")
                    .append(header.getContentIndentation())
                    .append("<a href=\"#" + header.getId() + "\">" + header.getText() + "</a>")
                    .appendHtmlLineBreak();
        }

        return contentBuilder.toString();
    }

    /** Gibt den Inhalt des Builders als String zurück. */
    @Override
    public String toString() {
        return builder.toString();
    }

}
