/* 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.ArrayList;
import java.util.List;
import net.fichotheque.corpus.fiche.FicheBlock;
import net.fichotheque.corpus.fiche.P;
import net.fichotheque.corpus.fiche.S;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.jsoup.nodes.TextNode;


/**
 *
 * @author Vincent Calame
 */
public abstract class ElementHandler {

    public ElementHandler() {

    }

    public abstract int handle(Element element, FlowBuffer flowBuffer);


    public List<FicheBlock> convertChildNodes(Element parent) {
        return convertChildNodes(parent.childNodes());
    }

    public List<FicheBlock> convertChildNodes(List<Node> nodeList) {
        InternalFlowBuffer flowBuffer = new InternalFlowBuffer();
        int skip = 0;
        for (Node node : nodeList) {
            if (skip > 0) {
                skip--;
                continue;
            }
            if (node instanceof TextNode) {
                flowBuffer.addInlindeNode(node);
            } else if (node instanceof Element) {
                Element child = (Element) node;
                skip = handle(child, flowBuffer);
                if (skip == 0) {
                    if (InlineConversion.canConvert(child)) {
                        flowBuffer.addInlindeNode(child);
                    } else {
                        String text = child.text();
                        if (text.length() > 0) {
                            flowBuffer.addInlindeNode(new TextNode(text));
                        }
                    }
                } else {
                    skip--;
                }
            }
        }
        flowBuffer.flushInline();
        return flowBuffer.result;
    }


    private static class InternalFlowBuffer implements FlowBuffer {

        private final List<FicheBlock> result = new ArrayList<FicheBlock>();
        private final List<Node> inlineNodeList = new ArrayList<Node>();
        private int emptyLines = 0;

        private InternalFlowBuffer() {

        }

        private void addInlindeNode(Node node) {
            inlineNodeList.add(node);
        }


        @Override
        public void flushInline() {
            if (inlineNodeList.isEmpty()) {
                return;
            }
            ContentBuffer buf = ContentBuffer.init()
                    .add(inlineNodeList);
            if (!buf.isEmpty()) {
                P p = new P();
                buf.flush(p);
                result.add(p);
                emptyLines = 0;
            }
            inlineNodeList.clear();
        }

        @Override
        public void addFicheBlock(FicheBlock ficheBlock) {
            flushInline();
            if (ficheBlock != null) {
                if (isWhiteLine(ficheBlock)) {
                    emptyLines++;
                } else {
                    if ((emptyLines > 1) && (ficheBlock instanceof P)) {
                        for (int i = 1; i < emptyLines; i++) {
                            result.add(new P());
                        }
                    }
                    emptyLines = 0;
                    result.add(ficheBlock);
                }
            }
        }

    }

    private static boolean isWhiteLine(FicheBlock ficheBlock) {
        if (!(ficheBlock instanceof P)) {
            return false;
        }
        P p = (P) ficheBlock;
        int size = p.size();
        if (size == 0) {
            return true;
        }
        if (size == 1) {
            Object first = p.get(0);
            if ((first instanceof S) && (((S) first).getType() == S.BR)) {
                return true;
            }
        }
        return false;
    }

}
