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


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

    private InlineConversion() {

    }

    public static boolean canConvert(Element element) {
        switch (element.tagName()) {
            case "a":
            case "abbr":
            case "b":
            case "br":
            case "cite":
            case "code":
            case "del":
            case "dfn":
            case "em":
            case "font":
            case "i":
            case "img":
            case "ins":
            case "kbd":
            case "q":
            case "samp":
            case "span":
            case "strong":
            case "sub":
            case "sup":
            case "u":
            case "var":
                return true;
            default:
                return false;
        }
    }

    public static void convertInto(Element inlineElement, ContentBuffer contentBuffer) {
        S fromBdfAttributeS = convertFromBdfAttributes(inlineElement);
        if (fromBdfAttributeS != null) {
            appendTo(fromBdfAttributeS, contentBuffer, inlineElement);
            return;
        }
        if (isIgnorable(inlineElement)) {
            contentBuffer.add(inlineElement.childNodes());
            return;
        }
        if (isSplitable(inlineElement)) {
            contentBuffer.add(split(inlineElement));
            return;
        }
        S s = InlineConversion.convert(inlineElement);
        appendTo(s, contentBuffer, inlineElement);
    }

    private static void appendTo(S s, ContentBuffer contentBuffer, Element originElement) {
        String wholeText = originElement.wholeText();
        int wholeTextLength = wholeText.length();
        if (wholeTextLength > 0) {
            if (Character.isWhitespace(wholeText.charAt(0))) {
                contentBuffer.addPart(" ");
            }
        }
        if (s != null) {
            contentBuffer.addPart(s);
        } else {
            contentBuffer.addPart(originElement.text());
        }
        if (wholeTextLength > 0) {
            if (Character.isWhitespace(wholeText.charAt(wholeTextLength - 1))) {
                contentBuffer.addPart(" ");
            }
        }
    }

    private static S convertFromBdfAttributes(Element element) {
        Map<String, String> dataset = element.dataset();
        String bdfType = dataset.get("bdf-type");
        if (bdfType == null) {
            return null;
        }
        short type;
        try {
            type = S.typeToShort(bdfType);
        } catch (IllegalArgumentException iae) {
            type = S.SPAN;
        }
        S fromBdfAttributeS = new S(type);
        fromBdfAttributeS.setValue(element.text());
        String bdfRef = dataset.get("bdf-ref");
        if (bdfRef != null) {
            fromBdfAttributeS.setRef(bdfRef);
        }
        return fromBdfAttributeS;
    }

    private static boolean isIgnorable(Element element) {
        switch (element.tagName()) {
            case "font":
            case "span":
                return true;
            default:
                return false;
        }
    }

    private static boolean isSplitable(Element element) {
        switch (element.tagName()) {
            case "i":
            case "u":
            case "em":
            case "b":
            case "strong":
                if (element.childNodeSize() > 1) {
                    return true;
                } else {
                    return false;
                }
            default:
                return false;
        }
    }

    private static List<Node> split(Element element) {
        String wrap = "<" + element.tagName() + "></" + element.tagName() + ">";
        List<Node> result = new ArrayList<Node>();
        for (Node node : element.childNodes()) {
            result.add(node.wrap(wrap).parent());
        }
        return result;
    }

    private static S convert(Element element) {
        switch (element.tagName()) {
            case "a":
                return convertLink(element);
            case "b":
            case "strong":
                return convertStrg(element);
            case "i":
            case "u":
            case "em":
                return convertEm(element);
            case "img":
                return convertImage(element, null);
            case "abbr":
                return new S(S.ABBR);
            case "br":
                return new S(S.BR);
            case "cite":
                return InlineConversion.convert(S.CITE, element);
            case "code":
                return InlineConversion.convert(S.CODE, element);
            case "del":
                return InlineConversion.convert(S.DELETE, element);
            case "dfn":
                return InlineConversion.convert(S.DEFINITION, element);
            case "ins":
                return InlineConversion.convert(S.INSERT, element);
            case "kbd":
                return InlineConversion.convert(S.KEYBOARD, element);
            case "q":
                return InlineConversion.convert(S.QUOTE, element);
            case "samp":
                return InlineConversion.convert(S.SAMPLE, element);
            case "sub":
                return InlineConversion.convert(S.SUB, element);
            case "sup":
                return InlineConversion.convert(S.SUP, element);
            case "var":
                return InlineConversion.convert(S.VAR, element);
            default:
                return null;
        }
    }

    private static S convert(short type, Element element) {
        return toS(type, element, getRefElement(element));
    }

    private static S convertImage(Element element, Element linkElement) {
        S span = new S(S.IMAGE);
        span.setRef(element.attr("src"));
        addTitle(span, element, linkElement);
        span.setValue(element.attr("alt"));
        if (linkElement != null) {
            addLinkAttributes(linkElement, span);
            addAttribute(linkElement, span, "href");
        }
        return span;
    }

    private static S convertLink(Element element) {
        short type = S.LINK;
        Element loneChild = TagUtils.getLoneChild(element);
        if (loneChild != null) {
            if (loneChild.tagName().equals("img")) {
                return convertImage(loneChild, element);
            }
            type = checkEmStrg(type, loneChild);
        }
        return toS(type, element, element);
    }

    private static S convertStrg(Element element) {
        Element loneChild = TagUtils.getLoneChild(element);
        short type = S.STRONG;
        Element refChild = null;
        if (loneChild != null) {
            refChild = getRefElement(loneChild);
            type = checkEmStrg(type, loneChild);
        }
        return toS(type, element, refChild);
    }

    private static S convertEm(Element element) {
        Element loneChild = TagUtils.getLoneChild(element);
        short type = S.EMPHASIS;

        Element refChild = null;
        if (loneChild != null) {
            refChild = getRefElement(loneChild);
            type = checkEmStrg(type, loneChild);
        }
        if (element.hasClass("STRG")) {
            type = S.EMSTRG;
        }
        return toS(type, element, refChild);
    }

    private static S toS(short type, Element mainElement, Element refElement) {
        S span = new S(type);
        if (refElement != null) {
            span.setRef(refElement.attr("href"));
            addLinkAttributes(refElement, span);
        }
        addTitle(span, mainElement, refElement);
        span.setValue(mainElement.text());
        return span;
    }

    private static void addTitle(S s, Element firstElement, Element secondElement) {
        String title = firstElement.attr("title");
        if ((title.isEmpty()) && (secondElement != null)) {
            title = secondElement.attr("title");
        }
        if (!title.isEmpty()) {
            s.putAtt("title", title);
        }
    }

    private static Element getRefElement(Element element) {
        if (element.tagName().equals("a")) {
            return element;
        }
        Element loneChild = TagUtils.getLoneChild(element);
        if (loneChild != null) {
            return getRefElement(loneChild);
        }
        return null;
    }

    private static short checkEmStrg(short type, Element element) {
        switch (element.tagName()) {
            case "b":
            case "strong":
                if (type == S.EMPHASIS) {
                    type = S.EMSTRG;
                } else {
                    type = S.STRONG;
                }
                break;
            case "i":
            case "u":
            case "em":
                if (type == S.STRONG) {
                    type = S.EMSTRG;
                } else {
                    type = S.EMPHASIS;
                }
                break;
        }
        if (type == S.EMSTRG) {
            return type;
        }
        Element loneChild = TagUtils.getLoneChild(element);
        if (loneChild != null) {
            type = checkEmStrg(type, loneChild);
        }
        return type;
    }

    private static void addLinkAttributes(Element linkElement, S span) {
        addAttribute(linkElement, span, "hreflang");
        addAttribute(linkElement, span, "rel");
        addAttribute(linkElement, span, "target");
        addAttribute(linkElement, span, "name");
    }

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

}
