/* BdfServer - Copyright (c) 2014-2022 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 fr.exemole.bdfserver.tools.subsettree.dom;

import fr.exemole.bdfserver.api.subsettree.GroupNode;
import fr.exemole.bdfserver.api.subsettree.SubsetNode;
import fr.exemole.bdfserver.tools.subsettree.GroupNodeBuilder;
import fr.exemole.bdfserver.tools.subsettree.NodeListBuilder;
import fr.exemole.bdfserver.tools.subsettree.SubsetNodeBuilder;
import fr.exemole.bdfserver.tools.subsettree.SubsetTreeBuilder;
import java.text.ParseException;
import java.util.function.Consumer;
import net.fichotheque.SubsetKey;
import net.mapeadores.util.logging.MessageHandler;
import net.mapeadores.util.text.StringUtils;
import net.mapeadores.util.xml.DOMUtils;
import net.mapeadores.util.xml.DomMessages;
import net.mapeadores.util.xml.XMLUtils;
import org.w3c.dom.Element;


/**
 *
 * @author Vincent Calame
 */
public class TreeDOMReader {

    private final SubsetTreeBuilder subsetTreeBuilder;
    private final MessageHandler messageHandler;

    public TreeDOMReader(SubsetTreeBuilder subsetTreeBuilder, MessageHandler messageHandler) {
        this.messageHandler = messageHandler;
        this.subsetTreeBuilder = subsetTreeBuilder;
    }

    public void readTree(Element element) {
        DOMUtils.readChildren(element, new NodeListConsumer(subsetTreeBuilder, messageHandler, subsetTreeBuilder.ignoreEmptyGroupNode()));
    }


    private static class NodeListConsumer implements Consumer<Element> {

        private final MessageHandler messageHandler;
        private final NodeListBuilder nodeListBuilder;
        private final boolean ignoreEmptyGroupNode;

        private NodeListConsumer(NodeListBuilder nodeListBuilder, MessageHandler messageHandler, boolean ignoreEmptyGroupNode) {
            this.messageHandler = messageHandler;
            this.nodeListBuilder = nodeListBuilder;
            this.ignoreEmptyGroupNode = ignoreEmptyGroupNode;
        }

        @Override
        public void accept(Element element) {
            String tagName = element.getTagName();
            if (tagName.equals("group")) {
                GroupNode groupNode = readGroupNode(element, messageHandler, ignoreEmptyGroupNode);
                if (groupNode != null) {
                    nodeListBuilder.addGroupNode(groupNode);
                }
            } else if (tagName.equals("subset")) {
                SubsetNode subsetNode = readSubsetNode(element, messageHandler);
                if (subsetNode != null) {
                    nodeListBuilder.addSubsetNode(subsetNode);
                }
            }
        }

    }

    private static GroupNode readGroupNode(Element element_xml, MessageHandler messageHandler, boolean ignoreEmptyGroupNode) {
        String name = element_xml.getAttribute("name");
        if (name.length() == 0) {
            DomMessages.emptyAttribute(messageHandler, "group", "name");
            return null;
        } else if (!StringUtils.isTechnicalName(name, true)) {
            DomMessages.wrongAttributeValue(messageHandler, "group", "name", name);
            return null;
        } else {
            GroupNodeBuilder childBuilder = new GroupNodeBuilder(name, ignoreEmptyGroupNode);
            NodeListConsumer childHandler = new NodeListConsumer(childBuilder, messageHandler, ignoreEmptyGroupNode);
            DOMUtils.readChildren(element_xml, childHandler);
            return childBuilder.toGroupNode();
        }
    }

    private static SubsetNode readSubsetNode(Element element_xml, MessageHandler messageHandler) {
        String xpath = "subset";
        String subsetKeyString = XMLUtils.getData(element_xml);
        if (subsetKeyString.length() == 0) {
            DomMessages.emptyElement(messageHandler, xpath);
            return null;
        }
        try {
            SubsetKey subsetKey = SubsetKey.parse(subsetKeyString);
            return SubsetNodeBuilder.build(subsetKey);
        } catch (ParseException pe) {
            DomMessages.wrongElementValue(messageHandler, xpath, subsetKeyString);
            return null;
        }
    }

}
