/* BdfServer - Copyright (c) 2008-2023 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.storage.directory.oldversions;

import fr.exemole.bdfserver.api.BdfServerEditor;
import fr.exemole.bdfserver.api.groups.GroupDef;
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.SubsetNodeBuilder;
import fr.exemole.bdfserver.tools.subsettree.SubsetTreeBuilder;
import java.text.ParseException;
import net.fichotheque.SubsetKey;
import net.mapeadores.util.logging.MessageHandler;
import net.mapeadores.util.text.Label;
import net.mapeadores.util.text.LabelUtils;
import net.mapeadores.util.xml.DomMessages;
import net.mapeadores.util.xml.XMLUtils;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;


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

    private final MessageHandler messageHandler;
    private BdfServerEditor bdfServerEditor;

    public TreesDOMReader(MessageHandler messageHandler) {
        this.messageHandler = messageHandler;
    }

    public void readTrees(BdfServerEditor bdfServerEditor, Element element_xml) {
        this.bdfServerEditor = bdfServerEditor;
        NodeList liste = element_xml.getChildNodes();
        int length = liste.getLength();
        for (int i = 0; i < length; i++) {
            if (liste.item(i).getNodeType() == Node.ELEMENT_NODE) {
                Element element = (Element) liste.item(i);
                String tagName = element.getTagName();
                if (tagName.equals("metadata")) {
                    readMetadata(element);
                }
            }
        }
        for (int i = 0; i < length; i++) {
            if (liste.item(i).getNodeType() == Node.ELEMENT_NODE) {
                Element element = (Element) liste.item(i);
                String tagName = element.getTagName();
                if (tagName.equals("metadata")) {
                    continue;
                } else if (tagName.equals("tree")) {
                    String typeString = element.getAttribute("type");
                    if (typeString.length() == 0) {
                        DomMessages.emptyAttribute(messageHandler, "tree", "type");
                        continue;
                    }
                    try {
                        short subsetCategory = toSubsetCategory(typeString);
                        SubsetTreeBuilder subsetTreeBuilder = new SubsetTreeBuilder(false);
                        readTree(subsetTreeBuilder, element);
                        bdfServerEditor.setSubsetTree(subsetCategory, subsetTreeBuilder.toSubsetTree());
                    } catch (IllegalArgumentException iae) {
                        DomMessages.wrongAttributeValue(messageHandler, "tree", "type", typeString);
                        continue;
                    }
                } else {
                    DomMessages.unknownTagWarning(messageHandler, tagName);
                }
            }
        }
    }

    private void readMetadata(Element element_xml) {
        NodeList liste = element_xml.getChildNodes();
        for (int i = 0; i < liste.getLength(); i++) {
            if (liste.item(i).getNodeType() == Node.ELEMENT_NODE) {
                Element element = (Element) liste.item(i);
                String tagName = element.getTagName();
                if (tagName.equals("group-def")) {
                    readGroupDef(element);
                } else {
                    DomMessages.unknownTagWarning(messageHandler, tagName);
                }
            }
        }
    }

    private void readGroupDef(Element element_xml) {
        String name = element_xml.getAttribute("name");
        if (name.length() == 0) {
            DomMessages.emptyAttribute(messageHandler, "group-def", "name");
            return;
        }
        name = checkName(name);
        GroupDef groupDef = bdfServerEditor.createGroupDef(name);
        NodeList liste = element_xml.getChildNodes();
        for (int i = 0; i < liste.getLength(); i++) {
            if (liste.item(i).getNodeType() == Node.ELEMENT_NODE) {
                Element element = (Element) liste.item(i);
                String tagName = element.getTagName();
                if (tagName.equals("lib")) {
                    try {
                        Label label = LabelUtils.readLabel(element);
                        if (label != null) {
                            bdfServerEditor.putLabel(groupDef, label);
                        }
                    } catch (ParseException ile) {
                        DomMessages.wrongLangAttribute(messageHandler, "lib", element.getAttribute("xml:lang"));
                    }
                } else {
                    DomMessages.unknownTagWarning(messageHandler, tagName);
                }
            }
        }
    }

    private void readTree(SubsetTreeBuilder subsetTreeBuilder, Element element_xml) {
        NodeList liste = element_xml.getChildNodes();
        for (int i = 0; i < liste.getLength(); i++) {
            if (liste.item(i).getNodeType() == Node.ELEMENT_NODE) {
                Element element = (Element) liste.item(i);
                String tagName = element.getTagName();
                if (tagName.equals("group")) {
                    GroupNode groupNode = readGroup(element);
                    if (groupNode != null) {
                        subsetTreeBuilder.addGroupNode(groupNode);
                    }
                } else if (tagName.equals("subset")) {
                    SubsetNode subsetNode = readSubset(element);
                    if (subsetNode != null) {
                        subsetTreeBuilder.addSubsetNode(subsetNode);
                    }
                } else {
                    DomMessages.unknownTagWarning(messageHandler, tagName);
                }
            }
        }
    }

    private GroupNode readGroup(Element element_xml) {
        String groupName = element_xml.getAttribute("name");
        if (groupName.length() == 0) {
            return null;
        }
        groupName = checkName(groupName);
        GroupNodeBuilder groupNodeBuilder = new GroupNodeBuilder(groupName, false);
        NodeList liste = element_xml.getChildNodes();
        for (int i = 0; i < liste.getLength(); i++) {
            if (liste.item(i).getNodeType() == Node.ELEMENT_NODE) {
                Element element = (Element) liste.item(i);
                String tagName = element.getTagName();
                if (tagName.equals("subset")) {
                    SubsetNode subsetNode = readSubset(element);
                    if (subsetNode != null) {
                        groupNodeBuilder.addSubsetNode(subsetNode);
                    }
                } else {
                    DomMessages.unknownTagWarning(messageHandler, tagName);
                }
            }
        }
        return groupNodeBuilder.toGroupNode();
    }

    private SubsetNode readSubset(Element element_xml) {
        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;
        }
    }

    private String checkName(String name) {
        try {
            int i = Integer.parseInt(name);
            return "grp" + i;
        } catch (NumberFormatException nfe) {
            return name;
        }
    }

    private static short toSubsetCategory(String typeString) {
        if (typeString.equals("grpcorpus")) {
            return SubsetKey.CATEGORY_CORPUS;
        } else if (typeString.equals("grpthesaurus")) {
            return SubsetKey.CATEGORY_THESAURUS;
        } else if (typeString.equals("grpsphere")) {
            return SubsetKey.CATEGORY_SPHERE;
        } else if (typeString.equals("grpalbum")) {
            return SubsetKey.CATEGORY_ALBUM;
        } else {
            throw new IllegalArgumentException("wrong typeString value : " + typeString);
        }
    }

}
