/* BdfServer - Copyright (c) 2014-2025 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.json;

import java.io.IOException;
import java.util.List;
import net.fichotheque.Fichotheque;
import net.fichotheque.corpus.metadata.FieldKey;
import net.fichotheque.selection.CroisementCondition;
import net.fichotheque.selection.FicheCondition;
import net.fichotheque.selection.FicheQuery;
import net.fichotheque.selection.FieldContentCondition;
import net.fichotheque.selection.MotcleCondition;
import net.fichotheque.selection.PeriodCondition;
import net.fichotheque.selection.RangeCondition;
import net.fichotheque.selection.SubsetCondition;
import net.fichotheque.selection.UserCondition;
import net.fichotheque.utils.FichothequeXMLUtils;
import net.mapeadores.util.annotation.Nullable;
import net.mapeadores.util.conditions.ConditionsUtils;
import net.mapeadores.util.conditions.TextCondition;
import net.mapeadores.util.json.JSONWriter;
import net.mapeadores.util.xml.XMLUtils;
import net.mapeadores.util.xml.XMLWriter;


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

    private FicheQueryJson() {

    }

    public static void properties(JSONWriter jw, Fichotheque fichotheque, FicheQuery ficheQuery) throws IOException {
        properties(jw, fichotheque, ficheQuery, null, false);
    }

    public static void properties(JSONWriter jw, Fichotheque fichotheque, FicheCondition.Entry ficheConditionEntry) throws IOException {
        properties(jw, fichotheque, ficheConditionEntry.getFicheQuery(), ficheConditionEntry.getCroisementCondition(), ficheConditionEntry.includeSatellites());
    }

    private static void properties(JSONWriter jw, Fichotheque fichotheque, FicheQuery ficheQuery, @Nullable CroisementCondition croisementCondition, boolean includeSatellites) throws IOException {
        SubsetCondition corpusCondition = ficheQuery.getCorpusCondition();
        jw.key("corpus");
        jw.object();
        ConditionJson.properties(jw, corpusCondition);
        jw.endObject();
        RangeCondition idRangeCondition = ficheQuery.getIdRangeCondition();
        if (idRangeCondition != null) {
            jw.key("range");
            jw.object();
            ConditionJson.properties(jw, idRangeCondition);
            jw.endObject();
        }
        String discardFilter = ficheQuery.getDiscardFilter();
        if (!discardFilter.equals(FicheQuery.DISCARDFILTER_ALL)) {
            jw.key("discard")
                    .value(discardFilter);
        }
        PeriodCondition periodCondition = ficheQuery.getPeriodCondition();
        if (periodCondition != null) {
            jw.key("period");
            jw.object();
            ConditionJson.properties(jw, periodCondition);
            jw.endObject();
        }
        FieldContentCondition fieldContentCondition = ficheQuery.getFieldContentCondition();
        if (fieldContentCondition != null) {
            jw.key("content");
            jw.object();
            properties(jw, fieldContentCondition);
            jw.endObject();
        }
        userConditionProperty(jw, ficheQuery, fichotheque);
        if (ficheQuery.isWithGeoloc()) {
            jw.key("geoloc")
                    .value(true);
        }
        MotcleCondition motcleCondition = ficheQuery.getMotcleCondition();
        if (motcleCondition != null) {
            jw.key("motcle");
            jw.object();
            ConditionJson.properties(jw, motcleCondition, fichotheque);
            jw.endObject();
        }
        FicheCondition ficheCondition = ficheQuery.getFicheCondition();
        if (ficheCondition != null) {
            jw.key("fiche");
            jw.object();
            ConditionJson.properties(jw, ficheCondition, fichotheque);
            jw.endObject();
        }
        if (includeSatellites) {
            jw.key("satellite")
                    .value(true);
        }
        if (croisementCondition != null) {
            jw.key("croisement");
            jw.object();
            CroisementJson.properties(jw, croisementCondition);
            jw.endObject();
        }
    }

    public static String toXmlString(List<FicheQuery> ficheQueryList) {
        StringBuilder buf = new StringBuilder();
        if (!ficheQueryList.isEmpty()) {
            XMLWriter xmlWriter = XMLUtils.toXMLWriter(buf);
            for (FicheQuery ficheQuery : ficheQueryList) {
                try {
                    xmlWriter.openTag("fiche-query");
                    FichothequeXMLUtils.writeFicheQuery(xmlWriter, ficheQuery, true);
                    xmlWriter.closeTag("fiche-query");
                } catch (IOException ioe) {
                }
            }
        }
        return buf.toString();
    }

    public static void properties(JSONWriter jw, FieldContentCondition fieldContentCondition) throws IOException {
        String scope = fieldContentCondition.getScope();
        jw.key("scope");
        if (scope.equals(FieldContentCondition.SELECTION_SCOPE)) {
            jw.array();
            for (FieldKey fieldKey : fieldContentCondition.getFieldKeyList()) {
                jw.value(fieldKey.getKeyString());
            }
            jw.endArray();
        } else {
            jw.value(scope);
        }
        TextCondition condition = fieldContentCondition.getTextCondition();
        jw.key("operator")
                .value(condition.getLogicalOperator());
        jw.key("q")
                .value(ConditionsUtils.conditionToString(condition));

    }

    private static void userConditionProperty(JSONWriter jw, FicheQuery ficheQuery, Fichotheque fichotheque) throws IOException {
        UserCondition userCondition = ficheQuery.getUserCondition();
        if (userCondition == null) {
            return;
        }
        if (userCondition.isSome()) {
            jw.key("users");
            jw.array();
            for (UserCondition.Entry entry : userCondition.getEntryList()) {
                jw.object();
                if (entry instanceof UserCondition.LoginEntry) {
                    UserCondition.LoginEntry loginEntry = (UserCondition.LoginEntry) entry;
                    jw.key("sphere")
                            .value(loginEntry.getSphereName());
                    jw.key("login")
                            .value(loginEntry.getLogin());
                } else if (entry instanceof UserCondition.IdEntry) {
                    UserCondition.IdEntry idEntry = (UserCondition.IdEntry) entry;
                    jw.key("sphere")
                            .value(idEntry.getSphereName());
                    jw.key("id")
                            .value(idEntry.getId());
                } else {
                    jw.key("sphere")
                            .value(entry.getSphereName());
                }
                jw.endObject();
            }
            jw.endArray();
        } else {
            jw.key("users")
                    .value(userCondition.getFilter());
        }
    }

}
