/* FichothequeLib_Tools - Copyright (c) 2012-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.selection;

import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;
import net.fichotheque.SubsetKey;
import net.fichotheque.selection.FicheCondition;
import net.fichotheque.selection.MotcleQuery;
import net.fichotheque.selection.RangeCondition;
import net.fichotheque.selection.StatusCondition;
import net.fichotheque.selection.SubsetCondition;
import net.fichotheque.thesaurus.Thesaurus;
import net.fichotheque.utils.SelectionUtils;
import net.fichotheque.utils.selection.FicheConditionBuilder;
import net.mapeadores.util.conditions.ConditionsConstants;
import net.mapeadores.util.conditions.TextCondition;


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

    private final Set<SubsetKey> thesaurusKeySet = new LinkedHashSet<SubsetKey>();
    private final FicheConditionBuilder ficheConditionBuilder = FicheConditionBuilder.init().setLogicalOperator(ConditionsConstants.LOGICALOPERATOR_AND);
    private final Set<String> statusSet = new LinkedHashSet<String>();
    private RangeCondition idRangeCondition = null;
    private RangeCondition levelRangeCondition = null;
    private TextCondition contentTextCondition = null;
    private String contentConditionScope = null;
    private boolean withCurrentThesaurus = false;
    private boolean exclude = false;

    public MotcleQueryBuilder() {

    }

    public MotcleQueryBuilder addThesaurus(Object object) {
        if (object == null) {
            return this;
        }
        if (object instanceof Thesaurus) {
            thesaurusKeySet.add(((Thesaurus) object).getSubsetKey());
        } else if (object instanceof SubsetKey) {
            SubsetKey subsetKey = (SubsetKey) object;
            if (subsetKey.isThesaurusSubset()) {
                thesaurusKeySet.add(subsetKey);
            }
        } else if (object instanceof Collection) {
            for (Object obj : ((Collection) object)) {
                if (obj != null) {
                    if (obj instanceof Thesaurus) {
                        thesaurusKeySet.add(((Thesaurus) obj).getSubsetKey());
                    } else if (obj instanceof SubsetKey) {
                        SubsetKey subsetKey = (SubsetKey) obj;
                        if (subsetKey.isThesaurusSubset()) {
                            thesaurusKeySet.add(subsetKey);
                        }
                    }
                }
            }
        } else if (object instanceof SubsetKey[]) {
            for (SubsetKey subsetKey : ((SubsetKey[]) object)) {
                if ((subsetKey != null) && (subsetKey.isThesaurusSubset())) {
                    thesaurusKeySet.add(subsetKey);
                }
            }
        }
        return this;
    }

    public MotcleQueryBuilder setIdRangeCondition(RangeCondition idRangeCondition) {
        this.idRangeCondition = idRangeCondition;
        return this;
    }

    public MotcleQueryBuilder setLevelRangeCondition(RangeCondition levelRangeCondition) {
        this.levelRangeCondition = levelRangeCondition;
        return this;
    }

    public MotcleQueryBuilder setContentCondition(TextCondition contentTextCondition, String contentConditionScope) {
        this.contentTextCondition = contentTextCondition;
        this.contentConditionScope = MotcleQuery.checkScope(contentConditionScope);
        return this;
    }

    public MotcleQueryBuilder addFicheConditionQuery(FicheCondition.Entry entry) {
        if (entry == null) {
            throw new IllegalArgumentException("ficheQuery is null");
        }
        ficheConditionBuilder.addEntry(entry);
        return this;
    }

    public MotcleQueryBuilder setFicheLogicalOperator(String ficheLogicalOperator) {
        ficheConditionBuilder.setLogicalOperator(ficheLogicalOperator);
        return this;
    }

    public MotcleQueryBuilder setWithCurrentThesaurus(boolean withCurrentThesaurus) {
        this.withCurrentThesaurus = withCurrentThesaurus;
        return this;
    }

    public MotcleQueryBuilder setExclude(boolean exclude) {
        this.exclude = exclude;
        return this;
    }

    public MotcleQueryBuilder addStatus(String status) {
        if (!status.isEmpty()) {
            this.statusSet.add(status);
        }
        return this;
    }

    public MotcleQuery toMotcleQuery() {
        SubsetCondition thesaurusCondition = SelectionUtils.toSubsetCondition(new LinkedHashSet(thesaurusKeySet), withCurrentThesaurus, exclude);
        StatusCondition statusCondition = SelectionUtils.toStatusCondition(statusSet);
        FicheCondition ficheCondition;
        if (ficheConditionBuilder.isEmpty()) {
            ficheCondition = null;
        } else {
            ficheCondition = ficheConditionBuilder.toFicheCondition();
        }
        MotcleQuery.ContentCondition contentCondition = null;
        if (contentTextCondition != null) {
            contentCondition = new InternalContentCondition(contentConditionScope, contentTextCondition);
        }
        return new InternalMotcleQuery(thesaurusCondition, idRangeCondition, levelRangeCondition, contentCondition, ficheCondition, statusCondition);
    }

    public static MotcleQueryBuilder init() {
        return new MotcleQueryBuilder();
    }


    private static class InternalMotcleQuery implements MotcleQuery {

        private final SubsetCondition thesaurusCondition;
        private final RangeCondition idRangeCondition;
        private final RangeCondition levelRangeCondition;
        private final ContentCondition contentCondition;
        private final FicheCondition ficheCondition;
        private final StatusCondition statusCondition;

        private InternalMotcleQuery(SubsetCondition thesaurusCondition, RangeCondition idRangeCondition, RangeCondition levelRangeCondition,
                ContentCondition contentCondition, FicheCondition ficheCondition, StatusCondition statusCondition) {
            this.thesaurusCondition = thesaurusCondition;
            this.idRangeCondition = idRangeCondition;
            this.levelRangeCondition = levelRangeCondition;
            this.contentCondition = contentCondition;
            this.ficheCondition = ficheCondition;
            this.statusCondition = statusCondition;
        }

        @Override
        public SubsetCondition getThesaurusCondition() {
            return thesaurusCondition;
        }

        @Override
        public RangeCondition getIdRangeCondition() {
            return idRangeCondition;
        }

        @Override
        public RangeCondition getLevelRangeCondition() {
            return levelRangeCondition;
        }

        @Override
        public ContentCondition getContentCondition() {
            return contentCondition;
        }

        @Override
        public FicheCondition getFicheCondition() {
            return ficheCondition;
        }

        @Override
        public StatusCondition getStatusCondition() {
            return statusCondition;
        }

    }


    private static class InternalContentCondition implements MotcleQuery.ContentCondition {

        private final String scope;
        private final TextCondition textCondition;

        private InternalContentCondition(String scope, TextCondition textCondition) {
            this.scope = scope;
            this.textCondition = textCondition;
        }

        @Override
        public String getScope() {
            return scope;
        }

        @Override
        public TextCondition getTextCondition() {
            return textCondition;
        }

    }

}
