/* FichothequeLib_Tools - Copyright (c) 2023-2024 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;

import java.util.ArrayList;
import java.util.List;
import net.fichotheque.corpus.Corpus;
import net.fichotheque.corpus.FicheMeta;
import net.fichotheque.corpus.Fiches;
import net.fichotheque.extraction.ExtractionContext;
import net.fichotheque.extraction.ExtractionSource;
import net.fichotheque.extraction.def.CorpusExtractDef;
import net.fichotheque.extraction.def.ExtractionDef;
import net.fichotheque.extraction.def.ThesaurusExtractDef;
import net.fichotheque.extraction.run.CorpusExtractResult;
import net.fichotheque.extraction.run.CorpusExtractor;
import net.fichotheque.extraction.run.ThesaurusExtractResult;
import net.fichotheque.extraction.run.ThesaurusExtractor;
import net.fichotheque.selection.FicheSelector;
import net.fichotheque.selection.MotcleSelector;
import net.fichotheque.selection.SelectionContext;
import net.fichotheque.thesaurus.Motcle;
import net.fichotheque.thesaurus.Thesaurus;
import net.fichotheque.utils.CorpusUtils;
import net.fichotheque.utils.ExtractionUtils;
import net.fichotheque.utils.selection.FicheSelectorBuilder;
import net.fichotheque.utils.selection.MotcleSelectorBuilder;
import net.fichotheque.utils.selection.SelectionContextBuilder;
import net.mapeadores.util.annotation.Nullable;


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

    private ExtractionEngineUtils() {

    }

    public static ExtractionSource getExtractionSource(Object dynamicObject) {
        return new SimpleExtractionSource(dynamicObject);
    }

    public static ExtractionSource getExtractionSource(Object dynamicObject, ExtractionContext extractionContext, ExtractionDef extractionDef, @Nullable Fiches staticFiches) {
        List<CorpusExtractDef> corpusExtractDefList = extractionDef.getStaticCorpusExtractDefList();
        List<ThesaurusExtractDef> thesaurusExtractDefList = extractionDef.getStaticThesaurusExtractDefList();
        if ((corpusExtractDefList.isEmpty()) && (thesaurusExtractDefList.isEmpty())) {
            return new SimpleExtractionSource(dynamicObject);
        }
        List<CorpusExtractResult> corpusExtractResultList = runCorpusExtractDef(corpusExtractDefList, extractionContext, staticFiches);
        List<ThesaurusExtractResult> thesaurusExtractResultList = runThesaurusExtractDef(thesaurusExtractDefList, extractionContext);
        return new CompleteExtractionSource(dynamicObject, corpusExtractResultList, thesaurusExtractResultList);
    }

    public static List<CorpusExtractResult> runCorpusExtractDef(List<CorpusExtractDef> corpusExtractDefList, ExtractionContext extractionContext, @Nullable Fiches selectedFiches) {
        if (corpusExtractDefList.isEmpty()) {
            return ExtractionUtils.EMPTY_CORPUSEXTRACTRESULTLIST;
        }
        List<FicheMeta> bufferList = null;
        if (selectedFiches != null) {
            bufferList = CorpusUtils.toList(selectedFiches);
        }
        List<CorpusExtractResult> list = new ArrayList<CorpusExtractResult>();
        for (CorpusExtractDef corpusExtractDef : corpusExtractDefList) {
            SelectionContext selectionContext = SelectionContextBuilder.build(extractionContext)
                    .setSubsetAccessPredicate(extractionContext.getSubsetAccessPredicate())
                    .toSelectionContext();
            FicheSelector ficheSelector = FicheSelectorBuilder.init(selectionContext)
                    .addAll(corpusExtractDef.getConditionEntryList())
                    .toFicheSelector();
            List<Corpus> corpusList = ficheSelector.getCorpusList();
            if (corpusList.isEmpty()) {
                continue;
            }
            CorpusExtractor corpusExtractor = extractionContext.getExtractorProvider().getCorpusExtractor(corpusExtractDef);
            if (bufferList != null) {
                for (FicheMeta ficheMeta : bufferList) {
                    if (ficheSelector.test(ficheMeta)) {
                        corpusExtractor.add(ficheMeta, null);
                    }
                }
            } else {
                for (Corpus corpus : corpusList) {
                    for (FicheMeta ficheMeta : corpus.getFicheMetaList()) {
                        if (ficheSelector.test(ficheMeta)) {
                            corpusExtractor.add(ficheMeta, null);
                        }
                    }
                }
            }
            CorpusExtractResult corpusExtractResult = corpusExtractor.getCorpusExtractResult();
            if (!corpusExtractResult.isEmpty()) {
                list.add(corpusExtractResult);
            }
        }
        int size = list.size();
        if (size == 0) {
            return ExtractionUtils.EMPTY_CORPUSEXTRACTRESULTLIST;
        }
        return list;
    }

    public static List<ThesaurusExtractResult> runThesaurusExtractDef(List<ThesaurusExtractDef> thesaurusExtractDefList, ExtractionContext extractionContext) {
        if (thesaurusExtractDefList.isEmpty()) {
            return ExtractionUtils.EMPTY_THESAURUSEXTRACTRESULTLIST;
        }
        List<ThesaurusExtractResult> list = new ArrayList<ThesaurusExtractResult>();
        SelectionContext selectionContext = SelectionContextBuilder.build(extractionContext)
                .setSubsetAccessPredicate(extractionContext.getSubsetAccessPredicate())
                .toSelectionContext();
        for (ThesaurusExtractDef thesaurusExtractDef : thesaurusExtractDefList) {
            MotcleSelector motcleSelector = MotcleSelectorBuilder.init(selectionContext).addAll(thesaurusExtractDef.getConditionEntryList()).toMotcleSelector();
            List<Thesaurus> thesaurusList = motcleSelector.getThesaurusList();
            if (thesaurusList.isEmpty()) {
                continue;
            }
            ThesaurusExtractor thesaurusExtractor = extractionContext.getExtractorProvider().getThesaurusExtractor(thesaurusExtractDef);
            for (Thesaurus thesaurus : thesaurusList) {
                for (Motcle motcle : thesaurus.getMotcleList()) {
                    if (motcleSelector.test(motcle)) {
                        thesaurusExtractor.add(motcle, null);
                    }
                }
            }
            ThesaurusExtractResult thesaurusExtractResult = thesaurusExtractor.getThesaurusExtractResult();
            if (!thesaurusExtractResult.getEntryList().isEmpty()) {
                list.add(thesaurusExtractResult);
            }
        }
        int size = list.size();
        if (size == 0) {
            return ExtractionUtils.EMPTY_THESAURUSEXTRACTRESULTLIST;
        }
        return list;
    }


    private static class SimpleExtractionSource implements ExtractionSource {

        private final Object dynamicObject;

        private SimpleExtractionSource(Object dynamicObject) {
            this.dynamicObject = dynamicObject;
        }

        @Override
        public Object getDynamicObject() {
            return dynamicObject;
        }

        @Override
        public List<CorpusExtractResult> getStaticCorpusExtractResultList() {
            return ExtractionUtils.EMPTY_CORPUSEXTRACTRESULTLIST;
        }

        @Override
        public List<ThesaurusExtractResult> getStaticThesaurusExtractResultList() {
            return ExtractionUtils.EMPTY_THESAURUSEXTRACTRESULTLIST;
        }

    }


    private static class CompleteExtractionSource implements ExtractionSource {

        private final Object dynamicObject;
        private final List<CorpusExtractResult> corpusExtractResultList;
        private final List<ThesaurusExtractResult> thesaurusExtractResultList;

        private CompleteExtractionSource(Object dynamicObject, List<CorpusExtractResult> corpusExtractResultList, List<ThesaurusExtractResult> thesaurusExtractResultList) {
            this.dynamicObject = dynamicObject;
            this.corpusExtractResultList = corpusExtractResultList;
            this.thesaurusExtractResultList = thesaurusExtractResultList;
        }

        @Override
        public Object getDynamicObject() {
            return dynamicObject;
        }

        @Override
        public List<CorpusExtractResult> getStaticCorpusExtractResultList() {
            return corpusExtractResultList;
        }

        @Override
        public List<ThesaurusExtractResult> getStaticThesaurusExtractResultList() {
            return thesaurusExtractResultList;
        }

    }

}
