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

import fr.exemole.bdfserver.api.namespaces.BdfUserSpace;
import fr.exemole.bdfserver.tools.users.BdfUserPrefsBuilder;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import net.fichotheque.Fichotheque;
import net.fichotheque.exportation.transformation.TransformationKey;
import net.fichotheque.selection.FicheQuery;
import net.fichotheque.tools.selection.SelectionDOMUtils;
import net.mapeadores.util.attr.Attribute;
import net.mapeadores.util.attr.AttributeBuilder;
import net.mapeadores.util.attr.AttributeKey;
import net.mapeadores.util.attr.AttributeKeyAlias;
import net.mapeadores.util.attr.AttributeUtils;
import net.mapeadores.util.localisation.Lang;
import net.mapeadores.util.localisation.LangPreferenceBuilder;
import net.mapeadores.util.localisation.LangsUtils;
import net.mapeadores.util.localisation.LocalisationUtils;
import net.mapeadores.util.logging.LogUtils;
import net.mapeadores.util.text.CleanedString;
import net.mapeadores.util.xml.DOMUtils;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;


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

    private final PrefsAttributeKeyAlias ALIAS = new PrefsAttributeKeyAlias();
    private final Fichotheque fichotheque;
    private final BdfUserPrefsBuilder bdfUserPrefsBuilder;

    public BdfUserPrefsDOMReader(Fichotheque fichotheque, BdfUserPrefsBuilder bdfUserPrefsBuilder) {
        this.fichotheque = fichotheque;
        this.bdfUserPrefsBuilder = bdfUserPrefsBuilder;
    }

    public void readBdfUserPrefs(Element element) {
        LangPreferenceBuilder langPreferenceBuilder = new LangPreferenceBuilder();
        DOMUtils.readChildren(element, new RootConsumer(langPreferenceBuilder));
        if (!langPreferenceBuilder.isEmpty()) {
            bdfUserPrefsBuilder.setCustomLangPreference(langPreferenceBuilder.toLangPreference());
        }
    }


    private class RootConsumer implements Consumer<Element> {

        private final LangPreferenceBuilder langPreferenceBuilder;

        private RootConsumer(LangPreferenceBuilder langPreferenceBuilder) {
            this.langPreferenceBuilder = langPreferenceBuilder;
        }

        @Override
        public void accept(Element element) {
            String tagName = element.getTagName();
            switch (tagName) {
                case "selection": {
                    FicheQuery ficheQuery = SelectionDOMUtils.getFicheConditionEntry(fichotheque, element).getFicheQuery();
                    bdfUserPrefsBuilder.setDefaultFicheQuery(ficheQuery);
                    String sort = element.getAttribute("sort");
                    if (!sort.isEmpty()) {

                    }
                    break;
                }
                case "transformation": {
                    readTransformation(bdfUserPrefsBuilder, element);
                    break;
                }
                case "loc-info": {
                    readLocalisationInfo(bdfUserPrefsBuilder, element);
                    break;
                }
                case "roles":
                    readRoles(bdfUserPrefsBuilder, element);
                    break;
                case "attr": {
                    AttributeUtils.readAttrElement(bdfUserPrefsBuilder.getAttributesBuilder(), element, ALIAS);
                    break;
                }
                case "lang": {
                    try {
                        Lang workingLang = Lang.parse(DOMUtils.readSimpleElement(element));
                        bdfUserPrefsBuilder.setWorkingLang(workingLang);
                    } catch (ParseException pe) {

                    }
                    break;
                }
                case "format-locale": {
                    try {
                        Lang formatLocaleLang = Lang.parse(DOMUtils.readSimpleElement(element));
                        bdfUserPrefsBuilder.setCustomFormatLocale(formatLocaleLang.toLocale());
                    } catch (ParseException lie) {

                    }
                    break;
                }
                case "lang-preference": {
                    LangsUtils.readLangElements(langPreferenceBuilder, element, LogUtils.NULL_MESSAGEHANDLER, "");
                    break;
                }
            }
        }

    }

    /**
     * Avant la révision 2177
     */
    private static void readLocalisationInfo(BdfUserPrefsBuilder bdfUserDefBuilder, Element element_xml) {
        String langString = element_xml.getAttribute("working-lang");
        Lang workingLang;
        try {
            workingLang = Lang.parse(langString);
            bdfUserDefBuilder.setWorkingLang(workingLang);
        } catch (ParseException pe) {
            return;
        }
        String localeString = element_xml.getAttribute("format-locale");
        if (localeString.length() > 0) {
            try {
                Lang localeLang = Lang.parse(localeString);
                if (!(localeLang.getRootLang().equals(workingLang))) {
                    bdfUserDefBuilder.setCustomLangPreference(LocalisationUtils.toLangPreference(localeLang));
                    bdfUserDefBuilder.setCustomFormatLocale(localeLang.toLocale());
                }
            } catch (ParseException pe) {
            }
        }
    }

    private static void readTransformation(BdfUserPrefsBuilder bdfUserDefBuilder, 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();
                String templateName = element.getAttribute("name");
                if (templateName.length() == 0) {
                    templateName = null;
                }
                TransformationKey transformationKey;
                try {
                    transformationKey = TransformationKey.parse(element.getAttribute("key"));
                } catch (java.text.ParseException pe) {
                    continue;
                }
                if (tagName.equals("xsl")) {
                    AttributeKey attributeKey = BdfUserSpace.toSimpleTemplateAttributeKey(transformationKey);
                    Attribute attribute = AttributeBuilder.toAttribute(attributeKey, templateName);
                    if (attribute != null) {
                        bdfUserDefBuilder.getAttributesBuilder().appendValues(attribute);
                    }
                } else if (tagName.equals("stream")) {
                    String extension = element.getAttribute("extension");
                    if (extension.length() == 0) {
                        continue;
                    }
                    AttributeKey attributeKey = BdfUserSpace.toStreamTemplateAttributeKey(transformationKey, extension);
                    Attribute attribute = AttributeBuilder.toAttribute(attributeKey, templateName);
                    if (attribute != null) {
                        bdfUserDefBuilder.getAttributesBuilder().appendValues(attribute);
                    }
                }
            }
        }
    }

    /*
     * Gestion des versions antérieures à la révision 1177
     */
    private static void readRoles(BdfUserPrefsBuilder bdfUserDefBuilder, Element element_xml) {
        Set<CleanedString> set = new HashSet<CleanedString>();
        List<CleanedString> list = new ArrayList<CleanedString>();
        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("role")) {
                    String name = element.getAttribute("name");
                    CleanedString cs = CleanedString.newInstance(name);
                    if (cs != null) {
                        if (!set.contains(cs)) {
                            set.add(cs);
                            list.add(cs);
                        }
                    }
                }
            }
        }
        AttributeKey attributeKey = AttributeKey.build(BdfUserSpace.BDFUSER_NAMESPACE, "roles");
        bdfUserDefBuilder.getAttributesBuilder().appendValues(attributeKey, list);
    }


    private static class PrefsAttributeKeyAlias implements AttributeKeyAlias {

        private PrefsAttributeKeyAlias() {

        }

        /**
         * Conversion suite à au nouveau format des clés d'attribut (révision
         * 1616)
         */
        @Override
        public String checkNameSpace(String nameSpace) {
            switch (nameSpace) {
                case "bdfuser_table":
                    return "bdfuser.table";
                case "bdfuser_template_simple":
                    return "bdfuser.template.simple";
                case "bdfuser_template_stream":
                    return "bdfuser.template.stream";
                default:
                    return nameSpace;
            }
        }

        /**
         * Conversion suite à au nouveau format des clés d'attribut (révision
         * 1616)
         */
        @Override
        public String checkLocalKey(String localKey) {
            return localKey.replace('/', '.');
        }

    }

}
