/* BdfServer_JsonProducers - Copyright (c) 2013-2026 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.jsonproducers.main;

import fr.exemole.bdfserver.api.instruction.BdfParameters;
import fr.exemole.bdfserver.api.users.BdfUser;
import fr.exemole.bdfserver.json.AccessJson;
import fr.exemole.bdfserver.json.ColDefJson;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import net.fichotheque.Subset;
import net.fichotheque.SubsetItem;
import net.fichotheque.corpus.Corpus;
import net.fichotheque.corpus.Fiches;
import net.fichotheque.exportation.table.CellConverter;
import net.fichotheque.exportation.table.ColDef;
import net.fichotheque.exportation.table.ColDefTitleProvider;
import net.fichotheque.exportation.table.SubsetTable;
import net.fichotheque.exportation.table.SumCellConverter;
import net.fichotheque.exportation.table.SumResult;
import net.fichotheque.exportation.table.TableExportContext;
import net.fichotheque.json.CellJson;
import net.fichotheque.json.MetadataJson;
import net.fichotheque.permission.PermissionSummary;
import net.fichotheque.thesaurus.Thesaurus;
import net.fichotheque.tools.exportation.table.FormulaEngine;
import net.fichotheque.utils.CorpusUtils;
import net.fichotheque.utils.FichothequeUtils;
import net.fichotheque.utils.TableDefUtils;
import net.fichotheque.utils.ThesaurusUtils;
import net.mapeadores.util.exceptions.SwitchException;
import net.mapeadores.util.format.FormatConstants;
import net.mapeadores.util.json.JSONWriter;
import net.mapeadores.util.json.JsonProperty;
import net.mapeadores.util.localisation.Lang;
import net.mapeadores.util.localisation.LangContext;
import net.mapeadores.util.money.Amount;


/**
 *
 * @author Vincent Calame
 */
public class TableJsonProperty implements JsonProperty {

    private final BdfParameters bdfParameters;
    private final BdfUser bdfUser;
    private final SubsetTable subsetTable;
    private final TableExportContext tableExportContext;
    private final CellConverter cellConverter;
    private final String propertiesMapping;

    public TableJsonProperty(BdfParameters bdfParameters, SubsetTable subsetTable, TableExportContext tableExportContext, CellConverter cellConverter, String propertiesMapping) {
        this.bdfParameters = bdfParameters;
        this.bdfUser = bdfParameters.getBdfUser();
        this.subsetTable = subsetTable;
        this.tableExportContext = tableExportContext;
        this.cellConverter = cellConverter;
        this.propertiesMapping = propertiesMapping;
    }

    @Override
    public String getName() {
        return "table";
    }

    @Override
    public void writeValue(JSONWriter jw) throws IOException {
        Subset subset = subsetTable.getSubset();
        PermissionSummary permissionSummary = bdfParameters.getPermissionSummary();
        Collection<SubsetItem> subsetItems = getSubsetItems(subset);
        Lang workingLang = bdfUser.getWorkingLang();
        List<ColDef> colDefList = subsetTable.getColDefList();
        int colCount = colDefList.size();
        boolean[] hiddenArray = new boolean[colCount];
        ColDefTitleProvider colDefTitleProvider = TableDefUtils.getLabelColDefTitleProvider(workingLang, tableExportContext.getSourceLabelProvider(), subset);
        jw.object();
        {
            jw.key("meta");
            jw.object();
            {
                jw.key("lang")
                        .value(bdfUser.getWorkingLang().toString());
                jw.key("locale")
                        .value(bdfUser.getISOFormatLocaleString());
                jw.key("mapping")
                        .value(propertiesMapping);
                MetadataJson.subsetProperty(jw, subsetTable.getSubsetKey());
                jw.key("columns");
                jw.array();
                for (int j = 0; j < colCount; j++) {
                    ColDef colDef = colDefList.get(j);
                    if (FormulaEngine.isFormula(colDef)) {
                        hiddenArray[j] = true;
                    } else {
                        hiddenArray[j] = false;
                        jw.object();
                        ColDefJson.properties(jw, colDef, colDefTitleProvider);
                        jw.endObject();
                    }
                }
                jw.endArray();
            }
            jw.endObject();
            jw.key("data");
            jw.array();
            for (SubsetItem subsetItem : subsetItems) {
                jw.object();
                AccessJson.properties(jw, subsetItem, permissionSummary, cellConverter);
                jw.endObject();
            }
            jw.endArray();
            if (cellConverter instanceof SumCellConverter) {
                SumResult sumResult = ((SumCellConverter) cellConverter).getSumResult(subsetTable);
                if (sumResult.hasColumnSum()) {
                    List<SumResult.Entry> entryList = sumResult.getEntryList();
                    jw.key("sum");
                    jw.array();
                    for (int j = 0; j < colCount; j++) {
                        if (hiddenArray[j]) {
                            continue;
                        }
                        SumResult.ColumnSum columnSum = entryList.get(j).getColumnSum();
                        if (columnSum != null) {
                            writeColumnSum(jw, columnSum, bdfUser);
                        } else {
                            jw.value(false);
                        }
                    }
                    jw.endArray();
                }
            }
        }
        jw.endObject();
    }

    private void writeColumnSum(JSONWriter jw, SumResult.ColumnSum columnSum, LangContext langContext) throws IOException {
        if (columnSum instanceof SumResult.IntegerColumnSum) {
            CellJson.value(jw, FormatConstants.INTEGER_CAST, ((SumResult.IntegerColumnSum) columnSum).getResult(), langContext);
        } else if (columnSum instanceof SumResult.DecimalColumnSum) {
            CellJson.value(jw, FormatConstants.DECIMAL_CAST, ((SumResult.DecimalColumnSum) columnSum).getResult(), langContext);
        } else if (columnSum instanceof SumResult.PercentageColumnSum) {
            CellJson.value(jw, FormatConstants.PERCENTAGE_CAST, ((SumResult.PercentageColumnSum) columnSum).getResult(), langContext);
        } else if (columnSum instanceof SumResult.MoneyColumnSum) {
            jw.object();
            {
                SumResult.MoneyColumnSum moneyColumnSum = (SumResult.MoneyColumnSum) columnSum;
                int resultCount = moneyColumnSum.getResultCount();
                jw.key("moneyArray");
                jw.array();
                for (int k = 0; k < resultCount; k++) {
                    Amount resultAmount = moneyColumnSum.getResult(k);
                    CellJson.value(jw, FormatConstants.MONEY_CAST, resultAmount, langContext);
                }
                jw.endArray();
            }
            jw.endObject();
        } else {
            jw.value(false);
        }
    }

    private Collection<SubsetItem> getSubsetItems(Subset subset) {
        if (subset instanceof Corpus) {
            Fiches fiches = bdfUser.getSelectedFiches();
            return CorpusUtils.getFicheMetaListByCorpus(fiches, subset.getSubsetKey());
        } else if (subset instanceof Thesaurus) {
            Thesaurus thesaurus = (Thesaurus) subset;
            if ((thesaurus == null) || (thesaurus.size() == 0)) {
                return FichothequeUtils.EMPTY_SUBSETITEMLIST;
            } else {
                return ThesaurusUtils.toSubsetItemList(thesaurus, -1);
            }
        }
        throw new SwitchException("Unknown subset: " + subset.getSubsetKeyString());
    }

}
