/* BdfServer - Copyright (c) 2009-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 fr.exemole.bdfserver.tools.ficheform.builders;

import fr.exemole.bdfserver.api.BdfServerConstants;
import fr.exemole.bdfserver.api.ficheform.FicheFormParameters;
import fr.exemole.bdfserver.api.ficheform.ThesaurusIncludeElement;
import fr.exemole.bdfserver.api.ui.IncludeUi;
import fr.exemole.bdfserver.api.ui.SubsetIncludeUi;
import fr.exemole.bdfserver.tools.BdfServerUtils;
import fr.exemole.bdfserver.tools.L10nUtils;
import fr.exemole.bdfserver.tools.ficheform.FicheFormUtils;
import java.util.List;
import java.util.function.Predicate;
import net.fichotheque.SubsetKey;
import net.fichotheque.namespaces.SelectSpace;
import net.fichotheque.pointeurs.FichePointeur;
import net.fichotheque.pointeurs.SubsetItemPointeur;
import net.fichotheque.selection.MotcleQuery;
import net.fichotheque.selection.SelectionContext;
import net.fichotheque.thesaurus.Motcle;
import net.fichotheque.thesaurus.Thesaurus;
import net.fichotheque.tools.selection.MotcleQueryBuilder;
import net.fichotheque.utils.EligibilityUtils;
import net.fichotheque.utils.selection.MotcleSelectorBuilder;
import net.mapeadores.util.annotation.Nullable;
import net.mapeadores.util.attr.Attribute;
import net.mapeadores.util.attr.AttributeUtils;
import net.mapeadores.util.attr.Attributes;
import net.mapeadores.util.conditions.ConditionsConstants;
import net.mapeadores.util.conditions.TextCondition;
import net.mapeadores.util.conditions.TextConditionBuilder;


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

    private final static Predicate<Motcle> ALL_PREDICATE = (Motcle motcle) -> {
        return true;
    };
    private final String name;
    private final Thesaurus thesaurus;
    private final MotcleEntryListBuilder motcleEntryListBuilder = new MotcleEntryListBuilder();
    private String label = "";
    private boolean mandatory = false;
    private String listType;
    private SubsetKey destinationSubsetKey;
    private boolean noneAllowed;
    private Predicate<Motcle> filterPredicate = ALL_PREDICATE;
    private boolean newIndexation;
    private Attribute idalphaStyle = null;
    private Attributes attributes = AttributeUtils.EMPTY_ATTRIBUTES;

    public ChoiceThesaurusIncludeElementBuilder(String name, Thesaurus thesaurus) {
        this.name = name;
        this.thesaurus = thesaurus;
    }

    public ChoiceThesaurusIncludeElementBuilder setLabel(String label) {
        if (label == null) {
            throw new IllegalArgumentException("label is null");
        }
        this.label = label;
        return this;
    }

    public ChoiceThesaurusIncludeElementBuilder setMandatory(boolean mandatory) {
        this.mandatory = mandatory;
        return this;
    }

    public ChoiceThesaurusIncludeElementBuilder setAttributes(Attributes attributes) {
        if (attributes == null) {
            this.attributes = AttributeUtils.EMPTY_ATTRIBUTES;
        } else {
            this.attributes = attributes;
        }
        return this;
    }

    public ChoiceThesaurusIncludeElementBuilder setListType(String listType) {
        this.listType = listType;
        return this;
    }

    public ChoiceThesaurusIncludeElementBuilder setNoneAllowed(boolean noneAllowed) {
        this.noneAllowed = noneAllowed;
        return this;
    }

    public ChoiceThesaurusIncludeElementBuilder setIdalphaStyle(Attribute idalphaStyle) {
        this.idalphaStyle = idalphaStyle;
        return this;
    }

    public ChoiceThesaurusIncludeElementBuilder setDestinationSubsetKey(SubsetKey destinationSubsetKey) {
        this.destinationSubsetKey = destinationSubsetKey;
        return this;
    }

    public ChoiceThesaurusIncludeElementBuilder setFilterPredicate(Predicate<Motcle> filterPredicate) {
        if (filterPredicate == null) {
            this.filterPredicate = ALL_PREDICATE;
        } else {
            this.filterPredicate = filterPredicate;
        }
        return this;
    }

    public ChoiceThesaurusIncludeElementBuilder setNewIndexation(boolean newIndexation) {
        this.newIndexation = newIndexation;
        return this;
    }

    public ThesaurusIncludeElement.Choice toListThesaurusIncludeElement() {
        return new InternalListThesaurusIncludeElement(name, label, mandatory, attributes,
                listType, thesaurus, noneAllowed, destinationSubsetKey, idalphaStyle, motcleEntryListBuilder.toList(), filterPredicate, newIndexation);
    }

    @Nullable
    public static ChoiceThesaurusIncludeElementBuilder check(FichePointeur fichePointeur, FicheFormParameters ficheFormParameters, SubsetIncludeUi includeUi) {
        Thesaurus thesaurus = (Thesaurus) ficheFormParameters.getBdfServer().getFichotheque().getSubset(includeUi.getSubsetKey());
        if (thesaurus == null) {
            return null;
        }
        boolean isMandatory = includeUi.isMandatory();
        Predicate<Motcle> filterPredicate = getFilterPredicate(ficheFormParameters, includeUi, thesaurus);
        ChoiceThesaurusIncludeElementBuilder builder = init(includeUi.getName(), thesaurus)
                .setMandatory(isMandatory)
                .setAttributes(includeUi.getAttributes())
                .setListType(includeUi.getOptionValue(BdfServerConstants.INPUTTYPE_OPTION, BdfServerConstants.INPUT_CHECK))
                .setIdalphaStyle(FicheFormUtils.getIdalphaStyle(includeUi, thesaurus))
                .setNoneAllowed(!isMandatory)
                .setFilterPredicate(filterPredicate)
                .setLabel(L10nUtils.toLabelString(ficheFormParameters, includeUi));
        SubsetItemPointeur pointeur = FicheFormUtils.checkMasterPointeur(fichePointeur, ficheFormParameters, includeUi);
        if (pointeur.isEmpty()) {
            builder.motcleEntryListBuilder.populateDefault(ficheFormParameters, includeUi, thesaurus);
        } else {
            builder.motcleEntryListBuilder.populate(pointeur.getCroisements(thesaurus), includeUi, false);
        }
        if ((builder.motcleEntryListBuilder.isEmpty()) && (includeUi.isObsolete())) {
            return null;
        }
        return builder
                .setNewIndexation(pointeur.isEmpty());
    }

    public static ChoiceThesaurusIncludeElementBuilder init(String name, Thesaurus thesaurus) {
        return new ChoiceThesaurusIncludeElementBuilder(name, thesaurus);
    }

    private static Predicate<Motcle> getFilterPredicate(FicheFormParameters ficheFormParameters, IncludeUi includeUi, Thesaurus thesaurus) {
        if (!thesaurus.isIdalphaType()) {
            return ALL_PREDICATE;
        }
        Attribute idalphaFilter = includeUi.getAttributes().getAttribute(SelectSpace.IDALPHA_KEY);
        if (idalphaFilter == null) {
            return ALL_PREDICATE;
        }
        TextConditionBuilder conditionBuilder = TextConditionBuilder.init(ConditionsConstants.LOGICALOPERATOR_OR);
        for (String value : idalphaFilter) {
            conditionBuilder.addTextTest(value);
        }
        TextCondition condition = conditionBuilder.toTextCondition();
        MotcleQuery motcleQuery = MotcleQueryBuilder.init()
                .addThesaurus(thesaurus)
                .setContentCondition(condition, MotcleQuery.SCOPE_IDALPHA_ONLY)
                .toMotcleQuery();
        SelectionContext selectionContext = BdfServerUtils.initSelectionContextBuilder(ficheFormParameters.getBdfServer(), ficheFormParameters.getWorkingLang())
                .setSubsetAccessPredicate(EligibilityUtils.ALL_SUBSET_PREDICATE)
                .toSelectionContext();
        return MotcleSelectorBuilder.init(selectionContext)
                .add(motcleQuery, null)
                .toMotcleSelector();
    }


    private static class InternalListThesaurusIncludeElement implements ThesaurusIncludeElement.Choice {

        private final String name;
        private final String label;
        private final boolean mandatory;
        private final Attributes attributes;
        private final String listType;
        private final Thesaurus thesaurus;
        private final SubsetKey destinationSubsetKey;
        private final boolean noneAllowed;
        private final Attribute idalphaStyle;
        private final List<ThesaurusIncludeElement.Entry> list;
        private final Predicate<Motcle> filterPredicate;
        private final boolean newIndexation;


        private InternalListThesaurusIncludeElement(String name, String label, boolean mandatory, Attributes attributes, String listType, Thesaurus thesaurus,
                boolean noneAllowed, SubsetKey destinationSubsetKey, Attribute idalphaStyle, List<ThesaurusIncludeElement.Entry> list, Predicate<Motcle> filterPredicate, boolean newIndexation) {
            this.name = name;
            this.label = label;
            this.mandatory = mandatory;
            this.attributes = attributes;
            this.listType = listType;
            this.thesaurus = thesaurus;
            this.noneAllowed = noneAllowed;
            this.destinationSubsetKey = destinationSubsetKey;
            this.idalphaStyle = idalphaStyle;
            this.list = list;
            this.filterPredicate = filterPredicate;
            this.newIndexation = newIndexation;
        }

        @Override
        public String getIncludeName() {
            return name;
        }

        @Override
        public String getLabel() {
            return label;
        }

        @Override
        public boolean isMandatory() {
            return mandatory;
        }

        @Override
        public Attributes getAttributes() {
            return attributes;
        }

        @Override
        public String geChoiceType() {
            return listType;
        }

        @Override
        public Thesaurus getThesaurus() {
            return thesaurus;
        }

        @Override
        public boolean isNoneAllowed() {
            return noneAllowed;
        }

        @Override
        public Attribute getIdalphaStyle() {
            return idalphaStyle;
        }

        @Override
        public SubsetKey getDestinationSubsetKey() {
            return destinationSubsetKey;
        }

        @Override
        public List<Entry> getEntryList() {
            return list;
        }

        @Override
        public Predicate<Motcle> getFilterPredicate() {
            return filterPredicate;
        }

        @Override
        public boolean isNewIndexation() {
            return newIndexation;
        }

    }

}
