/* BdfServer - Copyright (c) 2007-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.tools.exportation.table;

import fr.exemole.bdfserver.api.BdfServer;
import fr.exemole.bdfserver.api.exportation.table.FicheTableParameters;
import fr.exemole.bdfserver.api.instruction.BdfParameters;
import fr.exemole.bdfserver.api.managers.TableExportManager;
import fr.exemole.bdfserver.api.namespaces.UiSpace;
import fr.exemole.bdfserver.api.ui.UiComponent;
import fr.exemole.bdfserver.api.ui.UiComponents;
import fr.exemole.bdfserver.tools.BdfServerUtils;
import fr.exemole.bdfserver.tools.ui.UiUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import net.fichotheque.Subset;
import net.fichotheque.SubsetItem;
import net.fichotheque.SubsetKey;
import net.fichotheque.corpus.Corpus;
import net.fichotheque.exportation.table.CellConverterProvider;
import net.fichotheque.exportation.table.SubsetTable;
import net.fichotheque.exportation.table.SumCellConverter;
import net.fichotheque.exportation.table.TableDef;
import net.fichotheque.exportation.table.TableExport;
import net.fichotheque.exportation.table.TableExportContentDescription;
import net.fichotheque.exportation.table.TableExportContext;
import net.fichotheque.exportation.table.TableExportDef;
import net.fichotheque.exportation.table.TableExportDescription;
import net.fichotheque.extraction.ExtractionContext;
import net.fichotheque.permission.PermissionSummary;
import net.fichotheque.thesaurus.Thesaurus;
import net.fichotheque.tools.exportation.table.SubsetTableBuilder;
import net.fichotheque.tools.exportation.table.SumCellConverterFactory;
import net.fichotheque.tools.exportation.table.TableExportBuilder;
import net.fichotheque.utils.TableExportUtils;
import net.mapeadores.util.annotation.Nullable;


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

    public final static FicheTableParameters NONE_FICHETABLEPARAMETERS = FicheTableParametersBuilder.init()
            .toFicheTableParameters();
    public final static FicheTableParameters ALL_FICHETABLEPARAMETERS = FicheTableParametersBuilder.init()
            .putWith(FicheTableParameters.WITH_SECTION)
            .putWith(FicheTableParameters.WITH_CHRONO)
            .putWith(FicheTableParameters.WITH_ADDENDAINCLUDE)
            .putWith(FicheTableParameters.WITH_ALBUMINCLUDE)
            .putWith(FicheTableParameters.WITH_CORPUSINCLUDE)
            .putWith(FicheTableParameters.WITH_THESAURUSINCLUDE)
            .toFicheTableParameters();


    private BdfTableExportUtils() {
    }

    public static TableExport toDefaultTableExport(BdfServer bdfServer, FicheTableParameters ficheTableParameters, PermissionSummary permissionSummary) {
        TableExportBuilder tableExportBuilder = TableExportBuilder.init()
                .setTableExportDef(null);
        TableExportContext tableExportContext = bdfServer.getTableExportContext();
        for (Corpus corpus : bdfServer.getFichotheque().getCorpusList()) {
            if (!permissionSummary.hasAccess(corpus)) {
                continue;
            }
            TableDef tableDef = DefaultTableDefFactory.fromUi(bdfServer, corpus, ficheTableParameters, permissionSummary);
            tableExportBuilder.addSubsetTable(SubsetTableBuilder.init(corpus).populate(tableDef, tableExportContext).toSubsetTable());
        }
        return tableExportBuilder.toTableExport();
    }

    public static SubsetTable toDefaultSubsetTable(BdfServer bdfServer, Subset subset, FicheTableParameters ficheTableParameters, PermissionSummary permissionSummary) {
        TableDef tableDef;
        if (subset instanceof Corpus) {
            Corpus corpus = (Corpus) subset;
            tableDef = DefaultTableDefFactory.fromUi(bdfServer, corpus, ficheTableParameters, permissionSummary);

        } else if (subset instanceof Thesaurus) {
            Thesaurus thesaurus = (Thesaurus) subset;
            tableDef = DefaultTableDefFactory.fromThesaurusMetadata(thesaurus, bdfServer.getThesaurusLangChecker());
        } else {
            throw new UnsupportedOperationException("Unable to deal with : " + subset.getSubsetKeyString());
        }
        return SubsetTableBuilder.init(subset).populate(tableDef, bdfServer.getTableExportContext()).toSubsetTable();
    }

    public static List<TableExportDescription> getAvailableTableExportDescriptionList(TableExportManager manager, SubsetKey subsetKey, String hideTest) {
        String requestedPath = subsetKey + ".txt";
        List<TableExportDescription> list = new ArrayList<TableExportDescription>();
        for (TableExportDescription tableExportDescription : manager.getValidTableExportDescriptionList()) {
            if (UiSpace.testHide(tableExportDescription.getTableExportDef().getAttributes(), hideTest)) {
                continue;
            }
            boolean here = false;
            for (TableExportContentDescription tableExportContentDescription : tableExportDescription.getTableExportContentDescriptionList()) {
                String contentPath = tableExportContentDescription.getPath();
                if (contentPath.equals(requestedPath)) {
                    here = true;
                    break;
                }
            }
            if (here) {
                list.add(tableExportDescription);
            }
        }
        return list;
    }

    public static TableExportDescription getValidTableExportDescription(TableExportManager manager, String tableExportName) {
        for (TableExportDescription tableExportDescription : manager.getValidTableExportDescriptionList()) {
            if (tableExportDescription.getName().equals(tableExportName)) {
                return tableExportDescription;
            }
        }
        return null;
    }

    public static SumCellConverter toCellConverter(BdfServer bdfServer, ExtractionContext extractionContext, SubsetTable subsetTable) {
        return toCellConverter(bdfServer, extractionContext, subsetTable, null, null, true);
    }

    public static SumCellConverter toCellConverter(BdfServer bdfServer, ExtractionContext extractionContext, SubsetTable subsetTable, @Nullable TableExportDef tableExportDef) {
        return toCellConverter(bdfServer, extractionContext, subsetTable, tableExportDef, null, true);
    }

    public static SumCellConverter toCellConverter(BdfServer bdfServer, ExtractionContext extractionContext, SubsetTable subsetTable, @Nullable TableExportDef tableExportDef, @Nullable Predicate<SubsetItem> globalPredicate) {
        return toCellConverter(bdfServer, extractionContext, subsetTable, tableExportDef, globalPredicate, true);
    }

    public static SumCellConverter toCellConverter(BdfServer bdfServer, ExtractionContext extractionContext, SubsetTable subsetTable, @Nullable TableExportDef tableExportDef, @Nullable Predicate<SubsetItem> globalPredicate, boolean withLangContextCheck) {
        if (withLangContextCheck) {
            extractionContext = BdfServerUtils.checkLangMode(extractionContext, bdfServer, tableExportDef);
        }
        CellConverterProvider cellConverterProvider = CellConverterProviderFactory.newInstance(bdfServer, extractionContext, globalPredicate, withLangContextCheck);
        return SumCellConverterFactory.newInstance(subsetTable, bdfServer.getTableExportContext(), extractionContext, cellConverterProvider, globalPredicate);
    }

    public static SumCellConverter toCellConverter(BdfServer bdfServer, ExtractionContext extractionContext, TableExport tableExport) {
        return toCellConverter(bdfServer, extractionContext, tableExport, null, true);
    }

    public static SumCellConverter toCellConverter(BdfServer bdfServer, ExtractionContext extractionContext, TableExport tableExport, Predicate<SubsetItem> globalPredicate) {
        return toCellConverter(bdfServer, extractionContext, tableExport, globalPredicate, true);
    }

    public static SumCellConverter toCellConverter(BdfServer bdfServer, ExtractionContext extractionContext, TableExport tableExport, Predicate<SubsetItem> globalPredicate, boolean withLangContextCheck) {
        if (withLangContextCheck) {
            extractionContext = BdfServerUtils.checkLangMode(extractionContext, bdfServer, tableExport.getTableExportDef());
        }
        CellConverterProvider cellConverterProvider = CellConverterProviderFactory.newInstance(bdfServer, extractionContext, globalPredicate, withLangContextCheck);
        SumCellConverter cellConverter = SumCellConverterFactory.newInstance(tableExport.getSubsetTableList(), bdfServer.getTableExportContext(), extractionContext, cellConverterProvider, globalPredicate);
        return cellConverter;
    }

    public static SumCellConverter getCellConverterFromName(BdfServer bdfServer, ExtractionContext extractionContext, String tableExportName) {
        return getCellConverterFromName(bdfServer, extractionContext, tableExportName, null, true);
    }

    public static SumCellConverter getCellConverterFromName(BdfServer bdfServer, ExtractionContext extractionContext, String tableExportName, Predicate<SubsetItem> globalPredicate) {
        return getCellConverterFromName(bdfServer, extractionContext, tableExportName, globalPredicate, true);
    }

    public static SumCellConverter getCellConverterFromName(BdfServer bdfServer, ExtractionContext extractionContext, String tableExportName, Predicate<SubsetItem> globalPredicate, boolean withLangContextCheck) {
        TableExport tableExport = bdfServer.getTableExportManager().getTableExport(tableExportName);
        if (tableExport == null) {
            return null;
        }
        return toCellConverter(bdfServer, extractionContext, tableExport, globalPredicate, withLangContextCheck);
    }

    public static SumCellConverter getSpecialTableCellConverter(BdfParameters parameters, SubsetKey contextCorpusKey, String patternMode, @Nullable Corpus corpus) {
        TableUiComponentHandler handler = new TableUiComponentHandler(parameters, patternMode, contextCorpusKey);
        return handler.toCellConverter(corpus);
    }

    public static SumCellConverter getComponentsCellConverter(BdfParameters parameters, List<String> componentNameList, String patternMode, @Nullable Corpus corpus) {
        SelectionUiComponentHandler handler = new SelectionUiComponentHandler(parameters, patternMode, componentNameList);
        return handler.toCellConverter(corpus);
    }


    private static abstract class UiComponentHandler {

        final BdfParameters parameters;
        final String patternMode;

        UiComponentHandler(BdfParameters parameters, String patternMode) {
            this.parameters = parameters;
            this.patternMode = patternMode;
        }

        abstract List<UiComponent> getUiComponent(Corpus corpus);

        SumCellConverter toCellConverter(Corpus corpus) {
            BdfServer bdfServer = parameters.getBdfServer();
            PermissionSummary permissionSummary = parameters.getPermissionSummary();
            if (corpus != null) {
                if (!permissionSummary.hasAccess(corpus)) {
                    return TableExportUtils.EMPTY_SUMCELLCONVERTER;
                }
                SubsetTable subsetTable = toSubsetTable(corpus);
                return BdfTableExportUtils.toCellConverter(bdfServer, parameters.getDefaultExtractionContext(), subsetTable);
            } else {
                TableExportBuilder tableExportBuilder = TableExportBuilder.init();
                for (Corpus crp : bdfServer.getFichotheque().getCorpusList()) {
                    if (!permissionSummary.hasAccess(crp)) {
                        continue;
                    }
                    tableExportBuilder.addSubsetTable(toSubsetTable(crp));
                }
                return BdfTableExportUtils.toCellConverter(bdfServer, parameters.getDefaultExtractionContext(), tableExportBuilder.toTableExport());
            }

        }

        private SubsetTable toSubsetTable(Corpus corpus) {
            List<UiComponent> uiComponentList = getUiComponent(corpus);
            TableDef tableDef = DefaultTableDefFactory.fromComponentList(parameters.getBdfServer(), corpus, uiComponentList, patternMode, parameters.getPermissionSummary());
            return SubsetTableBuilder.init(corpus)
                    .populate(tableDef, parameters.getBdfServer().getTableExportContext())
                    .toSubsetTable();
        }

    }


    private static class TableUiComponentHandler extends UiComponentHandler {

        private final SubsetKey contextCorpusKey;

        TableUiComponentHandler(BdfParameters parameters, String mode, SubsetKey contextCorpusKey) {
            super(parameters, mode);
            this.contextCorpusKey = contextCorpusKey;
        }

        @Override
        List<UiComponent> getUiComponent(Corpus corpus) {
            return UiUtils.filterFicheTableUiComponents(parameters.getBdfServer().getUiManager().getMainUiComponents(corpus), contextCorpusKey);

        }

    }


    private static class SelectionUiComponentHandler extends UiComponentHandler {

        private final List<String> componentNameList;

        SelectionUiComponentHandler(BdfParameters parameters, String mode, List<String> componentNameList) {
            super(parameters, mode);
            this.componentNameList = componentNameList;
        }

        @Override
        List<UiComponent> getUiComponent(Corpus corpus) {
            List<UiComponent> result = new ArrayList<UiComponent>();
            UiComponents uiComponents = parameters.getBdfServer().getUiManager().getMainUiComponents(corpus);
            for (String componentName : componentNameList) {
                UiComponent uiComponent = uiComponents.getUiComponent(componentName);
                if (uiComponent != null) {
                    result.add(uiComponent);
                }
            }
            return result;
        }


    }

}
