/* BdfServer - Copyright (c) 2023-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.dataresolvers;

import fr.exemole.bdfserver.api.BdfServer;
import fr.exemole.bdfserver.api.BdfServerConstants;
import fr.exemole.bdfserver.api.externalsource.FichothequeSharing;
import fr.exemole.bdfserver.tools.externalsource.CoreExternalSourceCatalog;
import java.io.IOException;
import java.text.ParseException;
import java.util.Collection;
import net.fichotheque.Fichotheque;
import net.fichotheque.FichothequeConstants;
import net.fichotheque.SubsetKey;
import net.fichotheque.corpus.Corpus;
import net.fichotheque.corpus.FicheMeta;
import net.fichotheque.junction.Liaison;
import net.fichotheque.externalsource.ExternalSourceDef;
import net.fichotheque.extraction.DataResolver;
import net.fichotheque.include.IncludeKey;
import net.fichotheque.pointeurs.SubsetItemPointeur;
import net.fichotheque.thesaurus.Motcle;
import net.fichotheque.thesaurus.Thesaurus;
import net.fichotheque.tools.extraction.ExtractionContextUtils;
import net.fichotheque.utils.JunctionUtils;
import net.fichotheque.xml.extraction.ExtractionXMLUtils;
import net.fichotheque.xml.extraction.TagNames;
import net.mapeadores.util.localisation.LangContext;
import net.mapeadores.util.xml.XMLWriter;


/**
 *
 * @author Vincent Calame
 */
public class FichesDataResolver implements DataResolver {

    public final static String FICHOTHEQUE_PARAM = "fichotheque";
    public final static String MATCHINGTHESAURUS_PARAM = "matchingthesaurus";
    public final static String CORPUS_PARAM = "corpus";
    private final BdfServer bdfServer;
    private final FichothequeSharing fichothequeSharing;
    private final String fichothequeName;
    private final SubsetKey thesaurusKey;
    private final IncludeKey corpusIncludeKey;

    private FichesDataResolver(BdfServer bdfServer, FichothequeSharing fichothequeSharing, String fichothequeName, SubsetKey thesaurusKey, IncludeKey corpusIncludeKey) {
        this.bdfServer = bdfServer;
        this.fichothequeSharing = fichothequeSharing;
        this.fichothequeName = fichothequeName;
        this.thesaurusKey = thesaurusKey;
        this.corpusIncludeKey = corpusIncludeKey;
    }

    @Override
    public String getType() {
        return CoreExternalSourceCatalog.DATAUI_FICHES_TYPENAME;
    }

    @Override
    public Writer getWriter(SubsetItemPointeur pointeur, LangContext langContext) {
        Motcle matchingMotcle = getMatchingMotcle(pointeur.getCurrentSubsetItem().getId());
        if (matchingMotcle != null) {
            Collection<Liaison> liaisons = getLiaisons(matchingMotcle);
            if (!liaisons.isEmpty()) {
                return new ResolverWriter(langContext, liaisons);
            }
        }
        return ExtractionContextUtils.EMPTY_DATARESOLVER_WRITER;
    }

    private Motcle getMatchingMotcle(int id) {
        Fichotheque otherFichotheque = fichothequeSharing.getFichotheque(fichothequeName);
        if (otherFichotheque == null) {
            return null;
        }
        Thesaurus thesaurus = (Thesaurus) otherFichotheque.getSubset(thesaurusKey);
        if (thesaurus == null) {
            return null;
        }
        return thesaurus.getMotcleById(id);
    }

    private Collection<Liaison> getLiaisons(Motcle matchingMotcle) {
        Fichotheque fichotheque = matchingMotcle.getThesaurus().getFichotheque();
        Corpus corpus = (Corpus) fichotheque.getSubset(corpusIncludeKey.getSubsetKey());
        if (corpus == null) {
            return JunctionUtils.EMPTY_LIAISONCOLLECTION;
        }
        return JunctionUtils.filter(fichotheque.getJunctions(matchingMotcle, corpus), corpusIncludeKey);
    }

    public static FichesDataResolver build(BdfServer bdfServer, ExternalSourceDef externalSourceDef) throws ResolverErrorException {
        String fichothequeName = getValue(externalSourceDef, FICHOTHEQUE_PARAM);
        String matchingThesaurus = getValue(externalSourceDef, MATCHINGTHESAURUS_PARAM);
        String corpus = getValue(externalSourceDef, CORPUS_PARAM);
        SubsetKey thesaurusKey;
        try {
            thesaurusKey = SubsetKey.parse(SubsetKey.CATEGORY_THESAURUS, matchingThesaurus);
        } catch (ParseException pe) {
            throw new ResolverErrorException("MatchingThesaurus malformed: " + matchingThesaurus);
        }
        IncludeKey corpusIncludeKey;
        try {
            corpusIncludeKey = IncludeKey.parse("corpus_" + corpus);
        } catch (ParseException pe) {
            throw new ResolverErrorException("Corpus malformed: " + corpus);
        }
        FichothequeSharing fichothequeSharing = (FichothequeSharing) bdfServer.getContextObject(BdfServerConstants.FICHOTHEQUESHARING_CONTEXTOBJECT);
        if (fichothequeSharing == null) {
            throw new ResolverErrorException("FichothequeSharing not allowed");
        }
        Fichotheque otherFichotheque = fichothequeSharing.getFichotheque(fichothequeName);
        if (otherFichotheque == null) {
            throw new ResolverErrorException("Unknown fichotheque: " + fichothequeName);
        }
        if (!otherFichotheque.containsSubset(thesaurusKey)) {
            throw new ResolverErrorException("Unknown thesaurus: " + matchingThesaurus);
        }
        if (!otherFichotheque.containsSubset(corpusIncludeKey.getSubsetKey())) {
            throw new ResolverErrorException("Unknown corpus: " + corpusIncludeKey.getSubsetKey().getSubsetName());
        }
        return new FichesDataResolver(bdfServer, fichothequeSharing, fichothequeName, thesaurusKey, corpusIncludeKey);

    }

    private static String getValue(ExternalSourceDef externalSourceDef, String paramName) throws ResolverErrorException {
        String paramValue = externalSourceDef.getParam(paramName);
        if (paramValue == null) {
            throw new ResolverErrorException("Missing " + paramName + " parameter");
        }
        return paramValue;
    }


    private class ResolverWriter implements DataResolver.Writer {

        private final LangContext langContext;
        private final Collection<Liaison> liaisons;

        private ResolverWriter(LangContext langContext, Collection<Liaison> liaisons) {
            this.langContext = langContext;
            this.liaisons = liaisons;
        }

        @Override
        public boolean isEmpty() {
            return false;
        }

        @Override
        public void write(XMLWriter xmlWriter, int extractVersion) throws IOException {
            TagNames tagNames = new TagNames(extractVersion);
            for (Liaison liaison : liaisons) {
                FicheMeta ficheMeta = (FicheMeta) liaison.getSubsetItem();
                xmlWriter.startOpenTag("fiche")
                        .addAttribute("id", ficheMeta.getId())
                        .addAttribute("corpus", ficheMeta.getSubsetName())
                        .addAttribute("fichotheque", fichothequeName)
                        .endOpenTag();
                xmlWriter.addSimpleElement(tagNames.getTitleTagName(), ficheMeta.getTitle());
                ExtractionXMLUtils.writePhrase(xmlWriter, ficheMeta, FichothequeConstants.FICHE_PHRASE, langContext, extractVersion);
                xmlWriter.closeTag("fiche");
            }
        }

    }


}
