"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExportModule = void 0;
const tslib_1 = require("tslib");
const AdaptableModuleBase_1 = require("./AdaptableModuleBase");
const ModuleConstants = tslib_1.__importStar(require("../Utilities/Constants/ModuleConstants"));
const Enums_1 = require("../PredefinedConfig/Common/Enums");
const Helper_1 = require("../Utilities/Helpers/Helper");
const ExportRedux = tslib_1.__importStar(require("../Redux/ActionsReducers/ExportRedux"));
const GeneralConstants_1 = require("../Utilities/Constants/GeneralConstants");
const ArrayExtensions_1 = tslib_1.__importDefault(require("../Utilities/Extensions/ArrayExtensions"));
const StringExtensions_1 = tslib_1.__importDefault(require("../Utilities/Extensions/StringExtensions"));
const PopupRedux = tslib_1.__importStar(require("../Redux/ActionsReducers/PopupRedux"));
const ObjectFactory_1 = require("../Utilities/ObjectFactory");
const NewReportWizard_1 = require("../View/Export/Wizard/NewReportWizard");
const getExportColumnsViewItems_1 = require("./Utilities/Export/getExportColumnsViewItems");
const getExportRowsViewItems_1 = require("./Utilities/Export/getExportRowsViewItems");
const ReportExportDropdown_1 = require("../View/Export/ReportExportDropdown");
const getObjectTagsViewItems_1 = require("./Utilities/getObjectTagsViewItems");
const ExportSelector_1 = require("../View/Export/ExportSelector");
const SystemRedux_1 = require("../Redux/ActionsReducers/SystemRedux");
const windowFactory_1 = require("../View/Components/Popups/WindowPopups/windowFactory");
const Uuid_1 = require("../PredefinedConfig/Uuid");
const waitForTimeout_1 = require("../Utilities/waitForTimeout");
class ExportModule extends AdaptableModuleBase_1.AdaptableModuleBase {
    constructor(api) {
        super(ModuleConstants.ExportModuleId, ModuleConstants.ExportFriendlyName, 'export-data', 'ExportPopup', 'Export data from the Grid to numerous locations in numerous formatso', api);
    }
    getModuleAdaptableObjects() {
        return this.api.exportApi.getReports();
    }
    getExplicitlyReferencedColumnIds(report) {
        if (report.ReportColumnScope === 'ScopeColumns' &&
            this.api.columnScopeApi.scopeHasColumns(report.Scope)) {
            return this.api.columnScopeApi
                .getColumnsForScope(report.Scope)
                .map((adaptableColumn) => adaptableColumn.columnId);
        }
        return [];
    }
    getReferencedNamedQueryNames(report) {
        if (!report.Query) {
            return [];
        }
        return this.api.namedQueryApi.internalApi.getReferencedNamedQueryNames(report.Query.BooleanExpression);
    }
    createContextMenuItems(menuContext) {
        const canExport = !menuContext.isRowGroupColumn && this.isModuleAvailable();
        if (!canExport) {
            return;
        }
        let returnMenuItems = [];
        const availableSystemReports = this.api.exportApi.getAvailableSystemReports();
        if (availableSystemReports.includes(GeneralConstants_1.VISUAL_DATA_REPORT)) {
            returnMenuItems.push(this.createMenuItemClickFunction('export-visual-data-excel', 'Excel', 'excel', () => this.export(this.api.exportApi.getReportByName(GeneralConstants_1.VISUAL_DATA_REPORT), Enums_1.ExportDestination.Excel)));
        }
        if (availableSystemReports.includes(GeneralConstants_1.ALL_DATA_REPORT)) {
            const allDataReport = this.api.exportApi.getReportByName(GeneralConstants_1.ALL_DATA_REPORT);
            returnMenuItems.push(...this.buildReportMenuItems(allDataReport));
        }
        if (availableSystemReports.includes(GeneralConstants_1.CURRENT_DATA_REPORT)) {
            const currentDataReport = this.api.exportApi.getReportByName(GeneralConstants_1.CURRENT_DATA_REPORT);
            returnMenuItems.push(...this.buildReportMenuItems(currentDataReport));
        }
        const canExportCells = availableSystemReports.includes(GeneralConstants_1.SELECTED_CELLS_REPORT) &&
            menuContext.selectedCellInfo &&
            ArrayExtensions_1.default.IsNotNullOrEmpty(menuContext.selectedCellInfo.columns) &&
            ArrayExtensions_1.default.IsNotNullOrEmpty(menuContext.selectedCellInfo.gridCells);
        if (canExportCells) {
            const selectedCellReport = this.api.exportApi.getReportByName(GeneralConstants_1.SELECTED_CELLS_REPORT);
            returnMenuItems.push(...this.buildReportMenuItems(selectedCellReport));
        }
        const canExportRows = availableSystemReports.includes(GeneralConstants_1.SELECTED_ROWS_REPORT) &&
            menuContext.selectedRowInfo &&
            ArrayExtensions_1.default.IsNotNullOrEmpty(menuContext.selectedRowInfo.gridRows) &&
            menuContext.gridCell &&
            menuContext.gridCell.primaryKeyValue &&
            menuContext.isSelectedRow;
        if (canExportRows) {
            const selectedRowReport = this.api.exportApi.getReportByName(GeneralConstants_1.SELECTED_ROWS_REPORT);
            returnMenuItems.push(...this.buildReportMenuItems(selectedRowReport));
        }
        return returnMenuItems;
    }
    buildReportMenuItems(report) {
        // a bit convoluted, but ce la vie, that's what happens when you use enums instead of union types
        // convert to lowercase and replace empty spaces with hyphens
        const adjustName = (name = '') => {
            const result = name.replace(/ /g, '-');
            return result.toLowerCase();
        };
        const getMenuItemName = (reportName, destination) => {
            return `export-${adjustName(reportName)}-${adjustName(destination)}`;
        };
        const getMenuItemIcon = (exportDestination) => {
            // once we have icons for csv, clipboard etc then i would like to add them here one by one and use moduleinfo for custom
            switch (exportDestination) {
                case Enums_1.ExportDestination.Excel:
                    return 'excel';
                case Enums_1.ExportDestination.Clipboard:
                    return 'clipboard';
                case Enums_1.ExportDestination.CSV:
                    return 'csv';
                case Enums_1.ExportDestination.JSON:
                    return 'json';
                case Enums_1.ExportDestination.Table:
                    return 'grid';
            }
            return this.moduleInfo.Glyph;
        };
        const menuItems = [];
        for (const destination of this.api.exportApi.getAvailableExportDestinations()) {
            menuItems.push(this.createMenuItemClickFunction(getMenuItemName(report.Name, destination), destination, getMenuItemIcon(destination), //  'filter', //  this.moduleInfo.Glyph,
            () => this.export(report, destination)));
        }
        for (const customDestination of this.api.exportApi.getCustomDestinations()) {
            menuItems.push(this.createMenuItemClickFunction(getMenuItemName(report.Name, customDestination.name), customDestination.name, this.moduleInfo.Glyph, () => this.export(report, customDestination.name)));
        }
        return menuItems;
    }
    async export(report, exportDestination) {
        var _a;
        const cleanupExportProcess = () => {
            this.api.internalApi.dispatchReduxAction((0, SystemRedux_1.SystemVisualExportEnd)());
            this.api.userInterfaceApi.hideProgressIndicator();
        };
        if (report.Name === GeneralConstants_1.VISUAL_DATA_REPORT) {
            this.api.internalApi.dispatchReduxAction((0, SystemRedux_1.SystemVisualExportBegin)());
        }
        this.api.userInterfaceApi.showProgressIndicator({
            text: `${report.Name} Export in progress...`,
        });
        try {
            // waitForTimeout required to give the ProgressIndicator rendering a head-start (see rAF in ProgressIndicator implementation)
            await (0, waitForTimeout_1.waitForTimeout)(16);
            if (report.Name === GeneralConstants_1.VISUAL_DATA_REPORT) {
                this.api.logInfo(`Export ${report.Name} (${exportDestination})`);
                this.api.exportApi.exportVisualDataToExcel();
                // WYSIWYG is fully delegated to the AG Grid excel export, so we don't need to do anything else
                cleanupExportProcess();
                return;
            }
            const preProcessedExport = await this.preProcessExport(report);
            let reportData;
            if (preProcessedExport === false) {
                this.api.logInfo(`Export ${report.Name} (${exportDestination}) cancelled by preProcessExport()`);
                cleanupExportProcess();
                return;
            }
            else if (preProcessedExport === true) {
                this.api.logInfo(`Export ${report.Name} (${exportDestination}) using data from the grid`);
                reportData = this.api.exportApi.internalApi.getReportData(report);
            }
            else if ((preProcessedExport === null || preProcessedExport === void 0 ? void 0 : preProcessedExport.rows) == undefined ||
                (preProcessedExport === null || preProcessedExport === void 0 ? void 0 : preProcessedExport.columns) == undefined) {
                this.api.logWarn(`Export ${report.Name} (${exportDestination}) : preProcessExport() returned an invalid ReportData object, fallback to data from the grid`);
                reportData = this.api.exportApi.internalApi.getReportData(report);
            }
            else {
                this.api.logInfo(`Export ${report.Name} (${exportDestination}) using data from preProcessExport()`);
                reportData = preProcessedExport;
                if (!reportData.columns.length) {
                    // an empty column array means that all columns have been exported
                    // we have to update the report to reflect this
                    reportData.columns = this.api.exportApi.internalApi.getReportDataColumns(report);
                }
            }
            if (this.isCustomDestination(exportDestination)) {
                const customDestination = (_a = this.api.optionsApi
                    .getAdaptableOptions()
                    .exportOptions.customDestinations) === null || _a === void 0 ? void 0 : _a.find((cd) => cd.name == exportDestination);
                if (customDestination === null || customDestination === void 0 ? void 0 : customDestination.form) {
                    this.api.internalApi.dispatchReduxAction(PopupRedux.PopupShowForm({
                        Id: 'export-destination-form',
                        Form: customDestination === null || customDestination === void 0 ? void 0 : customDestination.form,
                        prepareContext: (context) => {
                            // we want to give the current popup time to close
                            // and we reopen with a delay in case this button action causes another popup
                            return new Promise((resolve) => {
                                setTimeout(() => {
                                    const preparedContext = Object.assign(Object.assign({}, context), { report,
                                        customDestination,
                                        reportData });
                                    resolve(preparedContext);
                                }, 20);
                            });
                        },
                    }));
                }
                else if (customDestination) {
                    const reportContext = Object.assign({ report: report, reportData }, this.api.internalApi.buildBaseContext());
                    customDestination.onExport(reportContext);
                }
            }
            else {
                switch (exportDestination) {
                    case Enums_1.ExportDestination.Excel:
                        this.convertReportToExcel(report, reportData);
                        break;
                    case Enums_1.ExportDestination.Clipboard:
                        this.copyToClipboard(reportData);
                        break;
                    case Enums_1.ExportDestination.CSV:
                        this.convertReportToCsv(report, reportData);
                        break;
                    case Enums_1.ExportDestination.JSON:
                        this.convertReportToJSON(report, reportData);
                        break;
                    case Enums_1.ExportDestination.Table:
                        this.openReportInTablePopup(report, reportData);
                        break;
                }
            }
            cleanupExportProcess();
        }
        catch (e) {
            this.api.consoleError(`Error while exporting ${report.Name}}`, e);
            cleanupExportProcess();
        }
    }
    async preProcessExport(report) {
        const preProcessExportFn = this.api.optionsApi.getAdaptableOptions().exportOptions.preProcessExport;
        if (preProcessExportFn) {
            this.api.logInfo(`Export ${report.Name} : preProcessExport()`);
            return preProcessExportFn(Object.assign(Object.assign({ report }, this.api.internalApi.buildBaseContext()), { getReportColumns: (includePrimaryKey) => {
                    return this.api.exportApi.internalApi.getReportDataColumns(report, includePrimaryKey);
                }, getReportRowData: (reportColumns, includePrimaryKey) => {
                    return this.api.exportApi.internalApi.getReportDataRows(report, reportColumns, includePrimaryKey);
                } }));
        }
        return true;
    }
    isCustomDestination(exportDestination) {
        if (Object.values(Enums_1.ExportDestination).some((val) => val === exportDestination)) {
            return false;
        }
        return this.api.exportApi.isExportDestinationCustom(exportDestination);
    }
    convertReportToJSON(report, reportData) {
        if (this.isEmptyReportData(reportData)) {
            this.showEmptyExportWarning();
            return;
        }
        const jsonContent = JSON.stringify(reportData);
        const jsonFileName = this.api.exportApi.internalApi.getReportFileName(report.Name, 'JSON') + '.json';
        Helper_1.Helper.createDownloadedFile(jsonContent, jsonFileName, 'application/json');
    }
    openReportInTablePopup(report, reportData) {
        if (this.isEmptyReportData(reportData)) {
            this.showEmptyExportWarning();
            return;
        }
        const popupProps = {
            reportData,
        };
        let title = 'Export Table';
        if (report.Name) {
            title = `${title} [${report.Name}]`;
        }
        if (report.Scope) {
            const scopeText = this.api.exportApi.internalApi.getReportColumnScopeShortDescription(report);
            if (scopeText === null || scopeText === void 0 ? void 0 : scopeText.length) {
                title = `${title} ${scopeText.join(',')}`;
            }
        }
        if (report.Query) {
            const queryText = this.api.exportApi.internalApi.getReportExpressionDescription(report, this.api.columnApi.getColumns());
            if (queryText === null || queryText === void 0 ? void 0 : queryText.length) {
                title = `${title} ${queryText}`;
            }
        }
        this.api.internalApi.showPopupWindow({
            // allow to open multiple tables
            id: 'report-table-' + (0, Uuid_1.createUuid)(),
            title: title,
            icon: 'export-data',
            factoryId: windowFactory_1.SHOW_EXPORT_TABLE,
            popupProps,
        });
    }
    convertReportToCsv(report, reportData) {
        const csvContent = this.createCSVContent(reportData);
        if (StringExtensions_1.default.IsNullOrEmpty(csvContent)) {
            this.showEmptyExportWarning();
            return;
        }
        const csvFileName = this.api.exportApi.internalApi.getReportFileName(report.Name, 'CSV') + '.csv';
        Helper_1.Helper.createDownloadedFile(csvContent, csvFileName, 'text/csv;encoding:utf-8');
    }
    convertReportToExcel(report, reportData) {
        if (this.isEmptyReportData(reportData)) {
            this.showEmptyExportWarning();
            return;
        }
        this.api.exportApi.exportDataToExcel(reportData, this.api.exportApi.internalApi.getReportFileName(report.Name, 'Excel'));
    }
    copyToClipboard(reportData) {
        const csvContent = this.createTabularContent(reportData);
        if (StringExtensions_1.default.IsNullOrEmpty(csvContent)) {
            this.showEmptyExportWarning();
            return;
        }
        Helper_1.Helper.copyToClipboard(csvContent);
    }
    createCSVContent(reportData) {
        const reportDataAsArray = this.api.exportApi.internalApi.convertReportDataToArray(reportData);
        return Helper_1.Helper.convertArrayToCsv(reportDataAsArray, ',');
    }
    createTabularContent(reportData) {
        const reportDataAsArray = this.api.exportApi.internalApi.convertReportDataToArray(reportData);
        return Helper_1.Helper.convertArrayToCsv(reportDataAsArray, '\t');
    }
    getTeamSharingAction() {
        return {
            ModuleEntities: this.api.exportApi.getReports(),
            AddAction: ExportRedux.ReportAdd,
            EditAction: ExportRedux.ReportEdit,
        };
    }
    isEmptyReportData(reportData) {
        var _a, _b;
        return !((_a = reportData === null || reportData === void 0 ? void 0 : reportData.rows) === null || _a === void 0 ? void 0 : _a.length) && !((_b = reportData === null || reportData === void 0 ? void 0 : reportData.columns) === null || _b === void 0 ? void 0 : _b.length);
    }
    showEmptyExportWarning() {
        this.api.internalApi.dispatchReduxAction(PopupRedux.PopupShowAlert({
            alertType: 'generic',
            header: 'Export',
            message: 'No Data To Export',
            alertDefinition: ObjectFactory_1.ObjectFactory.CreateInternalAlertDefinitionForMessages('Error'),
        }));
    }
    toView(report) {
        const isSystemReport = this.api.exportApi.internalApi.isSystemReport(report.Name);
        if (isSystemReport) {
            return {
                items: [
                    {
                        name: 'Report',
                        values: [report.Name],
                    },
                    (0, getObjectTagsViewItems_1.getObjectTagsViewItems)(report, this.api),
                ],
                abObject: report,
            };
        }
        return {
            items: [
                {
                    name: 'Report',
                    values: [report.Name],
                },
                (0, getExportColumnsViewItems_1.getExportColumnsViewItems)(report, this.api),
                (0, getExportRowsViewItems_1.getExportRowsViewItems)(report, this.api),
                (0, getObjectTagsViewItems_1.getObjectTagsViewItems)(report, this.api),
            ],
            abObject: report,
        };
    }
    toViewAll() {
        return this.getModuleAdaptableObjects().map((report) => this.toView(report));
    }
    getViewProperties() {
        return {
            newTooltipText: 'Create New Report',
            actions: [ReportExportDropdown_1.ReportExportDropdown],
            getDeleteAction: ExportRedux.ReportDelete,
            getEditWizard() {
                return NewReportWizard_1.NewReportWizard;
            },
            getStatusBarPanelProps: () => {
                return {
                    content: ExportSelector_1.ExportSelector,
                    triggerActionOnWrapperClick: false,
                };
            },
        };
    }
}
exports.ExportModule = ExportModule;
