/* FichothequeLib_Tools - Copyright (c) 2010-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 net.fichotheque.tools.exportation.table;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.fichotheque.Subset;
import net.fichotheque.exportation.table.Col;
import net.fichotheque.exportation.table.ColDef;
import net.fichotheque.exportation.table.FormatColDef;
import net.fichotheque.exportation.table.SubsetTable;
import net.fichotheque.exportation.table.TableDef;
import net.fichotheque.exportation.table.TableExportContext;
import net.fichotheque.exportation.table.TableInclusionDef;
import net.fichotheque.exportation.table.TableInclusionResolver;
import net.fichotheque.format.FormatContext;
import net.fichotheque.format.formatters.SourceFormatter;
import net.fichotheque.tools.format.FichothequeFormatDefEngine;
import net.fichotheque.utils.TableDefUtils;
import net.fichotheque.utils.TableExportUtils;
import net.mapeadores.util.logging.LogUtils;


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

    private final Subset subset;
    private final boolean allowDuplicate;
    private final List<Col> colList = new ArrayList<Col>();
    private final Map<String, String> parameterMap = new HashMap<String, String>();
    private final Set<String> existingColNameSet = new HashSet<String>();

    public SubsetTableBuilder(Subset subset) {
        this.subset = subset;
        this.allowDuplicate = false;
    }

    public SubsetTableBuilder(Subset subset, boolean allowDuplicate) {
        this.subset = subset;
        this.allowDuplicate = allowDuplicate;
    }

    public SubsetTableBuilder addCol(Col col) {
        String colName = col.getColDef().getColName();
        if ((allowDuplicate) || (!existingColNameSet.contains(colName))) {
            colList.add(col);
            existingColNameSet.add(colName);
        }
        return this;
    }

    public SubsetTableBuilder addCol(ColDef colDef, SourceFormatter formatter) {
        return addCol(TableExportUtils.toCol(colDef, formatter));
    }

    public SubsetTableBuilder addCols(TableInclusionDef tableInclusionDef, TableExportContext tableExportContext) {
        TableInclusionResolver tableInclusionResolver = tableExportContext.getTableInclusionResolverProvider().getTableInclusionResolver(tableInclusionDef.getNameSpace());
        if (tableInclusionResolver != null) {
            Col[] resolvedColArray = tableInclusionResolver.resolve(tableInclusionDef, subset, tableExportContext);
            for (Col col : resolvedColArray) {
                addCol(col);
            }
        }
        return this;
    }

    public SubsetTableBuilder addCol(FormatColDef colDef, FormatContext formatContext, boolean ignoreMissingCorpusField, String defaultSeparator) {
        SourceFormatter formatter = FichothequeFormatDefEngine.compute(subset, ((FormatColDef) colDef).getFichothequeFormatDef(), LogUtils.NULL_MESSAGEHANDLER, FichothequeFormatDefEngine.parameters(formatContext).defaultGlobalSelect(true).ignoreMissingCorpusField(ignoreMissingCorpusField).defaultSeparator(defaultSeparator));
        if (formatter != null) {
            addCol(colDef, formatter);
        }
        return this;
    }

    public SubsetTableBuilder addParameter(String parameterName, String parameterValue) {
        parameterMap.put(parameterName, parameterValue);
        return this;
    }

    public SubsetTableBuilder populate(TableDef tableDef, TableExportContext tableExportContext) {
        return populate(tableDef, tableExportContext, false, ";");
    }

    public SubsetTableBuilder populate(TableDef tableDef, TableExportContext tableExportContext, boolean ignoreMissingCorpusField, String defaultSeparator) {
        for (String name : tableDef.getParameterNameSet()) {
            addParameter(name, tableDef.getParameterName(name));
        }
        for (TableDef.Entry defEntry : tableDef.getEntryList()) {
            if (defEntry instanceof FormatColDef) {
                addCol((FormatColDef) defEntry, tableExportContext.getFormatContext(), ignoreMissingCorpusField, defaultSeparator);
            } else if (defEntry instanceof TableInclusionDef) {
                addCols((TableInclusionDef) defEntry, tableExportContext);
            }
        }
        return this;
    }

    public SubsetTable toSubsetTable() {
        int size = colList.size();
        ColDef[] colDefArray = new ColDef[size];
        Col[] colArray = new Col[size];
        for (int i = 0; i < size; i++) {
            Col col = colList.get(i);
            colArray[i] = col;
            colDefArray[i] = col.getColDef();
        }
        return new InternalSubsetTable(subset, TableDefUtils.wrap(colDefArray), TableExportUtils.wrap(colArray), parameterMap);
    }

    public static SubsetTableBuilder init(Subset subset) {
        return new SubsetTableBuilder(subset);
    }

    public static SubsetTableBuilder init(Subset subset, boolean allowDuplicate) {
        return new SubsetTableBuilder(subset, allowDuplicate);
    }


    private static class InternalSubsetTable implements SubsetTable {

        private final Subset subset;
        private final List<ColDef> colDefList;
        private final List<Col> colList;
        private final Map<String, String> parameterMap;

        private InternalSubsetTable(Subset subset, List<ColDef> colDefList, List<Col> colList, Map<String, String> parameterMap) {
            this.subset = subset;
            this.colDefList = colDefList;
            this.colList = colList;
            this.parameterMap = parameterMap;
        }

        @Override
        public Subset getSubset() {
            return subset;
        }

        @Override
        public List<ColDef> getColDefList() {
            return colDefList;
        }

        @Override
        public List<Col> getColList() {
            return colList;
        }

        @Override
        public String getParameterValue(String parameterName) {
            return parameterMap.get(parameterName);
        }

    }

}
