/* FichothequeLib_Tools - Copyright (c) 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 net.fichotheque.tools.extraction.dom;

import java.text.ParseException;
import java.util.Set;
import java.util.function.Consumer;
import net.fichotheque.Fichotheque;
import net.fichotheque.SubsetKey;
import net.fichotheque.extraction.def.ExtractionDef;
import net.fichotheque.extraction.def.GroupClause;
import net.fichotheque.extraction.def.GroupParams;
import net.fichotheque.extraction.def.PackClause;
import net.fichotheque.extraction.def.TagNameInfo;
import net.fichotheque.extraction.def.TitleClause;
import net.fichotheque.selection.DocumentQuery;
import net.fichotheque.selection.FicheQuery;
import net.fichotheque.selection.IllustrationQuery;
import net.fichotheque.selection.MotcleQuery;
import net.fichotheque.tools.extraction.GroupParamsParser;
import net.fichotheque.tools.extraction.builders.GroupClauseBuilder;
import net.fichotheque.tools.extraction.builders.PackClauseBuilder;
import net.fichotheque.tools.extraction.builders.TitleClauseBuilder;
import net.fichotheque.tools.selection.DocumentQueryBuilder;
import net.fichotheque.tools.selection.FicheQueryBuilder;
import net.fichotheque.tools.selection.IllustrationQueryBuilder;
import net.fichotheque.tools.selection.MotcleQueryBuilder;
import net.fichotheque.utils.ExtractionUtils;
import net.fichotheque.utils.FichothequeUtils;
import net.mapeadores.util.logging.MessageHandler;
import net.mapeadores.util.xml.DOMUtils;
import net.mapeadores.util.xml.DocumentFragmentHolder;
import net.mapeadores.util.xml.DomMessages;
import net.mapeadores.util.xml.XMLUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;


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

    private ExtractionDOMUtils() {

    }

    public static FicheQuery getFicheQuery(String s) {
        Set<SubsetKey> corpusKeySet = FichothequeUtils.toSubsetKeySet(SubsetKey.CATEGORY_CORPUS, s);
        if (!corpusKeySet.isEmpty()) {
            FicheQueryBuilder ficheQueryBuilder = new FicheQueryBuilder();
            ficheQueryBuilder.addCorpus(corpusKeySet);
            return ficheQueryBuilder.toFicheQuery();
        } else {
            return null;
        }
    }

    public static MotcleQuery getMotcleQuery(String s) {
        Set<SubsetKey> subsetKeySet = FichothequeUtils.toSubsetKeySet(SubsetKey.CATEGORY_THESAURUS, s);
        if (!subsetKeySet.isEmpty()) {
            return MotcleQueryBuilder.init()
                    .addThesaurus(subsetKeySet)
                    .toMotcleQuery();
        } else {
            return null;
        }
    }

    public static IllustrationQuery getIllustrationQuery(String s) {
        Set<SubsetKey> subsetKeySet = FichothequeUtils.toSubsetKeySet(SubsetKey.CATEGORY_ALBUM, s);
        if (!subsetKeySet.isEmpty()) {
            return IllustrationQueryBuilder.init()
                    .addAlbum(subsetKeySet)
                    .toIllustrationQuery();
        } else {
            return null;
        }
    }

    public static DocumentQuery getDocumentQuery(String s) {
        Set<SubsetKey> subsetKeySet = FichothequeUtils.toSubsetKeySet(SubsetKey.CATEGORY_ADDENDA, s);
        if (!subsetKeySet.isEmpty()) {
            return DocumentQueryBuilder.init()
                    .addAddenda(subsetKeySet)
                    .toDocumentQuery();
        } else {
            return null;
        }
    }

    public static String getExtractName(Element element) {
        String name = element.getAttribute("name");
        if (name.isEmpty()) {
            name = element.getAttribute("extrait-name");
        }
        return name;
    }

    public static TagNameInfo getTagNameInfo(Element element) {
        String tagName = element.getAttribute("tag-name");
        switch (tagName) {
            case "":
                return TagNameInfo.DEFAULT;
            case "NULL":
            case "_null":
                return TagNameInfo.NULL;
            default: {
                try {
                    TagNameInfo tagNameInfo = TagNameInfo.parse(tagName);
                    return tagNameInfo;
                } catch (ParseException pe) {
                    return TagNameInfo.DEFAULT;
                }
            }
        }
    }

    public static ExtractionDef readExtractionDef(Fichotheque fichotheque, String s, DocumentFragmentHolder documentFragmentHolder, MessageHandler messageHandler) {
        if (documentFragmentHolder == null) {
            documentFragmentHolder = XMLUtils.EMPTY_DOCUMENTFRAGMENTHOLDER;
        }
        try {
            Document document = DOMUtils.parseDocument(s);
            ExtractionDOMReader extractionDOMReader = new ExtractionDOMReader(fichotheque);
            return extractionDOMReader.readExtraction(document.getDocumentElement(), documentFragmentHolder);
        } catch (SAXException saxException) {
            DomMessages.saxException(messageHandler, saxException);
            return null;
        }
    }

    public static PackClause readPackClause(Element element) {
        int packSize;
        try {
            packSize = Integer.parseInt(element.getAttribute("size"));
        } catch (NumberFormatException nfe) {
            return null;
        }
        int modulo = 0;
        try {
            modulo = Integer.parseInt(element.getAttribute("modulo"));
        } catch (NumberFormatException nfe) {
        }
        TagNameInfo tagNameInfo = getTagNameInfo(element);
        return PackClauseBuilder.init(packSize)
                .setTagNameInfo(tagNameInfo)
                .setModulo(modulo)
                .toPackClause();
    }

    public static TitleClause readTitleClause(Element element) {
        return TitleClauseBuilder.DEFAULT;
    }

    public static GroupClause readGroupClause(Element element) {
        String groupType;
        try {
            groupType = ExtractionUtils.checkType(element.getAttribute("type"));
        } catch (IllegalArgumentException iae) {
            return null;
        }
        String sortOrder = ExtractionUtils.checkSort(element.getAttribute("sort"));
        String params = element.getAttribute("params");
        if (params.length() == 0) {
            params = element.getAttribute("mode");
        }
        GroupParams groupParams = GroupParamsParser.parse(groupType, params);
        TagNameInfo tagNameInfo = getTagNameInfo(element);
        GroupClause subGroupClause = readSubGroupClause(element);
        try {
            return GroupClauseBuilder.init(groupType)
                    .setTagNameInfo(tagNameInfo)
                    .setSortOrder(sortOrder)
                    .setGroupParams(groupParams)
                    .setSubGroupClause(subGroupClause)
                    .toGroupClause();
        } catch (IllegalStateException iae) {
            return null;
        }
    }

    private static GroupClause readSubGroupClause(Element element) {
        SubGroupClauseConsumer consumer = new SubGroupClauseConsumer();
        DOMUtils.readChildren(element, consumer);
        return consumer.getSubGroupClause();
    }


    private static class SubGroupClauseConsumer implements Consumer<Element> {

        private GroupClause subGroupClause = null;

        private SubGroupClauseConsumer() {

        }

        @Override
        public void accept(Element element) {
            String tagname = element.getTagName();
            if (tagname.equals("group")) {
                subGroupClause = readGroupClause(element);
            }
        }

        private GroupClause getSubGroupClause() {
            return subGroupClause;
        }

    }


}
