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

import java.util.function.Predicate;
import net.fichotheque.SubsetItem;
import net.fichotheque.selection.CroisementCondition;
import net.fichotheque.selection.FicheCondition;
import net.fichotheque.selection.MotcleQuery;
import net.fichotheque.selection.RangeCondition;
import net.fichotheque.selection.SelectionContext;
import net.fichotheque.selection.StatusCondition;
import net.fichotheque.thesaurus.Motcle;
import net.mapeadores.util.conditions.ConditionsConstants;
import net.mapeadores.util.conditions.ConditionsUtils;
import net.mapeadores.util.conditions.TextCondition;
import net.mapeadores.util.conditions.TextTestEngine;
import net.mapeadores.util.exceptions.SwitchException;
import net.mapeadores.util.localisation.Lang;
import net.mapeadores.util.text.Label;


/**
 *
 * @author Vincent Calame
 */
class MotcleSelectEngine {

    private final Lang lang;
    private final RangeCondition idRangeCondition;
    private final RangeCondition levelRangeCondition;
    private final StatusCondition statusCondition;
    private final FieldTest fieldTest;
    private final CroisementCondition croisementCondition;
    private final Predicate<SubsetItem> ficheConditionPredicate;

    MotcleSelectEngine(MotcleQuery motcleQuery, CroisementCondition croisementCondition, SelectionContext selectionContext) {
        this.lang = selectionContext.getWorkingLang();
        this.idRangeCondition = motcleQuery.getIdRangeCondition();
        this.levelRangeCondition = motcleQuery.getLevelRangeCondition();
        this.statusCondition = motcleQuery.getStatusCondition();
        MotcleQuery.ContentCondition contentCondition = motcleQuery.getContentCondition();
        if (contentCondition == null) {
            fieldTest = null;
        } else {
            fieldTest = initFieldTest(contentCondition, lang);
        }
        this.croisementCondition = croisementCondition;
        FicheCondition ficheCondition = motcleQuery.getFicheCondition();
        if (ficheCondition != null) {
            this.ficheConditionPredicate = FicheConditionPredicateFactory.newInstance(selectionContext, ficheCondition);
        } else {
            this.ficheConditionPredicate = null;
        }
    }

    private FieldTest initFieldTest(MotcleQuery.ContentCondition contentCondition, Lang lang) {
        short conditionType = ConditionsUtils.getConditionType(contentCondition.getTextCondition());
        switch (conditionType) {
            case ConditionsConstants.IMPOSSIBLE_CONDITION:
                return new ConstantFieldTest(false);
            case ConditionsConstants.NEUTRAL_CONDITION:
            case ConditionsConstants.UNKNOWN_CONDITION:
                return new ConstantFieldTest(true);
            case ConditionsConstants.NOTEMPTY_CONDITION:
                return new NotEmptyFieldTest(true);
            case ConditionsConstants.EMPTY_CONDITION:
                return new NotEmptyFieldTest(false);
            case ConditionsConstants.PARTIAL_CONDITION:
            case ConditionsConstants.PARTIALOREMPTY_CONDITION:
                return new ContentFieldTest(contentCondition.getScope(), contentCondition.getTextCondition(), lang);
            default:
                throw new SwitchException("state = " + conditionType);
        }
    }

    boolean isSelected(Motcle motcle) {
        if (statusCondition != null) {
            if (!statusCondition.accept(motcle.getStatus())) {
                return false;
            }
        }
        if (levelRangeCondition != null) {
            if (!levelRangeCondition.accept(motcle.getLevel())) {
                return false;
            }
        }
        if (idRangeCondition != null) {
            if (!idRangeCondition.accept(motcle.getId())) {
                return false;
            }
        }
        if (ficheConditionPredicate != null) {
            if (!ficheConditionPredicate.test(motcle)) {
                return false;
            }
        }
        if (fieldTest != null) {
            if (!fieldTest.isSelected(motcle)) {
                return false;
            }
        }
        return true;
    }

    void filter(Motcle motcle, FilteredCroisementBuilder builder) {
        if (!isSelected(motcle)) {
            return;
        }
        builder.testCondition(croisementCondition);
    }


    private abstract class FieldTest {

        public abstract boolean isSelected(Motcle motcle);

    }


    private class ConstantFieldTest extends FieldTest {

        private final boolean constantAnswer;

        private ConstantFieldTest(boolean constantAnswer) {
            this.constantAnswer = constantAnswer;
        }

        @Override
        public boolean isSelected(Motcle motcle) {
            return constantAnswer;
        }

    }


    private class NotEmptyFieldTest extends FieldTest {

        private final boolean notEmptyWanted;

        private NotEmptyFieldTest(boolean notEmpty) {
            this.notEmptyWanted = notEmpty;
        }

        @Override
        public boolean isSelected(Motcle motcle) {
            Label label = motcle.getLabels().getLabel(lang);
            if (label != null) {
                return notEmptyWanted;
            } else {
                return !notEmptyWanted;
            }
        }

    }


    private class ContentFieldTest extends FieldTest {

        private final String scope;
        private final TextTestEngine textTestEngine;


        private ContentFieldTest(String scope, TextCondition fieldCondition, Lang lang) {
            this.scope = scope;
            this.textTestEngine = TextTestEngine.newInstance(fieldCondition, lang);

        }

        @Override
        public boolean isSelected(Motcle motcle) {
            textTestEngine.start();
            if (!scope.equals(MotcleQuery.SCOPE_IDALPHA_WITHOUT)) {
                String idalpha = motcle.getIdalpha();
                if (idalpha != null) {
                    textTestEngine.addString(idalpha);
                    if (scope.equals(MotcleQuery.SCOPE_IDALPHA_ONLY)) {
                        return textTestEngine.getResult();
                    }
                }
            }
            if (!textTestEngine.canStop()) {
                textTestEngine.addString(motcle.getLabelString(lang, ""));
            }
            return textTestEngine.getResult();
        }

    }

}
