/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.maven.doxia.module.xdoc;

import javax.swing.text.html.HTML.Attribute;

import java.io.StringWriter;
import java.io.Writer;

import org.apache.maven.doxia.sink.Sink;
import org.apache.maven.doxia.sink.SinkEventAttributes;
import org.apache.maven.doxia.sink.impl.AbstractSinkTest;
import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
import org.junit.jupiter.api.Test;

import static org.apache.maven.doxia.util.HtmlTools.escapeHTML;
import static org.junit.jupiter.api.Assertions.assertEquals;

/**
 * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
 * @since 1.0
 */
public class XdocSinkTest extends AbstractSinkTest {

    @Test
    public void section1() {
        String title = "Title1";
        getSink().section1();
        getSink().sectionTitle1();
        getSink().text(title);
        getSink().sectionTitle1_();
        getSink().section1_();
        getSink().flush();
        getSink().close();

        String actual = getSinkContent();
        String expected = getSection1Block(title);

        assertEquals(expected, actual, "Wrong section1 block!");
    }

    @Test
    public void section2() {
        String title = "Title2";
        getSink().section2();
        getSink().sectionTitle2();
        getSink().text(title);
        getSink().sectionTitle2_();
        getSink().section2_();
        getSink().flush();
        getSink().close();

        String actual = getSinkContent();
        String expected = getSection2Block(title);

        assertEquals(expected, actual, "Wrong section2 block!");
    }

    protected String outputExtension() {
        return "xml";
    }

    protected Sink createSink(Writer writer) {
        return new XdocSink(writer, "UTF-8");
    }

    protected boolean isXmlSink() {
        return true;
    }

    protected String getTitleBlock(String title) {
        return "<title>" + title + "</title>";
    }

    protected String getAuthorBlock(String author) {
        return author;
    }

    protected String getDateBlock(String date) {
        return date;
    }

    protected String getHeadBlock() {
        return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
                + "<document xmlns=\"http://maven.apache.org/XDOC/2.0\" "
                + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
                + "xsi:schemaLocation=\"http://maven.apache.org/XDOC/2.0 https://maven.apache.org/xsd/xdoc-2.0.xsd\">"
                + "<properties></properties>";
    }

    protected String getBodyBlock() {
        return "<body></body></document>";
    }

    protected String getArticleBlock() {
        return "<article></article>";
    }

    protected String getNavigationBlock() {
        return "<nav></nav>";
    }

    protected String getSidebarBlock() {
        return "<aside></aside>";
    }

    protected String getSection1Block(String title) {
        return "<section name=\"" + title + "\"></section>";
    }

    protected String getSection2Block(String title) {
        return "<subsection name=\"" + title + "\"></subsection>";
    }

    protected String getSection3Block(String title) {
        return "<header>" + EOL + "<h3>" + title + "</h3></header>";
    }

    protected String getSection4Block(String title) {
        return "<header>" + EOL + "<h4>" + title + "</h4></header>";
    }

    protected String getSection5Block(String title) {
        return "<header>" + EOL + "<h5>" + title + "</h5></header>";
    }

    protected String getSection6Block(String title) {
        return "<header>" + EOL + "<h6>" + title + "</h6></header>";
    }

    protected String getHeaderBlock() {
        return "<header></header>";
    }

    protected String getContentBlock() {
        return "<main>" + EOL + "<div class=\"content\"></div></main>";
    }

    protected String getFooterBlock() {
        return "<footer></footer>";
    }

    protected String getListBlock(String item) {
        return "<ul>\n<li>" + item + "</li></ul>";
    }

    protected String getNumberedListBlock(String item) {
        return "<ol style=\"list-style-type: lower-roman;\">\n<li>" + item + "</li></ol>";
    }

    protected String getDefinitionListBlock(String definum, String definition) {
        return "<dl>\n<dt>" + definum + "</dt>\n<dd>" + definition + "</dd></dl>";
    }

    protected String getFigureBlock(String source, String caption) {
        String figureBlock = "<figure><img src=\"" + escapeHTML(source) + "\" />";
        if (caption != null) {
            figureBlock += "<figcaption>" + caption + "</figcaption>";
        }
        figureBlock += "</figure>";
        return figureBlock;
    }

    protected String getTableBlock(String cell, String caption) {
        return "<table border=\"0\"><caption>" + caption + "</caption>\n<tr>\n"
                + "<td style=\"text-align: center;\">" + cell + "</td>\n"
                + "<td>" + cell + "</td>\n"
                + "<td>" + cell + "</td></tr></table>";
    }

    @Override
    protected String getTableWithHeaderBlock(String... rowPrefixes) {
        return "<table border=\"0\">\n<tr>\n<th>" + rowPrefixes[0] + "0</th>\n<th>" + rowPrefixes[0] + "1</th>\n<th>"
                + rowPrefixes[0] + "2</th></tr>\n"
                + "<tr>\n<td style=\"text-align: left;\">" + rowPrefixes[1]
                + "0</td>\n<td style=\"text-align: right;\">" + rowPrefixes[1]
                + "1</td>\n<td style=\"text-align: center;\">" + rowPrefixes[1] + "2</td></tr>\n"
                + "<tr>\n<td style=\"text-align: left;\">" + rowPrefixes[2]
                + "0</td>\n<td style=\"text-align: right;\">" + rowPrefixes[2]
                + "1</td>\n<td style=\"text-align: center;\">" + rowPrefixes[2] + "2</td></tr>"
                + "</table>";
    }

    protected String getParagraphBlock(String text) {
        return "<p>" + text + "</p>";
    }

    protected String getDataBlock(String value, String text) {
        return "<data value=\"" + value + "\">" + text + "</data>";
    }

    protected String getTimeBlock(String datetime, String text) {
        return "<time datetime=\"" + datetime + "\">" + text + "</time>";
    }

    protected String getAddressBlock(String text) {
        return "<address>" + text + "</address>";
    }

    protected String getBlockquoteBlock(String text) {
        return "<blockquote>" + text + "</blockquote>";
    }

    protected String getDivisionBlock(String text) {
        return "<div>" + text + "</div>";
    }

    protected String getVerbatimBlock(String text) {
        return "<pre>" + text + "</pre>";
    }

    protected String getVerbatimSourceBlock(String text) {
        return "<source>" + text + "</source>";
    }

    protected String getHorizontalRuleBlock() {
        return "<hr />";
    }

    protected String getPageBreakBlock() {
        return "<!-- PB -->";
    }

    protected String getAnchorBlock(String anchor) {
        return "<a id=\"" + anchor + "\">" + anchor + "</a>";
    }

    protected String getLinkBlock(String link, String text) {
        return "<a href=\"" + link + "\">" + text + "</a>";
    }

    protected String getInlineBlock(String text) {
        return text;
    }

    protected String getInlineItalicBlock(String text) {
        return "<i>" + text + "</i>";
    }

    protected String getInlineBoldBlock(String text) {
        return "<b>" + text + "</b>";
    }

    protected String getInlineCodeBlock(String text) {
        return "<code>" + text + "</code>";
    }

    protected String getInlineDeleteBlock(String text) {
        return "<del>" + text + "</del>";
    }

    protected String getLineBreakBlock() {
        return "<br />";
    }

    protected String getLineBreakOpportunityBlock() {
        return "<wbr />";
    }

    protected String getNonBreakingSpaceBlock() {
        return "&#160;";
    }

    protected String getTextBlock(String text) {
        // TODO: need to be able to retreive those from outside the sink
        return escapeHTML(text);
    }

    protected String getRawTextBlock(String text) {
        return "~,_=,_-,_+,_*,_[,_],_<,_>,_{,_},_\\";
    }

    /**
     * Test verbatim.
     */
    @Test
    public void verbatimSource() {
        Writer writer = new StringWriter();
        try (XdocSink sink = new XdocSink(writer)) {
            sink.verbatim(null);
            sink.verbatim_();
            sink.verbatim(SinkEventAttributeSet.SOURCE);
            sink.verbatim_();
        }
        assertEquals("<pre></pre><source></source>", writer.toString());
    }

    /**
     * Test link.
     */
    @Test
    void linkWithTarget() {
        Writer writer = new StringWriter();
        try (XdocSink sink = new XdocSink(writer)) {
            sink.link("name");
            sink.link_();
            SinkEventAttributes attrs = new SinkEventAttributeSet();
            attrs.addAttribute(Attribute.TARGET, "nirvana");
            sink.link("name", attrs);
            sink.link_();
        }
        assertEquals("<a href=\"name\"></a><a target=\"nirvana\" href=\"name\"></a>", writer.toString());
    }

    @Override
    protected String getCommentBlock(String text) {
        return "<!--" + toXmlComment(text) + "-->";
    }

    @Override
    protected String getCommentBlockFollowedByParagraph(String comment, String paragraph) {
        return getCommentBlock(comment) + getParagraphBlock(paragraph); // no line break in between
    }
}
