/* FichothequeLib_API - Copyright (c) 2021 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.utils.selection;

import java.util.function.Predicate;
import net.fichotheque.Fichotheque;
import net.fichotheque.Subset;
import net.fichotheque.corpus.Corpus;
import net.fichotheque.corpus.FicheMeta;
import net.fichotheque.extraction.ExtractionContext;
import net.fichotheque.selection.SelectionContext;
import net.fichotheque.utils.EligibilityUtils;
import net.mapeadores.util.localisation.Lang;
import net.mapeadores.util.localisation.MessageLocalisationProvider;


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

    private final Fichotheque fichotheque;
    private final MessageLocalisationProvider messageLocalisationProvider;
    private final Lang lang;
    private Predicate<Subset> subsetAccessPredicate;
    private Predicate<FicheMeta> fichePredicate;
    private Corpus currentCorpus;

    public SelectionContextBuilder(Fichotheque fichotheque, MessageLocalisationProvider messageLocalisationProvider, Lang lang) {
        this.fichotheque = fichotheque;
        this.messageLocalisationProvider = messageLocalisationProvider;
        this.lang = lang;
    }

    public SelectionContextBuilder setSubsetAccessPredicate(Predicate<Subset> subsetAccessPredicate) {
        this.subsetAccessPredicate = subsetAccessPredicate;
        return this;
    }

    public SelectionContextBuilder setFichePredicate(Predicate<FicheMeta> fichePredicate) {
        this.fichePredicate = fichePredicate;
        return this;
    }

    public SelectionContextBuilder setCurrentCorpus(Corpus currentCorpus) {
        this.currentCorpus = currentCorpus;
        return this;
    }

    public SelectionContext toSelectionContext() {
        if (subsetAccessPredicate == null) {
            throw new IllegalStateException("subsetAccessPredicate must be defined");
        }
        Predicate<FicheMeta> finalFichePredicate;
        if (fichePredicate != null) {
            finalFichePredicate = fichePredicate;
        } else {
            finalFichePredicate = EligibilityUtils.ALL_FICHE_PREDICATE;
        }

        return new InternalSelectionContext(fichotheque, messageLocalisationProvider, lang, subsetAccessPredicate, finalFichePredicate, currentCorpus);
    }

    public static SelectionContextBuilder init(Fichotheque fichotheque, MessageLocalisationProvider messageLocalisationProvider, Lang lang) {
        return new SelectionContextBuilder(fichotheque, messageLocalisationProvider, lang);
    }

    public static SelectionContextBuilder build(ExtractionContext extractionContext) {
        return init(extractionContext.getFichotheque(), extractionContext.getMessageLocalisationProvider(), extractionContext.getLangContext().getDefaultLang());
    }

    public static SelectionContextBuilder build(ExtractionContext extractionContext, Lang lang) {
        return init(extractionContext.getFichotheque(), extractionContext.getMessageLocalisationProvider(), lang);
    }


    private static class InternalSelectionContext implements SelectionContext {

        private final Fichotheque fichotheque;
        private final MessageLocalisationProvider messageLocalisationProvider;
        private final Lang workingLang;
        private final Predicate<Subset> subsetAccessPredicate;
        private final Predicate<FicheMeta> fichePredicate;
        private final Corpus currentCorpus;

        private InternalSelectionContext(Fichotheque fichotheque, MessageLocalisationProvider messageLocalisationProvider, Lang workingLang, Predicate<Subset> subsetAccessPredicate, Predicate<FicheMeta> fichePredicate, Corpus currentCorpus) {
            this.fichotheque = fichotheque;
            this.messageLocalisationProvider = messageLocalisationProvider;
            this.workingLang = workingLang;
            this.subsetAccessPredicate = subsetAccessPredicate;
            this.fichePredicate = fichePredicate;
            this.currentCorpus = currentCorpus;
        }

        @Override
        public Fichotheque getFichotheque() {
            return fichotheque;
        }

        @Override
        public MessageLocalisationProvider getMessageLocalisationProvider() {
            return messageLocalisationProvider;
        }

        @Override
        public Lang getWorkingLang() {
            return workingLang;
        }

        @Override
        public Predicate<Subset> getSubsetAccessPredicate() {
            return subsetAccessPredicate;
        }

        @Override
        public Predicate<FicheMeta> getFichePredicate() {
            return fichePredicate;
        }

        @Override
        public Corpus getCurrentCorpus() {
            return currentCorpus;
        }

    }

}
