/* FichothequeLib_Import - Copyright (c) 2019-2025 Vincent Calame - Exemole
 * Logiciel libre donné sous triple licence :
 * 1) selon les termes de la CeCILL V2
 * 2) selon les termes de l’EUPL V.1.1
 * 3) selon les termes de la GNU GPLv3
 * Voir le fichier licences.txt
 */


package net.fichotheque.tools.from.html;

import java.util.Collections;
import java.util.List;
import net.fichotheque.corpus.fiche.AttConsumer;
import net.fichotheque.corpus.fiche.Code;
import net.fichotheque.corpus.fiche.FicheBlock;
import net.fichotheque.corpus.fiche.Li;
import net.fichotheque.corpus.fiche.Ln;
import net.fichotheque.corpus.fiche.P;
import net.fichotheque.corpus.fiche.ParagraphBlock;
import net.fichotheque.corpus.fiche.S;
import net.fichotheque.corpus.fiche.Table;
import net.fichotheque.corpus.fiche.Td;
import net.fichotheque.corpus.fiche.Tr;
import net.fichotheque.corpus.fiche.Ul;
import net.fichotheque.tools.from.html.handlers.LiHandler;
import net.mapeadores.util.text.StringUtils;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.jsoup.nodes.TextNode;


/**
 *
 * @author Vincent Calame
 */
public final class BlockConversion {

    private BlockConversion() {

    }

    public static void populate(Element element, ParagraphBlock paragraphBlock) {
        ContentBuffer.init()
                .add(element.childNodes())
                .flush(paragraphBlock);
    }

    public static FicheBlock fromPre(Element element) {
        Code code = new Code(Code.TYPE_NONE);
        String[] lines = StringUtils.getLineTokens(element.wholeText(), StringUtils.NOTCLEAN);
        for (String line : lines) {
            int indent = StringUtils.getIndent(line);
            code.add(new Ln(line, indent));
        }
        return code;
    }

    public static FicheBlock fromList(Element element, boolean ordered) {
        Ul ul = null;
        for (Element child : element.children()) {
            Li li;
            if (child.tagName().equals("li")) {
                li = convertLi(child.childNodes());
            } else {
                li = convertLi(Collections.singletonList(child));
            }
            if (li != null) {
                if (ul == null) {
                    ul = new Ul(li);
                } else {
                    ul.add(li);
                }
            }
        }
        if (ul != null) {
            if (ordered) {
                ul.putAtt("variant", "ol");
                addAttribute(element, ul, "type");
                addAttribute(element, ul, "start");
                addAttribute(element, ul, "reversed");
            }
            return ul;
        } else {
            return null;
        }
    }

    public static FicheBlock fromTable(Element element) {
        Table table = new Table();
        for (Element child : element.children()) {
            switch (child.tagName()) {
                case "caption":
                    ContentBuffer.init()
                            .add(child.childNodes())
                            .flush(table.getLegendeBuilder());
                    break;
                case "thead":
                case "tbody":
                case "tfoot":
                    convertTablePart(child, table);
                    break;
                case "tr":
                    convertTr(child, table);
            }
        }
        return table;
    }

    private static Li convertLi(List<Node> nodeList) {
        List<FicheBlock> ficheBlockList = LiHandler.INSTANCE.convertChildNodes(nodeList);
        int size = ficheBlockList.size();
        if (size == 0) {
            return null;
        }
        FicheBlock firstFicheBlock = ficheBlockList.get(0);
        Li li;
        if (firstFicheBlock instanceof P) {
            li = new Li((P) firstFicheBlock);
        } else {
            li = new Li(new P());
            li.add(firstFicheBlock);
        }
        for (int i = 1; i < size; i++) {
            li.add(ficheBlockList.get(i));
        }
        return li;
    }

    private static void convertTablePart(Element tablePart, Table table) {
        for (Element child : tablePart.children()) {
            if (child.tagName().equals("tr")) {
                convertTr(child, table);
            }
        }
    }

    private static void convertTr(Element row, Table table) {
        Tr tr = new Tr();
        for (Element child : row.children()) {
            Td td = null;
            switch (child.tagName()) {
                case "th":
                    td = new Td(Td.HEADER);
                    break;
                case "td":
                    td = new Td();
                    break;
            }
            if (td != null) {
                ContentBuffer buf = new ContentBuffer();
                flatBlocks(child, buf);
                buf.flush(td);
                tr.add(td);
            }
        }
        table.add(tr);
    }

    private static void flatBlocks(Element parent, ContentBuffer contentBuffer) {
        boolean next = false;
        for (Node node : parent.childNodes()) {
            if (node instanceof TextNode) {
                boolean done = contentBuffer.addPart(((TextNode) node).text());
                if (done) {
                    next = true;
                }
            } else if (node instanceof Element) {
                Element child = (Element) node;
                switch (TagUtils.getTagType(child)) {
                    case TagUtils.BLOCK_TYPE:
                        if (next) {
                            if (!contentBuffer.isBrLast()) {
                                contentBuffer.addPart(new S(S.BR));
                            }
                        } else {
                            next = true;
                        }
                        flatBlocks(child, contentBuffer);
                        break;
                    case TagUtils.INLINE_TYPE:
                        int previousSize = contentBuffer.size();
                        contentBuffer.add(child);
                        if (contentBuffer.size() > previousSize) {
                            next = true;
                        }
                        break;
                }
            }
        }
    }

    private static void addAttribute(Element element, AttConsumer attConsumer, String name) {
        String value = element.attr(name);
        if (!value.isEmpty()) {
            attConsumer.putAtt(name, value);
        }
    }

}
