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

import fr.exemole.bdfserver.api.BdfServer;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import net.fichotheque.ExistingIdException;
import net.fichotheque.FichothequeEditor;
import net.fichotheque.corpus.Corpus;
import net.fichotheque.corpus.FicheMeta;
import net.fichotheque.externalsource.ExternalItem;
import net.fichotheque.externalsource.ExternalSource;
import net.fichotheque.selection.FicheQuery;
import net.fichotheque.selection.SelectionContext;
import net.fichotheque.thesaurus.Motcle;
import net.fichotheque.thesaurus.Thesaurus;
import net.fichotheque.thesaurus.ThesaurusEditor;
import net.fichotheque.thesaurus.metadata.ThesaurusMetadata;
import net.fichotheque.tools.selection.FicheQueryBuilder;
import net.fichotheque.tools.selection.SelectionEngines;
import net.fichotheque.utils.Comparators;
import net.fichotheque.utils.EligibilityUtils;
import net.fichotheque.utils.selection.FicheSelectorBuilder;
import net.fichotheque.utils.selection.SelectionContextBuilder;
import net.mapeadores.util.conditions.TextConditionBuilder;
import net.mapeadores.util.conditions.ConditionsConstants;
import net.mapeadores.util.conditions.ConditionsUtils;
import net.mapeadores.util.conditions.TextTest;
import net.mapeadores.util.localisation.Lang;
import net.mapeadores.util.conditions.TextCondition;
import net.fichotheque.selection.FieldContentCondition;


/**
 *
 * @author Vincent Calame
 */
public class CorpusExternalSource implements ExternalSource {

    private final BdfServer bdfServer;
    private final String fichothequeName;
    private final Corpus externalCorpus;

    public CorpusExternalSource(BdfServer bdfServer, String fichothequeName, Corpus externalCorpus) {
        this.bdfServer = bdfServer;
        this.fichothequeName = fichothequeName;
        this.externalCorpus = externalCorpus;
    }

    @Override
    public int getIdType() {
        return ExternalSource.ID_TYPE;
    }

    @Override
    public Motcle getMotcle(FichothequeEditor fichothequeEditor, Thesaurus localThesaurus, int id) {
        if (localThesaurus.getThesaurusMetadata().getThesaurusType() != ThesaurusMetadata.BABELIEN_TYPE) {
            return null;
        }
        FicheMeta ficheMeta = externalCorpus.getFicheMetaById(id);
        if (ficheMeta != null) {
            return checkMotcle(fichothequeEditor, localThesaurus, ficheMeta);
        } else {
            return null;
        }
    }

    @Override
    public Motcle getMotcle(FichothequeEditor fichothequeEditor, Thesaurus localThesaurus, String label, Lang lang) {
        if (localThesaurus.getThesaurusMetadata().getThesaurusType() != ThesaurusMetadata.BABELIEN_TYPE) {
            return null;
        }
        TextTest textTest = ConditionsUtils.toTextTest(ConditionsConstants.MATCHES_TEST, label);
        TextCondition condition = TextConditionBuilder.init(ConditionsConstants.LOGICALOPERATOR_AND).addTextTest(textTest).toTextCondition();
        Collection<FicheMeta> fiches = searchFiches(condition, lang);
        if (!fiches.isEmpty()) {
            FicheMeta ficheMeta = fiches.iterator().next();
            return checkMotcle(fichothequeEditor, localThesaurus, ficheMeta);
        } else {
            return null;
        }
    }

    @Override
    public Collection<ExternalItem> search(String query, Lang lang) {
        TextCondition condition = ConditionsUtils.parseSimpleCondition(query);
        if (condition == null) {
            return ExternalSourceUtils.EXTERNALITEM_EMPTYLIST;
        }
        Collection<FicheMeta> fiches = searchFiches(condition, lang);
        if (fiches.isEmpty()) {
            return ExternalSourceUtils.EXTERNALITEM_EMPTYLIST;
        }
        List<ExternalItem> resultList = new ArrayList<ExternalItem>(fiches.size());
        for (FicheMeta fiche : fiches) {
            resultList.add(ExternalSourceUtils.toExternalItem(fiche.getId(), fiche.getTitle(), ""));
        }
        return resultList;
    }

    private Collection<FicheMeta> searchFiches(TextCondition condition, Lang lang) {
        FicheQuery ficheQuery = FicheQueryBuilder.init().addCorpus(externalCorpus).setFieldContentCondition(condition, FieldContentCondition.TITLE_SCOPE, null).toFicheQuery();
        SelectionContext selectionContext = SelectionContextBuilder.init(externalCorpus.getFichotheque(), bdfServer.getL10nManager(), lang)
                .setSubsetAccessPredicate(EligibilityUtils.ALL_SUBSET_PREDICATE)
                .toSelectionContext();
        return SelectionEngines.run(selectionContext, FicheSelectorBuilder.init(selectionContext).add(ficheQuery).toFicheSelector(), Comparators.FICHEID_ASC);
    }

    private Motcle checkMotcle(FichothequeEditor fichothequeEditor, Thesaurus localThesaurus, FicheMeta ficheMeta) {
        ThesaurusEditor thesaurusEditor = fichothequeEditor.getThesaurusEditor(localThesaurus);
        int id = ficheMeta.getId();
        Motcle motcle = localThesaurus.getMotcleById(id);
        if (motcle == null) {
            try {
                motcle = thesaurusEditor.createMotcle(id, null);
            } catch (ExistingIdException | ParseException e) {
                //throw new ShouldNotOccurException(e);
                return null;
            }
        }
        Lang ficheLang = ficheMeta.getLang();
        if (ficheLang == null) {
            ficheLang = Lang.build("und");
        }
        thesaurusEditor.putLabel(motcle, ficheLang, ficheMeta.getTitle());
        return motcle;
    }


}
