"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LayoutModule = void 0;
const tslib_1 = require("tslib");
const AdaptableModuleBase_1 = require("./AdaptableModuleBase");
const ModuleConstants = tslib_1.__importStar(require("../Utilities/Constants/ModuleConstants"));
const LayoutRedux = tslib_1.__importStar(require("../Redux/ActionsReducers/LayoutRedux"));
const ArrayExtensions_1 = tslib_1.__importDefault(require("../Utilities/Extensions/ArrayExtensions"));
const LayoutRadioSelector_1 = require("../View/Layout/LayoutRadioSelector");
const LayoutStatusBarSubPanelPopover_1 = require("../View/Layout/LayoutStatusBarSubPanelPopover");
const EditCurrentLayoutButton_1 = require("../View/Layout/EditCurrentLayoutButton");
const LayoutCloneButton_1 = require("../View/Layout/LayoutCloneButton");
const SaveLayoutButton_1 = require("../View/Layout/SaveLayoutButton");
const LayoutWizard_1 = require("../View/Layout/Wizard/LayoutWizard");
const getLayoutFilterViewItems_1 = require("./Utilities/Layout/getLayoutFilterViewItems");
const getLayoutSortViewItems_1 = require("./Utilities/Layout/getLayoutSortViewItems");
const AggregationColumns_1 = require("../PredefinedConfig/Common/AggregationColumns");
const windowFactory_1 = require("../View/Components/Popups/WindowPopups/windowFactory");
const flattenDeep_1 = tslib_1.__importDefault(require("lodash/flattenDeep"));
const StringExtensions_1 = tslib_1.__importDefault(require("../Utilities/Extensions/StringExtensions"));
const getGridFilterPreview_1 = require("../View/Layout/Wizard/getGridFilterPreview");
const RowSummaryService_1 = require("../Utilities/Services/RowSummaryService");
class LayoutModule extends AdaptableModuleBase_1.AdaptableModuleBase {
    constructor(api) {
        super(ModuleConstants.LayoutModuleId, ModuleConstants.LayoutFriendlyName, 'grid', 'LayoutPopup', 'Named sets of column visibility, order, groupings, aggregation, pivots etc.', api);
        this.rowSummaryService = new RowSummaryService_1.RowSummaryService(this.api);
    }
    onAdaptableReady() {
        this.rowSummaryService.onAdapterReady();
        this.api.eventApi.on('LayoutChanged', (layoutChangedInfo) => {
            var _a;
            if (layoutChangedInfo.newLayoutState.CurrentLayout !==
                ((_a = layoutChangedInfo.oldLayoutState) === null || _a === void 0 ? void 0 : _a.CurrentLayout)) {
                // we are interested only if current layout was changed (is different from the previous one)
                this.handleLayoutChange();
            }
        });
        requestAnimationFrame(() => {
            this.api.layoutApi.internalApi.fireLayoutChangedEvent('ADAPTABLE_READY', null, this.api.layoutApi.getLayoutState());
        });
    }
    getModuleAdaptableObjects() {
        return this.api.layoutApi.getLayouts();
    }
    getExplicitlyReferencedColumnIds(layout) {
        const columnIds = [];
        columnIds.push(...layout.Columns);
        if (layout.AggregationColumns) {
            columnIds.push(...Object.keys(layout.AggregationColumns));
        }
        if (layout.PivotColumns) {
            columnIds.push(...layout.PivotColumns);
        }
        if (layout.RowGroupedColumns) {
            columnIds.push(...layout.RowGroupedColumns);
        }
        return Array.from(new Set(columnIds));
    }
    getTeamSharingReferences(adaptableObject) {
        const teamSharingReferences = super.getTeamSharingReferences(adaptableObject);
        const layoutName = adaptableObject.Name;
        if (this.api.layoutApi.internalApi.hasLayoutSpecificObjects() && !!layoutName) {
            const layoutAssociatedObjectReferences = [];
            const loadConfig = {
                associatedWithLayout: layoutName,
            };
            // we ensured that there are layout specific objects, so all the "getAll*()" api methods will return only the objects available in the current layout
            this.api.alertApi.getAlertDefinitions(loadConfig).forEach((alertDefinition) => layoutAssociatedObjectReferences.push({
                Reference: alertDefinition,
                Module: 'Alert',
            }));
            this.api.customSortApi.getCustomSorts(loadConfig).forEach((customSort) => layoutAssociatedObjectReferences.push({
                Reference: customSort,
                Module: 'CustomSort',
            }));
            this.api.flashingCellApi.getFlashingCellDefinitions(loadConfig).forEach((flashingCell) => layoutAssociatedObjectReferences.push({
                Reference: flashingCell,
                Module: 'FlashingCell',
            }));
            this.api.formatColumnApi.getFormatColumns(loadConfig).forEach((formatColumn) => layoutAssociatedObjectReferences.push({
                Reference: formatColumn,
                Module: 'FormatColumn',
            }));
            this.api.styledColumnApi.getStyledColumns(loadConfig).forEach((styledcolumn) => layoutAssociatedObjectReferences.push({
                Reference: styledcolumn,
                Module: 'StyledColumn',
            }));
            this.api.plusMinusApi.getAllPlusMinus(loadConfig).forEach((plusMinusNudge) => layoutAssociatedObjectReferences.push({
                Reference: plusMinusNudge,
                Module: 'PlusMinus',
            }));
            this.api.shortcutApi.getShortcuts(loadConfig).forEach((shortcut) => layoutAssociatedObjectReferences.push({
                Reference: shortcut,
                Module: 'Shortcut',
            }));
            [
                ...this.api.scheduleApi.getReportSchedules(loadConfig),
                ...this.api.scheduleApi.getReminderSchedules(loadConfig),
                ...this.api.scheduleApi.getIPushPullSchedules(loadConfig),
                ...this.api.scheduleApi.getOpenFinSchedules(loadConfig),
            ].forEach((schedule) => layoutAssociatedObjectReferences.push({
                Reference: schedule,
                Module: 'Schedule',
            }));
            teamSharingReferences.push(...layoutAssociatedObjectReferences);
        }
        return teamSharingReferences;
    }
    hasNamedQueryReferences() {
        return true;
    }
    createColumnMenuItems(column) {
        var _a, _b;
        if (!this.isModuleEditable()) {
            return;
        }
        let returnColumnMenuItems = [];
        const isReadOnlyLayout = this.api.layoutApi.isCurrentLayoutReadOnly();
        if (!isReadOnlyLayout) {
            returnColumnMenuItems.push(this.createMenuItemShowPopup('layout-edit', 'Edit Layout', this.moduleInfo.Popup, 'edit-table', {
                action: 'Edit',
                source: 'ColumnMenu',
                value: this.api.layoutApi.getCurrentLayout(),
            }));
            if (column) {
                returnColumnMenuItems.push(this.createMenuItemClickFunction('layout-column-caption-change', 'Change Caption', 'edit', () => this.api.layoutApi.showChangeColumnCaption(column)));
            }
        }
        if (column) {
            if (column.hideable) {
                returnColumnMenuItems.push(this.createMenuItemClickFunction('layout-column-hide', 'Hide Column', 'visibility-off-bold', () => {
                    this.api.columnApi.hideColumn(column.columnId);
                }));
            }
            const hasExistingSelection = (_b = (_a = this.api.gridApi.getSelectedCellInfo()) === null || _a === void 0 ? void 0 : _a.gridCells) === null || _b === void 0 ? void 0 : _b.length;
            if (hasExistingSelection) {
                returnColumnMenuItems.push(this.createMenuItemClickFunction('layout-column-select-preserve', 'Select Column (Preserve Selection)', 'select-fwd', () => {
                    this.api.columnApi.addColumnToSelection(column.columnId);
                }));
                returnColumnMenuItems.push(this.createMenuItemClickFunction('layout-column-select-reset', 'Select Column (Reset Selection)', 'tab-unselected', () => {
                    this.api.columnApi.selectColumn(column.columnId);
                }));
            }
            else {
                returnColumnMenuItems.push(this.createMenuItemClickFunction('layout-column-select', 'Select Column', 'tab-unselected', () => {
                    this.api.columnApi.selectColumn(column.columnId);
                }));
            }
        }
        returnColumnMenuItems.push(this.createMenuItemClickFunction('layout-grid-select', 'Select Grid', 'select-all', () => {
            this.api.gridApi.selectAll();
        }));
        return returnColumnMenuItems;
    }
    createContextMenuItems(menuContext) {
        let returnColumnMenuItems = [];
        if (this.isModuleEditable() && !this.api.layoutApi.isCurrentLayoutReadOnly()) {
            returnColumnMenuItems.push(this.createMenuItemShowPopup('layout-edit', 'Edit Layout', this.moduleInfo.Popup, 'edit-table', {
                action: 'Edit',
                source: 'ColumnMenu',
            }));
        }
        if ((menuContext.selectedCellInfo &&
            ArrayExtensions_1.default.IsNotNullOrEmpty(menuContext.selectedCellInfo.columns)) ||
            (menuContext.selectedRowInfo &&
                ArrayExtensions_1.default.IsNotNullOrEmpty(menuContext.selectedRowInfo.gridRows))) {
            returnColumnMenuItems.push(this.createMenuItemClickFunction('layout-clear-selection', 'Clear Selected Cells', 'select-off', () => {
                this.api.gridApi.deselectAll();
            }));
        }
        returnColumnMenuItems.push(this.createMenuItemClickFunction('layout-select-all', 'Select Grid', 'select-all', () => {
            this.api.gridApi.selectAll();
        }));
        returnColumnMenuItems.push(this.createMenuItemClickFunction('layout-auto-size', 'Auto Size', 'arrow-expand', () => {
            this.api.columnApi.autosizeAllColumns();
        }));
        const viewPivotItemsMenuItem = this.createViewPivotItemsMenuItem(menuContext);
        if (viewPivotItemsMenuItem) {
            returnColumnMenuItems.push(viewPivotItemsMenuItem);
        }
        return returnColumnMenuItems;
    }
    // TODO next time this method is touched, it should be extracted in an internal Api
    createViewPivotItemsMenuItem(menuContext) {
        // current group => menuContext.rowNode.field;
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
        const selectedCellInfo = (_a = menuContext.selectedCellInfo) !== null && _a !== void 0 ? _a : this.api.gridApi.getSelectedCellInfo();
        if (((_b = selectedCellInfo === null || selectedCellInfo === void 0 ? void 0 : selectedCellInfo.gridCells) === null || _b === void 0 ? void 0 : _b.length) !== 1) {
            return;
        }
        const gridCell = (_c = menuContext.gridCell) !== null && _c !== void 0 ? _c : selectedCellInfo.gridCells[0];
        const currentLayout = this.api.layoutApi.getCurrentLayout();
        if (!currentLayout.EnablePivot) {
            return;
        }
        const { agGridColumn } = menuContext;
        const columnId = agGridColumn.getColId();
        const isPivotColumn = this.api.columnApi.isAutoPivotColumn(columnId);
        if (!isPivotColumn && this.api.columnApi.getColumnDataTypeForColumnId(columnId) !== 'Number') {
            return;
        }
        /**
         * Cannot base the values on the pivot column id, because the value or the field may have underscrores
         *
         *
         * e.g. pivot_license_MIT License_stargazers_count
         */
        // pivot_status_Booked_price
        // price
        const aggColumn = (_g = (_f = (_e = (_d = agGridColumn === null || agGridColumn === void 0 ? void 0 : agGridColumn.getColDef) === null || _d === void 0 ? void 0 : _d.call(agGridColumn).pivotValueColumn) === null || _e === void 0 ? void 0 : _e.getColDef) === null || _f === void 0 ? void 0 : _f.call(_e)) === null || _g === void 0 ? void 0 : _g.field;
        // Booked
        const pivotValue = (_k = (_j = (_h = agGridColumn === null || agGridColumn === void 0 ? void 0 : agGridColumn.getColDef) === null || _h === void 0 ? void 0 : _h.call(agGridColumn)) === null || _j === void 0 ? void 0 : _j.pivotKeys) === null || _k === void 0 ? void 0 : _k[0];
        // status - the preview works only with one column
        const pivotColumnId = (_l = currentLayout === null || currentLayout === void 0 ? void 0 : currentLayout.PivotColumns) === null || _l === void 0 ? void 0 : _l[0];
        function getData(rows) {
            return [
                ...rows.map((row) => {
                    if (row.childrenAfterFilter) {
                        return getData(row.childrenAfterFilter);
                    }
                    return row.data;
                }),
            ];
        }
        const data = (0, flattenDeep_1.default)(getData(menuContext.rowNode.childrenAfterFilter));
        const rowGroups = currentLayout.RowGroupedColumns;
        const cellValue = isPivotColumn
            ? (_o = (_m = menuContext.rowNode) === null || _m === void 0 ? void 0 : _m.aggData) === null || _o === void 0 ? void 0 : _o[columnId]
            : gridCell.displayValue;
        const popupProps = {
            hasPivotValue: isPivotColumn,
            columnId,
            rowGroups,
            rows: data,
            layout: currentLayout,
            aggColumn,
            pivotValue,
            pivotColumnId,
        };
        return {
            name: 'layout-aggregated-view',
            module: this.moduleInfo.ModuleName,
            isVisible: true,
            label: 'Expand Aggregated Value',
            onClick: () => {
                this.api.internalApi.showPopupWindow({
                    // force only one window instance opened
                    id: windowFactory_1.SHOW_PIVOT_COLUMN_DETAILS,
                    factoryId: windowFactory_1.SHOW_PIVOT_COLUMN_DETAILS,
                    title: `Rows for Aggregated Value: ${cellValue}`,
                    icon: undefined,
                    popupProps,
                });
            },
            icon: {
                name: 'arrow-expand',
            },
        };
    }
    getTeamSharingAction() {
        return {
            ModuleEntities: this.api.layoutApi.getLayouts(),
            AddAction: LayoutRedux.LayoutAdd,
            EditAction: LayoutRedux.LayoutSave,
        };
    }
    toViewAll() {
        return this.getModuleAdaptableObjects().map((layout) => this.toView(layout));
    }
    toView(layout) {
        var _a, _b, _c, _d, _e, _f, _g;
        const maxColumnsToDisplay = (_b = (_a = this.api.optionsApi.getLayoutOptions().layoutViewOptions) === null || _a === void 0 ? void 0 : _a.maxColumnsToDisplay) !== null && _b !== void 0 ? _b : 10;
        const columnIdToFriendlyName = (columnId) => {
            return this.api.columnApi.getFriendlyNameForColumnId(columnId);
        };
        let columns = layout.Columns.filter((c) => !this.api.columnApi.isAutoRowGroupColumn(c)).filter((c) => !this.api.columnApi.isAutoPivotColumn(c));
        if (columns.length >
            maxColumnsToDisplay + 1 /* +1 is to show tag only beginning with 2, 'other 2' */) {
            const extraColumns = columns.length - maxColumnsToDisplay;
            const firstNColumns = columns
                .slice(0, maxColumnsToDisplay)
                .map((column) => columnIdToFriendlyName(column));
            columns = [...firstNColumns, `and ${extraColumns} more`];
        }
        else {
            columns = columns.map((column) => columnIdToFriendlyName(column));
        }
        return {
            items: [
                {
                    name: 'Name',
                    values: [layout.Name],
                },
                {
                    name: 'Layout Grid Type',
                    values: [(layout === null || layout === void 0 ? void 0 : layout.EnablePivot) ? 'Pivot' : 'Table'],
                },
                /**
                 * Hide pivot columns.
                 *
                 * The generated pivot columns cannot be prevented from beeing on the layout object.
                 * When they are removed/not added, they no longer apear in the grid.
                 */
                !layout.EnablePivot && {
                    name: 'Columns',
                    values: columns,
                },
                ((_c = layout.ColumnSorts) === null || _c === void 0 ? void 0 : _c.length) && (0, getLayoutSortViewItems_1.getLayoutSortViewItems)(layout, this.api),
                ((_d = layout === null || layout === void 0 ? void 0 : layout.ColumnFilters) === null || _d === void 0 ? void 0 : _d.length) && (0, getLayoutFilterViewItems_1.getLayoutFilterViewItems)(layout, this.api),
                ((_e = layout === null || layout === void 0 ? void 0 : layout.RowGroupedColumns) === null || _e === void 0 ? void 0 : _e.length) && {
                    name: 'Grouped Columns',
                    values: layout.RowGroupedColumns.map((colId) => columnIdToFriendlyName(colId)),
                },
                ((_f = layout === null || layout === void 0 ? void 0 : layout.PivotColumns) === null || _f === void 0 ? void 0 : _f.length) && {
                    name: 'Pivot Columns',
                    values: layout.PivotColumns.map((colId) => columnIdToFriendlyName(colId)),
                },
                (layout === null || layout === void 0 ? void 0 : layout.AggregationColumns) &&
                    Object.keys(layout === null || layout === void 0 ? void 0 : layout.AggregationColumns).length && {
                    name: 'Aggregation Columns',
                    values: Object.entries(layout === null || layout === void 0 ? void 0 : layout.AggregationColumns)
                        .map(([colId, aggFn]) => {
                        if (colId === 'Source' || colId === 'Uuid') {
                            return '';
                        }
                        let aggFnName = '';
                        if (typeof aggFn === 'string') {
                            aggFnName = aggFn;
                        }
                        else if (typeof aggFn === 'object' && aggFn.type === 'weightedAverage') {
                            aggFnName = AggregationColumns_1.WEIGHTED_AVERAGE_AGG_FN_NAME;
                        }
                        return `${aggFnName}(${columnIdToFriendlyName(colId)})`;
                    })
                        .filter(Boolean),
                },
                (layout === null || layout === void 0 ? void 0 : layout.GridFilter) &&
                    StringExtensions_1.default.IsNotNullOrEmpty(layout.GridFilter.Expression) &&
                    (0, getGridFilterPreview_1.getGridFilterViewItems)(layout),
                ((_g = layout === null || layout === void 0 ? void 0 : layout.RowSummaries) === null || _g === void 0 ? void 0 : _g.length) && {
                    name: 'Row Summaries',
                    values: layout === null || layout === void 0 ? void 0 : layout.RowSummaries.map((rowSummary) => {
                        var _a;
                        const columns = Object.entries((_a = rowSummary.ColumnsMap) !== null && _a !== void 0 ? _a : {})
                            .map(([columnId, expression]) => {
                            if (columnId === 'Source' || columnId === 'Uuid') {
                                return '';
                            }
                            return `${expression}(${columnIdToFriendlyName(columnId)})`;
                        })
                            .filter(Boolean)
                            .join(', ');
                        return `${rowSummary.Position}: ${columns}`;
                    }),
                },
            ].filter(Boolean),
            abObject: layout,
        };
    }
    getViewProperties() {
        return {
            actions: [LayoutRadioSelector_1.LayoutRadioSelector, LayoutCloneButton_1.LayoutCloneButton],
            getDeleteAction: (layout) => {
                // make sure we do not delete the last layout
                if (this.getModuleAdaptableObjects().length === 1) {
                    return null;
                }
                return LayoutRedux.LayoutDelete(layout);
            },
            getEditWizard: () => LayoutWizard_1.LayoutWizard,
            getStatusBarPanelProps: () => {
                return {
                    content: LayoutStatusBarSubPanelPopover_1.LayoutStatusbar,
                    extraActions: [EditCurrentLayoutButton_1.EditCurrentLayoutButton, SaveLayoutButton_1.SaveLayoutButton],
                };
            },
        };
    }
    handleLayoutChange() {
        if (!this.api.layoutApi.internalApi.hasLayoutSpecificObjects()) {
            // no need if no callback implementation is provided or no auto checking
            return;
        }
        // PlusMinus
        this.api.internalApi
            .getModuleService()
            .getModuleById('PlusMinus')
            .checkListenToKeyDown();
        // Shortcut
        this.api.internalApi
            .getModuleService()
            .getModuleById('Shortcut')
            .checkListenToKeyDown();
        // Schedule
        this.api.internalApi
            .getModuleService()
            .getModuleById('Schedule')
            .setUpScheduleJobs();
        // CustomSort, FlashingCell, FormatColumn, StyledColumn
        // we need to re-setup the column defs, as some colDefs properties may be changed
        this.api.internalApi
            .getAdaptableInstance()
            .updateColumnModelAndRefreshGrid({ skipColDefsRefresh: true });
    }
    getReferencedNamedQueryNames(layout) {
        var _a;
        if (!((_a = layout.GridFilter) === null || _a === void 0 ? void 0 : _a.Expression)) {
            return [];
        }
        return this.api.namedQueryApi.internalApi.getReferencedNamedQueryNames(layout.GridFilter.Expression);
    }
}
exports.LayoutModule = LayoutModule;
