/* 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.policies.dom;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import net.fichotheque.Fichotheque;
import net.fichotheque.SubsetKey;
import net.fichotheque.thesaurus.Thesaurus;
import net.fichotheque.thesaurus.policies.DynamicEditPolicy;
import net.fichotheque.tools.externalsource.ExternalSourceDefBuilder;
import net.fichotheque.tools.thesaurus.DynamicEditPolicyBuilder;
import net.fichotheque.utils.ThesaurusUtils;
import net.mapeadores.util.logging.MessageHandler;
import net.mapeadores.util.xml.DOMUtils;
import net.mapeadores.util.xml.DomMessages;
import org.w3c.dom.Element;


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

    private final MessageHandler messageHandler;
    private final Fichotheque fichotheque;

    public ThesaurusPolicyDOMReader(MessageHandler messageHandler, Fichotheque fichotheque) {
        this.messageHandler = messageHandler;
        this.fichotheque = fichotheque;
    }

    public DynamicEditPolicy readDynamicEditPolicy(Element element, SubsetKey subsetKey) {
        Thesaurus thesaurus = (Thesaurus) fichotheque.getSubset(subsetKey);
        if (thesaurus == null) {
            return null;
        }
        String type = element.getAttribute("type");
        if (type.isEmpty()) {
            type = element.getAttribute("ajout");
        }
        if (type.isEmpty()) {
            type = "none";
        }
        DynamicEditPolicy policy;
        switch (type) {
            case "none": {
                policy = ThesaurusUtils.NONE_POLICY;
                break;
            }
            case "allow": {
                policy = ThesaurusUtils.ALLOW_POLICY;
                break;
            }
            case "transfer": {
                List<SubsetKey> subsetKeyList = getSubsetKeyList(element);
                if (subsetKeyList.isEmpty()) {
                    policy = ThesaurusUtils.NONE_POLICY;
                } else {
                    policy = DynamicEditPolicyBuilder.buildTransfer(subsetKeyList.get(0));
                }
                break;
            }
            case "check":
            case "verif": {
                List<SubsetKey> subsetKeyList = getSubsetKeyList(element);
                if (subsetKeyList.isEmpty()) {
                    policy = ThesaurusUtils.ALLOW_POLICY;
                } else {
                    policy = DynamicEditPolicyBuilder.buildCheck(subsetKeyList);
                }
                break;
            }
            case "external": {
                String sourceType = element.getAttribute("source-type");
                if (sourceType.isEmpty()) {
                    DomMessages.emptyAttribute(messageHandler, element.getTagName(), "source-type");
                    return null;
                }
                ExternalSourceDefBuilder externalSourceDefBuilder = new ExternalSourceDefBuilder(sourceType);
                DOMUtils.readChildren(element, new ExternalConsumer(externalSourceDefBuilder));
                policy = DynamicEditPolicyBuilder.buildExternal(externalSourceDefBuilder.toExternalSourceDef());
                break;
            }
            default: {
                DomMessages.wrongAttributeValue(messageHandler, element.getTagName(), "type", type);
                return null;
            }
        }
        return policy;
    }

    private List<SubsetKey> getSubsetKeyList(Element element) {
        ThesaurusConsumer thesaurusConsumer = new ThesaurusConsumer(fichotheque);
        DOMUtils.readChildren(element, thesaurusConsumer);
        return thesaurusConsumer.getThesaurusList();
    }


    private class ThesaurusConsumer implements Consumer<Element> {

        private final List<SubsetKey> thesaurusList = new ArrayList<SubsetKey>();
        private final Fichotheque fichotheque;

        private ThesaurusConsumer(Fichotheque fichotheque) {
            this.fichotheque = fichotheque;
        }

        @Override
        public void accept(Element element) {
            String tagName = element.getTagName();
            if (tagName.equals("thesaurus")) {
                String name = DOMUtils.readSimpleElement(element);
                if (name.length() > 0) {
                    try {
                        SubsetKey subsetKey = SubsetKey.parse(SubsetKey.CATEGORY_THESAURUS, name);
                        if (fichotheque.containsSubset(subsetKey)) {
                            thesaurusList.add(subsetKey);
                        }
                    } catch (ParseException pe) {
                    }

                }
            } else {
                DomMessages.unknownTagWarning(messageHandler, tagName);
            }
        }

        public List<SubsetKey> getThesaurusList() {
            return thesaurusList;
        }

    }


    private class ExternalConsumer implements Consumer<Element> {

        private final ExternalSourceDefBuilder externalSourceDefBuilder;

        private ExternalConsumer(ExternalSourceDefBuilder externalSourceDefBuilder) {
            this.externalSourceDefBuilder = externalSourceDefBuilder;
        }

        @Override
        public void accept(Element element) {
            String tagName = element.getTagName();
            if (tagName.equals("param")) {
                String name = element.getAttribute("name");
                if (!name.isEmpty()) {
                    String value = DOMUtils.readSimpleElement(element);
                    externalSourceDefBuilder.addParam(name, value);
                }
            } else {
                DomMessages.unknownTagWarning(messageHandler, tagName);
            }
        }


    }

}
