import { dequal } from 'dequal/lite';
import { SlickEventHandler } from '../core/index.js';
import { ExtensionName } from '../enums/index.js';
import { fetchAsPromise, sortPresetColumns } from './utilities.js';
export class GridStateService {
    constructor(extensionService, filterService, pubSubService, sharedService, sortService, treeDataService, rxjs) {
        this.extensionService = extensionService;
        this.filterService = filterService;
        this.pubSubService = pubSubService;
        this.sharedService = sharedService;
        this.sortService = sortService;
        this.treeDataService = treeDataService;
        this.rxjs = rxjs;
        this.pluginName = 'GridStateService';
        this._columns = [];
        this._subscriptions = [];
        this._selectedRowIndexes = [];
        this._selectedRowDataContextIds = []; // used with row selection
        this._wasRecheckedAfterPageChange = true; // used with row selection & pagination
        this._eventHandler = new SlickEventHandler();
    }
    /** Getter of SlickGrid DataView object */
    get _dataView() {
        return this._grid?.getData() ?? {};
    }
    /** Getter for the Grid Options pulled through the Grid Object */
    get _gridOptions() {
        return this._grid?.getOptions() ?? {};
    }
    /** Getter of the selected data context object IDs */
    get selectedRowDataContextIds() {
        return this._selectedRowDataContextIds;
    }
    /** Setter of the selected data context object IDs */
    set selectedRowDataContextIds(dataContextIds) {
        this._selectedRowDataContextIds = dataContextIds;
    }
    addRxJsResource(rxjs) {
        this.rxjs = rxjs;
    }
    /**
     * Initialize the Service
     * @param grid
     */
    init(grid) {
        this._grid = grid;
        this.subscribeToAllGridChanges(grid);
    }
    /** Dispose of all the SlickGrid & PubSub subscriptions */
    dispose() {
        this._columns = [];
        // unsubscribe all SlickGrid events
        this._eventHandler.unsubscribeAll();
        // also dispose of all Subscriptions
        this.pubSubService.unsubscribeAll(this._subscriptions);
    }
    /**
     * Dynamically change the arrangement/distribution of the columns Positions/Visibilities and optionally Widths.
     * For a column to have its visibly as hidden, it has to be part of the original list but excluded from the list provided as argument to be considered a hidden field.
     * If you are passing columns Width, then you probably don't want to trigger the autosizeColumns (2nd argument to False).
     * We could also resize the columns by their content but be aware that you can only trigger 1 type of resize at a time (either the 2nd argument or the 3rd last argument but not both at same time)
     * The resize by content could be called by the 3rd argument OR simply by enabling `enableAutoResizeColumnsByCellContent` but again this will only get executed when the 2nd argument is set to false.
     * @param {Array<Column>} definedColumns - defined columns
     * @param {Boolean} triggerAutoSizeColumns - True by default, do we also want to call the "autosizeColumns()" method to make the columns fit in the grid?
     * @param {Boolean} triggerColumnsFullResizeByContent - False by default, do we also want to call full columns resize by their content?
     */
    changeColumnsArrangement(definedColumns, triggerAutoSizeColumns = true, triggerColumnsFullResizeByContent = false) {
        if (Array.isArray(definedColumns) && definedColumns.length > 0) {
            const newArrangedColumns = this.getAssociatedGridColumns(this._grid, definedColumns);
            this.updateColumnDefinitionsList(newArrangedColumns, triggerAutoSizeColumns, triggerColumnsFullResizeByContent);
        }
    }
    /** Prepare and load all SlickGrid editors, if an async editor is found then we'll also execute it. */
    loadSlickGridEditors(columns) {
        if (columns.some((col) => `${col.id}`.includes('.'))) {
            console.warn('[Slickgrid-Universal] Make sure that none of your Column Definition "id" property includes a dot in its name because that will cause some problems with the Editors. For example if your column definition "field" property is "user.firstName" then use "firstName" as the column "id".');
        }
        return columns.map((column) => {
            // on every Editor that have a "collectionAsync", resolve the data and assign it to the "collection" property
            if (column?.editor?.collectionAsync) {
                this.loadEditorCollectionAsync(column);
            }
            return { ...column, editorClass: column.editor?.model };
        });
    }
    /**
     *  Syncs plugin/extension columns (e.g., row move, checkbox selector, row detail)
     *  into the provided columns array based on enabled grid options.
     *  @param {Column[]} newColumns - Visible column definitions to update.
     *  @param {Column[]} allColumns - Full column registry (may include plugin columns).
     *  @returns {Column[]} Updated columns array with plugin columns ensured/positioned.
     */
    syncPluginColumns(newColumns, allColumns) {
        // map the Editor model to editorClass and load editor collectionAsync
        newColumns = this.loadSlickGridEditors(newColumns);
        if (Array.isArray(newColumns) && newColumns.length > 0) {
            // make sure that the checkbox selector is still visible in the list when it is enabled
            if (Array.isArray(allColumns)) {
                const dynamicAddonColumnByIndexPositionList = [];
                // make sure that the dynamic columns are included in presets (1.Row Move, 2. Row Selection, 3. Row Detail)
                if (this._gridOptions.enableRowMoveManager) {
                    dynamicAddonColumnByIndexPositionList.push({
                        columnId: this._gridOptions?.rowMoveManager?.columnId ?? '_move',
                        columnIndexPosition: this._gridOptions?.rowMoveManager?.columnIndexPosition ?? 0,
                    });
                }
                if (this._gridOptions.enableCheckboxSelector) {
                    dynamicAddonColumnByIndexPositionList.push({
                        columnId: this._gridOptions?.checkboxSelector?.columnId ?? '_checkbox_selector',
                        columnIndexPosition: this._gridOptions?.checkboxSelector?.columnIndexPosition ?? 0,
                    });
                }
                if (this._gridOptions.enableRowDetailView) {
                    dynamicAddonColumnByIndexPositionList.push({
                        columnId: this._gridOptions?.rowDetailView?.columnId ?? '_detail_selector',
                        columnIndexPosition: this._gridOptions?.rowDetailView?.columnIndexPosition ?? 0,
                    });
                }
                // since some features could have a `columnIndexPosition`, we need to make sure these indexes are respected in the column definitions
                this.addColumnDynamicWhenFeatureEnabled(dynamicAddonColumnByIndexPositionList, allColumns, newColumns);
            }
            // keep copy of the original optional `width` properties optionally provided by the user.
            // We will use this when doing a resize by cell content, if user provided a `width` it won't override it.
            newColumns.forEach((col) => (col.originalWidth = col.width || col.originalWidth));
        }
        return newColumns;
    }
    /**
     * Dynamically change or update the column definitions list.
     * We will re-render the grid so that the new header and data shows up correctly.
     * If using i18n, we also need to trigger a re-translate of the column headers
     */
    updateColumnDefinitionsList(newColumns, triggerAutoSizeColumns = true, triggerColumnsFullResizeByContent = false) {
        // get all columns or use local copy if grid is not yet initialized,
        let allColumns = this.sharedService.allColumns || this._grid.getColumns();
        // then resync the dynamic columns (checkbox selector, row move, row detail) with the new columns list
        const updatedColumns = this.syncPluginColumns(newColumns, allColumns);
        // finally sort and set the new presets columns (including checkbox selector if need be)
        const orderedColumns = sortPresetColumns(allColumns, updatedColumns);
        this._grid.setColumns(orderedColumns);
        // resize the columns to fit the grid canvas
        if (triggerAutoSizeColumns) {
            this._grid.autosizeColumns();
        }
        else if (triggerColumnsFullResizeByContent ||
            (this._gridOptions.enableAutoResizeColumnsByCellContent && !this._gridOptions.autosizeColumnsByCellContentOnFirstLoad)) {
            this.pubSubService.publish('onFullResizeByContentRequested', { caller: 'GridStateService' });
        }
    }
    /**
     * Get the current grid state (filters/sorters/pagination), by default we'll return only the visible columns
     * but with the argument `includeHiddenColumns` set to true, we could instead return all columns including their "hidden"
     * @param {Boolean} [includeHiddenColumns=false] - should we include all columns including the hidden column and their "hidden"
     * @return grid state
     */
    getCurrentGridState(includeHiddenColumns = false) {
        const isIncludingHiddenProps = !!(includeHiddenColumns || this._gridOptions.gridStateIncludeHiddenProps);
        const { frozenColumn, frozenRow, frozenBottom } = this.sharedService.gridOptions;
        const gridState = {
            columns: this.getCurrentColumns(isIncludingHiddenProps),
            filters: this.getCurrentFilters(),
            sorters: this.getCurrentSorters(),
            pinning: { frozenColumn, frozenRow, frozenBottom },
        };
        // optional Grouping
        const currentGrouping = this.getCurrentGrouping();
        if (currentGrouping) {
            gridState.grouping = currentGrouping;
        }
        // optional Pagination
        const currentPagination = this.getCurrentPagination();
        if (currentPagination) {
            gridState.pagination = currentPagination;
        }
        // optional Row Selection
        if (this.hasRowSelectionEnabled()) {
            const currentRowSelection = this.getCurrentRowSelections();
            if (currentRowSelection) {
                gridState.rowSelection = currentRowSelection;
            }
        }
        // optional Tree Data toggle items
        if (this._gridOptions?.enableTreeData) {
            const treeDataTreeToggleState = this.getCurrentTreeDataToggleState();
            if (treeDataTreeToggleState) {
                gridState.treeData = treeDataTreeToggleState;
            }
        }
        return gridState;
    }
    /**
     * Get the Columns (and their state: visibility/position) that are currently applied in the grid
     * @return {Array<Column>} current columns
     */
    getColumns() {
        return this._columns;
    }
    /**
     * From an array of Grid Column Definitions, get the associated Current Columns.
     * @param {Array<Column>} gridColumns
     * @param {Boolean} [includeHiddenProps=false] - should we also include the "hidden" on all the columns? defaults to `false`
     * @returns {{Array<CurrentColumn>} current columns
     */
    getAssociatedCurrentColumns(gridColumns, includeHiddenProps = false) {
        const currentColumns = [];
        if (Array.isArray(gridColumns)) {
            gridColumns.forEach((column) => {
                if (column?.id) {
                    const currColumn = {
                        columnId: column.id,
                        cssClass: column.cssClass || '',
                        headerCssClass: column.headerCssClass || '',
                        width: column.width || 0,
                    };
                    if (includeHiddenProps) {
                        currColumn.hidden = column.hidden;
                    }
                    currentColumns.push(currColumn);
                }
            });
        }
        return currentColumns;
    }
    /**
     * From an array of Grid State Columns (`CurrentColumn[]`), get the associated Grid Column Definitions
     * @param {Object} grid
     * @param {Array<CurrentColumn>} currentColumns (e.g. Grid Preset)
     * @returns {Array<Column>} column definitions
     */
    getAssociatedGridColumns(grid, currentColumns) {
        const columns = [];
        const gridColumns = this.sharedService.allColumns || grid.getColumns();
        if (currentColumns && Array.isArray(currentColumns)) {
            currentColumns.forEach((currentColumn) => {
                const gridColumn = gridColumns.find((c) => c.id === currentColumn.columnId);
                if (gridColumn?.id) {
                    columns.push({
                        ...gridColumn,
                        cssClass: currentColumn.cssClass || gridColumn.cssClass,
                        headerCssClass: currentColumn.headerCssClass || gridColumn.headerCssClass,
                        hidden: currentColumn.hidden || false,
                        // for the width we will only pull the custom width or else nothing
                        // since we don't want to use the default width that SlickGrid uses internally (which is 60px),
                        // because that would cancel any column resize done by Slickgrid-Universal (like autoResizeColumnsByCellContent)
                        width: currentColumn.width,
                    });
                }
            });
        }
        this._columns = columns;
        return columns;
    }
    /**
     * Get the Columns (and their states: visibility/position/width) that are currently applied in the grid
     * @param {Boolean} [includeHiddenColumns=false] - should we include all columns including the hidden column and their "hidden"
     * @return current columns
     */
    getCurrentColumns(includeHiddenColumns = false) {
        // when enable, we'll retrieve all columns and include the "hidden" props as well
        const columns = includeHiddenColumns ? this._grid.getColumns() : this._grid.getVisibleColumns();
        return this.getAssociatedCurrentColumns(columns, includeHiddenColumns);
    }
    /**
     * Get the Filters (and their state, columnId, searchTerm(s)) that are currently applied in the grid
     * @return current filters
     */
    getCurrentFilters() {
        if (this._gridOptions?.backendServiceApi) {
            const backendService = this._gridOptions.backendServiceApi.service;
            if (backendService?.getCurrentFilters) {
                return backendService.getCurrentFilters();
            }
        }
        else if (this.filterService?.getCurrentLocalFilters) {
            return this.filterService.getCurrentLocalFilters();
        }
        return null;
    }
    /**
     * Get the Grouping column IDs or null when there are no Grouping set
     * @returns current Grouping column IDs
     */
    getCurrentGrouping() {
        if (this._gridOptions?.enableGrouping || this._gridOptions.enableDraggableGrouping) {
            return this._dataView.getGrouping().map((g) => g.getter?.toString() || '');
        }
        return null;
    }
    /**
     * Get current Pagination (and its state, pageNumber, pageSize) that are currently applied in the grid
     * @return current pagination state
     */
    getCurrentPagination() {
        if (this._gridOptions?.enablePagination) {
            if (this._gridOptions.backendServiceApi) {
                const backendService = this._gridOptions.backendServiceApi.service;
                if (backendService?.getCurrentPagination) {
                    return backendService.getCurrentPagination();
                }
            }
            return this.sharedService.currentPagination;
        }
        return null;
    }
    /**
     * Get the current Row Selections (and its state, gridRowIndexes, dataContextIds, filteredDataContextIds) that are currently applied in the grid
     * @return current row selections
     */
    getCurrentRowSelections() {
        if (this._grid && this._dataView && this.hasRowSelectionEnabled()) {
            return {
                gridRowIndexes: this._grid.getSelectedRows() || [],
                dataContextIds: this._dataView.getAllSelectedIds() || [],
                filteredDataContextIds: this._dataView.getAllSelectedFilteredIds() || [],
            };
        }
        return null;
    }
    /**
     * Get the current Sorters (and their state, columnId, direction) that are currently applied in the grid
     * @return current sorters
     */
    getCurrentSorters() {
        if (this._gridOptions?.backendServiceApi) {
            const backendService = this._gridOptions.backendServiceApi.service;
            if (backendService?.getCurrentSorters) {
                return backendService.getCurrentSorters();
            }
        }
        else if (this.sortService?.getCurrentLocalSorters) {
            return this.sortService.getCurrentLocalSorters();
        }
        return null;
    }
    /**
     * Get the current list of Tree Data item(s) that got toggled in the grid
     * @returns {Array<TreeToggledItem>} treeDataToggledItems - items that were toggled (array of `parentId` and `isCollapsed` flag)
     */
    getCurrentTreeDataToggleState() {
        if (this._gridOptions?.enableTreeData && this.treeDataService) {
            return this.treeDataService.getCurrentToggleState();
        }
        return null;
    }
    /** Check whether the row selection needs to be preserved */
    needToPreserveRowSelection() {
        let preservedRowSelection = false;
        if (this._gridOptions?.dataView && this._gridOptions.dataView.hasOwnProperty('syncGridSelection')) {
            const syncGridSelection = this._gridOptions.dataView.syncGridSelection;
            if (typeof syncGridSelection === 'boolean') {
                preservedRowSelection = this._gridOptions.dataView.syncGridSelection;
            }
            else if (typeof syncGridSelection === 'object') {
                preservedRowSelection = syncGridSelection.preserveHidden || syncGridSelection.preserveHiddenOnSelectionChange;
            }
            // if the result is True but the grid is using a Backend Service, we will do an extra flag check the reason is because it might have some unintended behaviors
            // with the BackendServiceApi because technically the data in the page changes the DataView on every page.
            if (preservedRowSelection &&
                this._gridOptions.backendServiceApi &&
                this._gridOptions.dataView.hasOwnProperty('syncGridSelectionWithBackendService')) {
                preservedRowSelection = this._gridOptions.dataView.syncGridSelectionWithBackendService;
            }
        }
        return preservedRowSelection;
    }
    resetColumns(columns) {
        const currentColumns = this.getAssociatedCurrentColumns(columns || this._columns);
        const isIncludingHiddenProps = !!this._gridOptions.gridStateIncludeHiddenProps;
        this.pubSubService.publish('onGridStateChanged', {
            change: { newValues: currentColumns, type: 'columns' },
            gridState: this.getCurrentGridState(isIncludingHiddenProps),
        });
    }
    /**
     * Reset the grid to its original (all) columns, that is to display the entire set of columns with their original positions & visibilities
     * @param {Boolean} triggerAutoSizeColumns - True by default, do we also want to call the "autosizeColumns()" method to make the columns fit in the grid?
     */
    resetToOriginalColumns(triggerAutoSizeColumns = true) {
        this._grid.setColumns(this.sharedService.allColumns);
        // resize the columns to fit the grid canvas
        if (triggerAutoSizeColumns) {
            this._grid.autosizeColumns();
        }
    }
    /** if we use Row Selection or the Checkbox Selector, we need to reset any selection */
    resetRowSelectionWhenRequired() {
        if (!this.needToPreserveRowSelection() && (this._gridOptions.enableSelection || this._gridOptions.enableCheckboxSelector)) {
            // this also requires the Hybrid Selection OR Row Selection Model to be registered as well
            if (this.extensionService?.getExtensionByName?.('hybridSelection')?.instance) {
                this._grid.setSelectedRows([]);
            }
        }
    }
    /**
     * Subscribe to all necessary SlickGrid or Service Events that deals with a Grid change,
     * when triggered, we will publish a Grid State Event with current Grid State
     */
    subscribeToAllGridChanges(grid) {
        const isIncludingHiddenProps = !!this._gridOptions.gridStateIncludeHiddenProps;
        // Subscribe to Event Emitter of Filter changed
        this._subscriptions.push(this.pubSubService.subscribe('onFilterChanged', (currentFilters) => {
            this.resetRowSelectionWhenRequired();
            this.pubSubService.publish('onGridStateChanged', {
                change: { newValues: currentFilters, type: 'filter' },
                gridState: this.getCurrentGridState(isIncludingHiddenProps),
            });
        }));
        // Subscribe to Event Emitter of Filter cleared
        this._subscriptions.push(this.pubSubService.subscribe('onFilterCleared', () => {
            this.resetRowSelectionWhenRequired();
            this.pubSubService.publish('onGridStateChanged', {
                change: { newValues: [], type: 'filter' },
                gridState: this.getCurrentGridState(isIncludingHiddenProps),
            });
        }));
        // Subscribe to Event Emitter of Sort changed
        this._subscriptions.push(this.pubSubService.subscribe('onSortChanged', (currentSorters) => {
            this.resetRowSelectionWhenRequired();
            this.pubSubService.publish('onGridStateChanged', {
                change: { newValues: currentSorters, type: 'sorter' },
                gridState: this.getCurrentGridState(isIncludingHiddenProps),
            });
        }));
        // Subscribe to Event Emitter of Sort cleared
        this._subscriptions.push(this.pubSubService.subscribe('onSortCleared', () => {
            this.resetRowSelectionWhenRequired();
            this.pubSubService.publish('onGridStateChanged', {
                change: { newValues: [], type: 'sorter' },
                gridState: this.getCurrentGridState(isIncludingHiddenProps),
            });
        }));
        // Subscribe to ColumnPicker and/or GridMenu for show/hide Columns visibility changes
        this.bindExtensionAddonEventToGridStateChange('columnPicker', 'onColumnsChanged');
        this.bindExtensionAddonEventToGridStateChange('gridMenu', 'onColumnsChanged');
        // subscribe to Column Resize & Reordering
        this.bindSlickGridColumnChangeEventToGridStateChange('onColumnsReordered', grid);
        this.bindSlickGridColumnChangeEventToGridStateChange('onColumnsResized', grid);
        this.bindSlickGridOnSetOptionsEventToGridStateChange(grid);
        // subscribe to Row Selection changes (when enabled)
        if (this._gridOptions.enableSelection || this._gridOptions.enableCheckboxSelector) {
            this._eventHandler.subscribe(this._dataView.onSelectedRowIdsChanged, (_e, args) => {
                const previousSelectedRowIndexes = (this._selectedRowIndexes || []).slice();
                const previousSelectedFilteredRowDataContextIds = (this.selectedRowDataContextIds || []).slice();
                this.selectedRowDataContextIds = args.filteredIds;
                this._selectedRowIndexes = args.rows;
                // prettier-ignore
                if (!dequal(this.selectedRowDataContextIds, previousSelectedFilteredRowDataContextIds) || !dequal(this._selectedRowIndexes, previousSelectedRowIndexes)) {
                    const newValues = {
                        gridRowIndexes: this._selectedRowIndexes || [],
                        dataContextIds: args.selectedRowIds,
                        filteredDataContextIds: args.filteredIds,
                    };
                    this.pubSubService.publish('onGridStateChanged', {
                        change: { newValues, type: 'rowSelection' },
                        gridState: this.getCurrentGridState(isIncludingHiddenProps),
                    });
                }
            });
        }
        // subscribe to HeaderMenu & GridService show/hide column(s)
        this._subscriptions.push(this.pubSubService.subscribe(['onHideColumns', 'onShowColumns'], (data) => {
            const currentColumns = this.getAssociatedCurrentColumns(data.columns);
            this.pubSubService.publish('onGridStateChanged', {
                change: { newValues: currentColumns, type: 'columns' },
                gridState: this.getCurrentGridState(isIncludingHiddenProps),
            });
        }));
        // subscribe to Tree Data toggle items changes
        this._subscriptions.push(this.pubSubService.subscribe('onTreeItemToggled', (toggleChange) => {
            this.pubSubService.publish('onGridStateChanged', {
                change: { newValues: toggleChange, type: 'treeData' },
                gridState: this.getCurrentGridState(isIncludingHiddenProps),
            });
        }));
        // subscribe to Tree Data full tree toggle changes
        this._subscriptions.push(this.pubSubService.subscribe('onTreeFullToggleEnd', (toggleChange) => {
            this.pubSubService.publish('onGridStateChanged', {
                change: { newValues: toggleChange, type: 'treeData' },
                gridState: this.getCurrentGridState(isIncludingHiddenProps),
            });
        }));
    }
    // --
    // protected methods
    // ------------------
    /**
     * Add certain column(s), when the feature is/are enabled, to an output column definitions array (by reference).
     * Basically some features (for example: Row Selection, Row Detail, Row Move) will be added as column(s) dynamically and internally by the lib,
     * we just ask the developer to enable the feature, via flags, and internally the lib will create the necessary column.
     * So specifically for these column(s) and feature(s), we need to re-add them internally when the user calls the `changeColumnsArrangement()` method.
     * @param {Array<Object>} dynamicAddonColumnByIndexPositionList - array of plugin columnId and columnIndexPosition that will be re-added (if it wasn't already found in the output array) dynamically
     * @param {Array<Column>} fullColumns - full column definitions array that includes every columns (including Row Selection, Row Detail, Row Move when enabled)
     * @param {Array<Column>} newArrangedColumns - output array that will be use to show in the UI (it could have less columns than fullColumnDefinitions array since user might hide some columns)
     */
    addColumnDynamicWhenFeatureEnabled(dynamicAddonColumnByIndexPositionList, fullColumns, newArrangedColumns) {
        // 1- first step is to sort them by their index position
        dynamicAddonColumnByIndexPositionList.sort((feat1, feat2) => feat1.columnIndexPosition - feat2.columnIndexPosition);
        // 2- second step, we can now proceed to create each extension/addon and that will position them accordingly in the column definitions list
        dynamicAddonColumnByIndexPositionList.forEach((feature) => {
            const pluginColumnIdx = fullColumns.findIndex((col) => col.id === feature.columnId);
            const associatedGridCheckboxColumnIdx = newArrangedColumns.findIndex((col) => col.id === feature.columnId);
            if (pluginColumnIdx >= 0 && associatedGridCheckboxColumnIdx === -1) {
                const pluginColumn = fullColumns[pluginColumnIdx];
                pluginColumnIdx === 0 ? newArrangedColumns.unshift(pluginColumn) : newArrangedColumns.splice(pluginColumnIdx, 0, pluginColumn);
            }
        });
    }
    /**
     * Bind a SlickGrid Extension Event to a Grid State change event
     * @param extension name
     * @param event name
     */
    bindExtensionAddonEventToGridStateChange(extensionName, eventName) {
        const extension = this.extensionService?.getExtensionByName?.(extensionName);
        const slickEvent = extension?.instance?.[eventName];
        const isIncludingHiddenProps = !!this._gridOptions.gridStateIncludeHiddenProps;
        if (slickEvent && typeof slickEvent.subscribe === 'function') {
            this._eventHandler.subscribe(slickEvent, (_e, args) => {
                const columns = args?.columns;
                const currentColumns = this.getAssociatedCurrentColumns(columns);
                this.pubSubService.publish('onGridStateChanged', {
                    change: { newValues: currentColumns, type: 'columns' },
                    gridState: this.getCurrentGridState(isIncludingHiddenProps),
                });
            });
        }
    }
    /**
     * Bind a Grid Event (of Column changes) to a Grid State change event
     * @param event - event name
     * @param grid - SlickGrid object
     */
    bindSlickGridColumnChangeEventToGridStateChange(eventName, grid) {
        const slickGridEvent = grid?.[eventName];
        const isIncludingHiddenProps = !!this._gridOptions.gridStateIncludeHiddenProps;
        if (slickGridEvent && typeof slickGridEvent.subscribe === 'function') {
            this._eventHandler.subscribe(slickGridEvent, () => {
                const columns = grid.getColumns();
                const currentColumns = this.getAssociatedCurrentColumns(columns);
                this.pubSubService.publish('onGridStateChanged', {
                    change: { newValues: currentColumns, type: 'columns' },
                    gridState: this.getCurrentGridState(isIncludingHiddenProps),
                });
            });
        }
    }
    /**
     * Bind a Grid Event (of grid option changes) to a Grid State change event, if we detect that any of the pinning (frozen) options changes then we'll trigger a Grid State change
     * @param grid - SlickGrid object
     */
    bindSlickGridOnSetOptionsEventToGridStateChange(grid) {
        const onSetOptionsHandler = grid.onSetOptions;
        this._eventHandler.subscribe(onSetOptionsHandler, (_e, args) => {
            const { frozenBottom: frozenBottomBefore, frozenColumn: frozenColumnBefore, frozenRow: frozenRowBefore } = args.optionsBefore;
            const { frozenBottom: frozenBottomAfter, frozenColumn: frozenColumnAfter, frozenRow: frozenRowAfter } = args.optionsAfter;
            if (frozenBottomBefore !== frozenBottomAfter || frozenColumnBefore !== frozenColumnAfter || frozenRowBefore !== frozenRowAfter) {
                const isIncludingHiddenProps = !!this._gridOptions.gridStateIncludeHiddenProps;
                const newValues = { frozenBottom: frozenBottomAfter, frozenColumn: frozenColumnAfter, frozenRow: frozenRowAfter };
                const currentGridState = this.getCurrentGridState(isIncludingHiddenProps);
                this.pubSubService.publish('onGridStateChanged', {
                    change: { newValues, type: 'pinning' },
                    gridState: currentGridState,
                });
            }
        });
    }
    /** Check wether the grid has the Row Selection enabled */
    hasRowSelectionEnabled() {
        const selectionModel = this._grid.getSelectionModel();
        const isRowSelectionEnabled = !!(this._gridOptions.enableSelection || this._gridOptions.enableCheckboxSelector);
        return isRowSelectionEnabled && !!selectionModel;
    }
    /** Load the Editor Collection asynchronously and replace the "collection" property when Promise resolves */
    loadEditorCollectionAsync(column) {
        if (column?.editor) {
            const collectionAsync = column.editor.collectionAsync;
            column.editor.disabled = true; // disable the Editor DOM element, we'll re-enable it after receiving the collection with "updateEditorCollection()"
            if (collectionAsync instanceof Promise && collectionAsync) {
                fetchAsPromise(collectionAsync).then((resolvedCollection) => {
                    if (resolvedCollection) {
                        this.updateEditorCollection(column, resolvedCollection);
                    }
                });
            }
            else if (this.rxjs?.isObservable(collectionAsync)) {
                // wrap this inside a microtask at the end of the task to avoid timing issue since updateEditorCollection requires to call SlickGrid getColumns() method after columns are available
                queueMicrotask(() => {
                    this._subscriptions.push(collectionAsync.subscribe((resolvedCollection) => this.updateEditorCollection(column, resolvedCollection)));
                });
            }
        }
    }
    /**
     * When the Editor(s) has a "editor.collection" property, we'll load the async collection.
     * Since this is called after the async call resolves, the pointer will not be the same as the "column" argument passed.
     */
    updateEditorCollection(column, newCollection) {
        if (this._grid && column.editor) {
            column.editor.collection = newCollection;
            column.editor.disabled = false;
            // get current Editor, remove it from the DOM then re-enable it and re-render it with the new collection.
            const currentEditor = this._grid.getCellEditor();
            if (currentEditor?.disable && currentEditor?.renderDomElement) {
                currentEditor.destroy();
                currentEditor.disable(false);
                currentEditor.renderDomElement(newCollection);
            }
        }
    }
}
//# sourceMappingURL=gridState.service.js.map