/* BdfServer_Get - 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.get.instructions.tables;

import fr.exemole.bdfserver.api.BdfServer;
import fr.exemole.bdfserver.api.instruction.BdfParameters;
import fr.exemole.bdfserver.api.managers.TableExportManager;
import fr.exemole.bdfserver.api.users.BdfUser;
import fr.exemole.bdfserver.get.streamproducers.TableExportCsvProducer;
import fr.exemole.bdfserver.get.streamproducers.TableExportHtmlProducer;
import fr.exemole.bdfserver.get.streamproducers.TableExportOdsProducer;
import fr.exemole.bdfserver.tools.exportation.table.BdfTableExportUtils;
import fr.exemole.bdfserver.tools.exportation.table.CellConversionInit;
import fr.exemole.bdfserver.tools.instruction.BdfErrors;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import net.fichotheque.Subset;
import net.fichotheque.SubsetItem;
import net.fichotheque.SubsetKey;
import net.fichotheque.corpus.Corpus;
import net.fichotheque.corpus.Fiches;
import net.fichotheque.exportation.table.SubsetTable;
import net.fichotheque.exportation.table.SumCellConverter;
import net.fichotheque.exportation.table.TableExport;
import net.fichotheque.exportation.table.TableExportConstants;
import net.fichotheque.exportation.table.TableExportContext;
import net.fichotheque.exportation.table.TableExportDef;
import net.fichotheque.extraction.ExtractionContext;
import net.fichotheque.permission.PermissionSummary;
import net.fichotheque.thesaurus.Thesaurus;
import net.fichotheque.tools.exportation.table.TableExportOdsParameters;
import net.fichotheque.utils.CorpusUtils;
import net.fichotheque.utils.FichothequeUtils;
import net.fichotheque.utils.ThesaurusUtils;
import net.mapeadores.util.exceptions.SwitchException;
import net.mapeadores.util.logging.ErrorMessageException;
import net.mapeadores.util.request.RequestMap;
import net.mapeadores.util.servlets.ResponseHandler;
import net.mapeadores.util.servlets.handlers.HtmlResponseHandler;
import net.mapeadores.util.servlets.handlers.StreamResponseHandler;
import net.mapeadores.util.text.FileName;
import net.mapeadores.util.text.StringUtils;


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

    public final static String ECHANTILLON_TYPE = "echantillon";
    public final static String SELECTION_TYPE = "selection";
    private final static String SUBSET_PARAMNAME = "subset";
    private final static String TYPE_PARAMNAME = "type";
    private final static String TABLEEXPORT_PARAMNAME = "tableexport";
    private final static String HEADER_PARAMNAME = "header";
    private final BdfParameters bdfParameters;
    private final BdfServer bdfServer;
    private String type = SELECTION_TYPE;
    private String headerType = TableExportConstants.COLUMNTITLE_HEADER;
    private final SubsetKey subsetKey;
    private String tableExportName;
    private final String extension;
    private boolean fragment;

    private UniqueTableExportEngine(BdfParameters bdfParameters, SubsetKey subsetKey, String extension) {
        this.bdfParameters = bdfParameters;
        this.bdfServer = bdfParameters.getBdfServer();
        this.subsetKey = subsetKey;
        this.extension = extension;
    }

    private void setTableExportName(String tableExportName) {
        this.tableExportName = tableExportName;
    }

    private void setType(String type) {
        this.type = type;
    }

    private void setHeaderType(String headerType) {
        this.headerType = headerType;
    }

    private void setFragment(boolean fragment) {
        this.fragment = fragment;
    }


    public ResponseHandler run() {
        PermissionSummary permissionSummary = bdfParameters.getPermissionSummary();
        TableExportManager tableExportManager = bdfServer.getTableExportManager();
        SubsetTable subsetTable = null;
        TableExportDef tableExportDef = null;
        if (tableExportName != null) {
            TableExport tableExport = tableExportManager.getTableExport(tableExportName);
            if (tableExport != null) {
                tableExportDef = tableExport.getTableExportDef();
                subsetTable = tableExport.getSubsetTable(subsetKey);
            }
        } else {
            Subset subset = bdfServer.getFichotheque().getSubset(subsetKey);
            if (subset != null) {
                subsetTable = BdfTableExportUtils.toDefaultSubsetTable(bdfServer, subset, bdfParameters.getBdfUser().getPrefs().getDefaultFicheTableParameters(), permissionSummary);
            }
        }
        if (subsetTable == null) {
            return null;
        }
        if (!permissionSummary.hasAccess(subsetTable.getSubset())) {
            return null;
        }
        TableExportContext tableExportContext = bdfServer.getTableExportContext();
        Collection<SubsetItem> subsetItems = getSubsetItems();
        ExtractionContext extractionContext = bdfParameters.getDefaultExtractionContext();
        SumCellConverter sumCellConverter = CellConversionInit.subsetTable(bdfServer, extractionContext, subsetTable, tableExportDef).getCellConverter();
        switch (extension) {
            case "csv":
                return StreamResponseHandler.init(new TableExportCsvProducer(null, bdfParameters, subsetTable, subsetItems, headerType, tableExportContext, sumCellConverter));
            case "ods":
                return StreamResponseHandler.init(TableExportOdsProducer.newUniqueInstance(null, bdfParameters, subsetTable, subsetItems,
                        TableExportOdsParameters.init(tableExportContext, bdfParameters.getUserLangContext())
                                .setSumCellConverter(sumCellConverter)
                                .setHeaderType(headerType)));
            default:
                return HtmlResponseHandler.init(new TableExportHtmlProducer(bdfParameters, subsetTable, subsetItems, headerType, fragment, tableExportContext, sumCellConverter));
        }
    }

    public static UniqueTableExportEngine buildFromRequest(BdfParameters bdfParameters, RequestMap requestMap) throws ErrorMessageException {
        String subsetString = requestMap.getParameter(SUBSET_PARAMNAME);
        if (subsetString == null) {
            throw BdfErrors.emptyMandatoryParameter(SUBSET_PARAMNAME);
        }
        SubsetKey subsetKey = parseSubsetKey(SUBSET_PARAMNAME, subsetString);
        UniqueTableExportEngine tableExportEngine = new UniqueTableExportEngine(bdfParameters, subsetKey, "html");
        String tableexportString = requestMap.getParameter(TABLEEXPORT_PARAMNAME);
        if (tableexportString != null) {
            tableExportEngine.setTableExportName(testTableExport(bdfParameters.getBdfServer(), TABLEEXPORT_PARAMNAME, tableexportString));
        }
        initCommonParam(tableExportEngine, requestMap, bdfParameters.getBdfUser());
        tableExportEngine.setFragment(true);
        return tableExportEngine;
    }

    public static UniqueTableExportEngine buildFromPath(BdfParameters bdfParameters, FileName fileName, RequestMap requestMap) throws ErrorMessageException {
        String[] tokens = StringUtils.getTokens(fileName.getBasename(), '-', StringUtils.EMPTY_EXCLUDE);
        int length = tokens.length;
        SubsetKey subsetKey = parseSubsetKey("tables instruction", tokens[0]);
        String extension = fileName.getExtension();
        if (!testExtension(extension)) {
            throw new ErrorMessageException("_ error.unknown.extension", extension);
        }
        UniqueTableExportEngine tableExportEngine = new UniqueTableExportEngine(bdfParameters, subsetKey, extension);
        if (length > 1) {
            String value = tokens[1];
            tableExportEngine.setTableExportName(testTableExport(bdfParameters.getBdfServer(), "-", value));
        }
        initCommonParam(tableExportEngine, requestMap, bdfParameters.getBdfUser());
        return tableExportEngine;
    }

    private static void initCommonParam(UniqueTableExportEngine tableExportEngine, RequestMap requestMap, BdfUser bdfUser) throws ErrorMessageException {
        String typeString = requestMap.getTrimedParameter(TYPE_PARAMNAME);
        if (!typeString.isEmpty()) {
            switch (typeString) {
                case ECHANTILLON_TYPE:
                case SELECTION_TYPE:
                    tableExportEngine.setType(typeString);
                    break;
                default:
                    throw BdfErrors.unknownParameterValue(TYPE_PARAMNAME, typeString);
            }
        }
        String headerType = requestMap.getTrimedParameter(HEADER_PARAMNAME);
        if (!headerType.isEmpty()) {
            try {
                tableExportEngine.setHeaderType(TableExportConstants.checkHeaderType(headerType));
            } catch (IllegalArgumentException iae) {
                throw BdfErrors.unknownParameterValue(HEADER_PARAMNAME, headerType);
            }
        } else {
            tableExportEngine.setHeaderType(bdfUser.getPrefs().getDefaultHeaderType());
        }
    }

    private Collection<SubsetItem> getSubsetItems() {
        if (subsetKey.isCorpusSubset()) {
            Fiches fiches = bdfParameters.getBdfUser().getSelectedFiches();
            List<SubsetItem> ficheMetaList = CorpusUtils.getFicheMetaListByCorpus(fiches, subsetKey);
            if (type.equals(SELECTION_TYPE)) {
                return ficheMetaList;
            } else if (type.equals(ECHANTILLON_TYPE)) {
                if (ficheMetaList.size() > 0) {
                    return reduceList(ficheMetaList);
                } else {
                    Corpus corpus = (Corpus) bdfServer.getFichotheque().getSubset(subsetKey);
                    if (corpus == null) {
                        return FichothequeUtils.EMPTY_SUBSETITEMLIST;
                    } else {
                        return reduceList(corpus.getSubsetItemList());
                    }
                }
            } else {
                throw new SwitchException("Unknown prefix: " + type);
            }
        } else if (subsetKey.isThesaurusSubset()) {
            Thesaurus thesaurus = (Thesaurus) bdfServer.getFichotheque().getSubset(subsetKey);
            if ((thesaurus == null) || (thesaurus.size() == 0)) {
                return FichothequeUtils.EMPTY_SUBSETITEMLIST;
            } else {
                int max = -1;
                if (type.equals(ECHANTILLON_TYPE)) {
                    max = 5;
                }
                return ThesaurusUtils.toSubsetItemList(thesaurus, max);
            }
        }
        throw new SwitchException("Unknown subset: " + subsetKey);
    }

    private static String testTableExport(BdfServer bdfServer, String paramName, String paramValue) throws ErrorMessageException {
        if (paramValue.length() == 0) {
            return null;
        }
        TableExportManager tableExportManager = bdfServer.getTableExportManager();
        if (!tableExportManager.containsTableExport(paramValue)) {
            throw new ErrorMessageException("_ error.unknown.parametervalue", paramName, paramValue);
        }
        return paramValue;
    }

    private static SubsetKey parseSubsetKey(String paramName, String paramValue) throws ErrorMessageException {
        SubsetKey subsetKey;
        try {
            subsetKey = SubsetKey.parse(paramValue);
        } catch (ParseException pe) {
            throw new ErrorMessageException("_ error.wrong.parametervalue", paramName, paramValue);
        }
        if ((!subsetKey.isCorpusSubset()) && (!subsetKey.isThesaurusSubset())) {
            throw new ErrorMessageException("_ error.wrong.parametervalue", paramName, paramValue);
        }
        return subsetKey;
    }

    private static boolean testExtension(String extension) {
        switch (extension) {
            case "html":
            case "csv":
            case "ods":
                return true;
            default:
                return false;
        }
    }

    private static List<SubsetItem> reduceList(List<SubsetItem> origin) {
        if (origin.size() <= 3) {
            return origin;
        }
        List<SubsetItem> result = new ArrayList<SubsetItem>();
        result.add(origin.get(0));
        result.add(origin.get(1));
        result.add(origin.get(2));
        return result;
    }

}
