"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AgGridAdapter = void 0;
const tslib_1 = require("tslib");
const ag_grid_enterprise_1 = require("ag-grid-enterprise");
const AdaptableColumn_1 = require("../AdaptableState/Common/AdaptableColumn");
const GeneralConstants_1 = require("../Utilities/Constants/GeneralConstants");
const Uuid_1 = require("../AdaptableState/Uuid");
const ArrayExtensions_1 = tslib_1.__importDefault(require("../Utilities/Extensions/ArrayExtensions"));
const ModuleConstants = tslib_1.__importStar(require("../Utilities/Constants/ModuleConstants"));
const agGridModules_1 = require("./agGridModules");
const agGridDataTypeDefinitions_1 = require("./agGridDataTypeDefinitions");
const ColumnApiImpl_1 = require("../Api/Implementation/ColumnApiImpl");
const isPivotColumnTotal_1 = require("../layout-manager/src/isPivotColumnTotal");
const isPivotAggTotalColumn_1 = require("../layout-manager/src/isPivotAggTotalColumn");
// AG GRID obfuscates its internals, this is (currently) the best way to get hold of its internal services
const DANGER_AG_GRID_BEANS_MAP = {};
const getColumnApiModule = () => ag_grid_enterprise_1.ColumnApiModule;
class AgGridAdapter {
    constructor(_adaptableInstance, config) {
        this._adaptableInstance = _adaptableInstance;
        const columnApiModuleReference = config?.getAgGridColumnApiModuleReference?.() ?? getColumnApiModule();
        const ColumnDefFactory_Prototype = columnApiModuleReference?.beans?.[0]?.prototype;
        if (!ColumnDefFactory_Prototype) {
            console.error(`CRITICAL: could not get hold of AG Grid beans, this should never happen!`);
        }
        else {
            const ColumnDefFactory_Prototye_preWireBeans = ColumnDefFactory_Prototype.preWireBeans;
            ColumnDefFactory_Prototype.preWireBeans = function (beans) {
                ColumnDefFactory_Prototye_preWireBeans?.apply(this, arguments);
                const gridId = beans?.context?.getGridId();
                if (!gridId) {
                    console.error('CRITICAL: No gridId found in beans, this should never happen!');
                }
                DANGER_AG_GRID_BEANS_MAP[gridId] = beans;
            };
        }
    }
    destroy() {
        delete DANGER_AG_GRID_BEANS_MAP[this._agGridId];
        this.initialGridOptions = null;
        this.DANGER_gridApi_from_args = null;
        this.DANGER_USE_GETTER_gridApi = null;
        this.DANGER_updateGridOptionsMonkeyPatcher = null;
        this._adaptableInstance = null;
    }
    get adaptableOptions() {
        return this._adaptableInstance.adaptableOptions;
    }
    get adaptableApi() {
        return this._adaptableInstance.api;
    }
    get logger() {
        return this._adaptableInstance.logger;
    }
    get agGridOptionsService() {
        return this._adaptableInstance.agGridOptionsService;
    }
    setAgGridId(agGridId) {
        this._agGridId = agGridId;
    }
    setAgGridApi(gridApi) {
        this.DANGER_USE_GETTER_gridApi = gridApi;
    }
    getAgGridApi(skipLogging) {
        if (this.DANGER_USE_GETTER_gridApi) {
            return this.DANGER_USE_GETTER_gridApi;
        }
        if (this.DANGER_gridApi_from_args) {
            return this.DANGER_gridApi_from_args;
        }
        if (!skipLogging) {
            console.error('AgGridApi is not available yet');
        }
    }
    // #gridOpts_monkey_patch
    // we need to intercept some of the GridOptions updates and refresh the Adaptable state
    monkeyPatchingGridOptionsUpdates(agGridApi) {
        const agGridOptionsService = this.DANGER_getPrivateAgGridBeans()?.gos;
        if (!agGridOptionsService) {
            return;
        }
        const agGridOptionsServicePrototype = Object.getPrototypeOf(agGridOptionsService);
        const GridOptionsService_updateGridOptions = agGridOptionsServicePrototype.updateGridOptions;
        const self = this;
        this.DANGER_updateGridOptionsMonkeyPatcher = function ({ options, force, source = 'api', }) {
            const passedColumnDefs = options.columnDefs;
            if (passedColumnDefs) {
                const colDefsWithSpecialColumns = self.getColumnDefinitionsInclSpecialColumns(passedColumnDefs);
                const allDisplayedColIds = self
                    .getAgGridApi()
                    .getAllDisplayedColumns()
                    .map((col) => col.getColId());
                // mark as hidden the colDefs of special columns which are not visible
                self.patchColDefs(colDefsWithSpecialColumns, (colDef) => {
                    if (self.adaptableApi.columnApi.internalApi.isSpecialColumn(colDef.colId)) {
                        colDef.hide = !allDisplayedColIds.includes(colDef.colId);
                    }
                });
                options['columnDefs'] = colDefsWithSpecialColumns;
                self.logger.info(`Added SpecialColumns on GridOptions.columnDefs update (source=${source})`);
            }
            // `context`
            const passedContext = options.context;
            if (passedContext) {
                passedContext['__adaptable'] = self._adaptableInstance;
                passedContext['adaptableApi'] = self.adaptableApi;
            }
            // we mutated the options array, so it's OK to use the 'arguments' object
            GridOptionsService_updateGridOptions.apply(this, arguments);
        };
        agGridOptionsService.updateGridOptions = this.DANGER_updateGridOptionsMonkeyPatcher;
    }
    DANGER_getPrivateAgGridBeans() {
        const beans = DANGER_AG_GRID_BEANS_MAP[this._agGridId];
        if (!beans) {
            this.logger.consoleError('Could not get hold of AgGridBeans! This is a critical error and will prevent Adaptable from working correctly.');
        }
        return beans;
    }
    DANGER_getLiveGridOptions() {
        return this.DANGER_getPrivateAgGridBeans()?.gridOptions;
    }
    isAgGridModuleRegistered(moduleName) {
        const agGridOptionsService = this.DANGER_getPrivateAgGridBeans()?.gos;
        if (!agGridOptionsService) {
            this.logger.consoleError('Could not get hold of GridOptionsService! This is a critical error and will prevent Adaptable from working correctly.');
            return false;
        }
        return agGridOptionsService.isModuleRegistered(moduleName);
    }
    getAgGridRegisteredModules() {
        const allModulesSet = agGridModules_1.ALL_AG_GRID_MODULES;
        const registeredModules = [];
        allModulesSet.forEach((module) => {
            if (this.isAgGridModuleRegistered(module.moduleName)) {
                registeredModules.push(module);
            }
        });
        return registeredModules;
    }
    getAgGridRegisteredModuleNames() {
        return this.getAgGridRegisteredModules().map((module) => module.moduleName);
    }
    getAgGridRootElement() {
        return this.DANGER_getPrivateAgGridBeans()?.eGridDiv;
    }
    /**
     * When AG Grid is rendered the first time, the AG GridApi is not yet set in the Adaptable context (as it's set only AFTER the grid is fully initialised)
     * yet we need it when evaluating custom GridOptions properties on the first render.
     * to handle this edge case, we try to extract the AG GridApi from the invocation arguments
     */
    grabAgGridApiOnTheFly(args) {
        if (this.DANGER_USE_GETTER_gridApi || this.DANGER_gridApi_from_args) {
            return;
        }
        if (Array.isArray(args) &&
            args[0] &&
            typeof args[0].api === 'object' &&
            // can't ise instanceof operator because gridApi is exported as interface
            typeof args[0].api?.getGridId === 'function') {
            this.DANGER_gridApi_from_args = args[0].api;
        }
    }
    updateGridOptions(options) {
        this.getAgGridApi()?.updateGridOptions(options);
    }
    getGridOption(key) {
        return this.getAgGridApi()?.getGridOption(key);
    }
    setGridOption(key, value) {
        this.getAgGridApi()?.setGridOption(key, value);
    }
    getUserGridOptionsProperty(propertyName) {
        return this.agGridOptionsService.getUserGridOptionsProperty(propertyName);
    }
    updateColumnFilterActiveState() {
        const filteredCols = new Set();
        const columnFilters = this.adaptableApi.filterApi.columnFilterApi.getActiveColumnFilters();
        columnFilters?.forEach?.((columnFilter) => {
            if (this.adaptableApi.filterApi.columnFilterApi.isColumnFilterActive(columnFilter)) {
                filteredCols.add(columnFilter.ColumnId);
            }
        });
        const agGridApi = this.getAgGridApi();
        (agGridApi.getColumns() || []).forEach((col) => {
            col.filterActive = filteredCols.has(col.getColId());
        });
    }
    getColumnDefinitionsInclSpecialColumns(agGridColDefs) {
        const allColDefs = this.enhanceColDefsWithSpecialColumns(agGridColDefs ?? this.getAgGridApi().getColumnDefs());
        return allColDefs;
    }
    enhanceColDefsWithSpecialColumns(agGridColDefs) {
        this.assignColumnIdsToColDefs(agGridColDefs);
        const specialColDefs = this.getSpecialColDefs();
        const isSpecialColDef = (colDef) => {
            const { type } = colDef;
            const colTypes = Array.isArray(type) ? type : [type];
            return colTypes.some((colType) => [
                AdaptableColumn_1.ACTION_COLUMN_TYPE,
                AdaptableColumn_1.CALCULATED_COLUMN_TYPE,
                AdaptableColumn_1.FREE_TEXT_COLUMN_TYPE,
                AdaptableColumn_1.FDC3_COLUMN_TYPE,
            ].includes(colType));
        };
        const processedSpecialColDefIds = [];
        const mapColDefs = (colDefs) => {
            return colDefs.map((colDef) => {
                if (this._adaptableInstance.agGridColumnAdapter.isColGroupDef(colDef)) {
                    // if it's a group column, recursively map its children
                    colDef.children = mapColDefs(colDef.children);
                    return colDef;
                }
                else {
                    if (!isSpecialColDef(colDef)) {
                        // if it's not a special column, return it as is
                        // without a minWidth, columns in details grid are VERY wide
                        // so the line below fixes https://github.com/AdaptableTools/adaptable/issues/2559
                        return { minWidth: 10, ...colDef };
                    }
                    const newlyCreatedSpecialColDef = specialColDefs.find((specialColDef) => specialColDef.colId === colDef.colId);
                    if (newlyCreatedSpecialColDef) {
                        // if it's a special column and we have a special col def for it, return the special col def
                        processedSpecialColDefIds.push(colDef.colId);
                        // merge the user defined colDef with the special col def
                        // this way the user may provide some custom settings for the special col def (tooltip, etc)
                        const mergedColDef = {
                            // see above comment for minWidth
                            minWidth: 10,
                            ...colDef,
                            ...newlyCreatedSpecialColDef,
                        };
                        return mergedColDef;
                    }
                    else {
                        // otherwise, return the original col def
                        return colDef;
                    }
                }
            });
        };
        let resultColDefs = mapColDefs(agGridColDefs);
        // check if there are any special colDefs that were not processed
        // in that case, add them to the end of the colDefs
        specialColDefs.forEach((specialColDef) => {
            if (!processedSpecialColDefIds.includes(specialColDef.colId)) {
                resultColDefs.push(specialColDef);
            }
        });
        // remove special column that are no longer defined
        resultColDefs = resultColDefs.filter((colDef) => {
            if (isSpecialColDef(colDef)) {
                // must be in specialColDefs
                return specialColDefs.some((specialColDef) => specialColDef.colId === colDef.colId);
            }
            return true;
        });
        return resultColDefs;
    }
    getSpecialColDefs() {
        const specialColDefs = [
            ...this.adaptableApi.calculatedColumnApi.internalApi.getColDefsForCalculatedColumns(),
            ...this.adaptableApi.actionColumnApi.internalApi.getColDefsForActionColumns(),
            ...this.adaptableApi.freeTextColumnApi.internalApi.getColDefsForFreeTextColumns(),
            ...this.adaptableApi.fdc3Api.internalApi.getFdc3ActionColDefs(),
        ];
        this.assignColumnIdsToColDefs(specialColDefs);
        return specialColDefs;
    }
    deriveSelectedCellInfoFromAgGrid() {
        const selected = this.getAgGridApi().getCellRanges();
        const columns = [];
        const gridCells = [];
        // we iterate for each ranges
        selected.forEach((rangeSelection) => {
            let shouldIncludeRange = true;
            if (rangeSelection.startRow && rangeSelection.endRow) {
                let isStartRowPin = rangeSelection.startRow.rowPinned != null;
                let isEndRowPin = rangeSelection.endRow.rowPinned != null;
                // Warn user if trying to select pinned rows and if only selecting them, stop
                if (isStartRowPin) {
                    if (isEndRowPin) {
                        shouldIncludeRange = false;
                    }
                    this.logger.consoleWarn('Cannot select pinned rows in AG Grid.');
                }
                if (shouldIncludeRange) {
                    const y1 = Math.min(rangeSelection.startRow.rowIndex, rangeSelection.endRow.rowIndex);
                    const y2 = Math.max(rangeSelection.startRow.rowIndex, rangeSelection.endRow.rowIndex);
                    for (const column of rangeSelection.columns) {
                        if (column != null) {
                            const colId = column.getColId();
                            const selectedColumn = this.adaptableApi.columnApi.getColumnWithColumnId(colId);
                            if (selectedColumn && !columns.includes(selectedColumn)) {
                                columns.push(selectedColumn);
                            }
                            for (let rowIndex = y1; rowIndex <= y2; rowIndex++) {
                                const rowNode = this.getAgGridApi().getDisplayedRowAtIndex(rowIndex);
                                // we used NOT to return grouped rows but I think that was wrong - if someone wants to return them then that is up to them...
                                // we definitely dont return pinned rows as they cannot be selected
                                if (rowNode && !this.isPinnedRowNode(rowNode)) {
                                    const selectedCell = this.adaptableApi.gridApi.getGridCellFromRowNode(rowNode, colId);
                                    gridCells.push(selectedCell);
                                }
                            }
                        }
                    }
                }
            }
        });
        const selectedCellInfo = {
            columns,
            gridCells,
        };
        return selectedCellInfo;
    }
    deriveSelectedRowInfoFromAgGrid() {
        const nodes = this.getAgGridApi().getSelectedNodes();
        const selectedRows = [];
        if (this.getAgGridApi().isPivotMode()) {
            //  dont perform row selection in pivot mode
            return undefined;
        }
        if (ArrayExtensions_1.default.IsNotNullOrEmpty(nodes)) {
            nodes.forEach((node) => {
                const rowInfo = {
                    isMaster: !!(node.master != null && node.master == true),
                    isExpanded: !!(node.expanded != null && node.expanded == true),
                    isGroup: !!(node.group != null && node.group == true),
                    isSelected: true,
                    isDisplayed: node.displayed == true,
                    rowGroupLevel: node.level,
                };
                const gridRow = {
                    primaryKeyValue: this.adaptableApi.gridApi.getPrimaryKeyValueForRowNode(node),
                    rowData: node.data,
                    rowNode: node,
                    rowInfo,
                };
                selectedRows.push(gridRow);
            });
        }
        return { gridRows: selectedRows };
    }
    isPinnedRowNode(rowNode) {
        if (!rowNode) {
            return false;
        }
        if (rowNode.isRowPinned()) {
            return true;
        }
        return false;
    }
    createAdaptableColumnFromAgGridColumn(agGridColumn, colsToGroups) {
        const colId = agGridColumn.getColId();
        const colDef = agGridColumn.getColDef();
        const { columnApi } = this.adaptableApi;
        const ColumnId = colId;
        const pkColumn = this.adaptableOptions.primaryKey;
        const ColumnGroup = colsToGroups?.[ColumnId];
        const isRealColumnGroup = ColumnGroup
            ? ColumnGroup.columnGroupId !== ColumnGroup.friendlyName
            : false;
        const isFdc3MainActionColumn = this.adaptableApi.fdc3Api.internalApi.isFdc3MainActionColumn(colId);
        let friendlyName;
        const isGeneratedRowGroupColumn = columnApi.isAutoRowGroupColumn(ColumnId);
        const isGeneratedPivotResultColumn = columnApi.isPivotResultColumn(ColumnId) && !agGridColumn.isPrimary();
        const colExists = columnApi.doesColumnExist(ColumnId) ||
            isGeneratedRowGroupColumn ||
            isGeneratedPivotResultColumn;
        if (colExists) {
            friendlyName = columnApi.getFriendlyNameForColumnId(ColumnId);
        }
        else {
            const displayName = this.getAgGridApi().getDisplayNameForColumn(agGridColumn, 'header');
            const columnFriendlyName = this.adaptableOptions.columnOptions.columnFriendlyName;
            const customFriendlyName = typeof columnFriendlyName === 'function'
                ? columnFriendlyName({
                    colId: colId,
                    agColumn: agGridColumn,
                    columnGroup: isRealColumnGroup ? ColumnGroup : undefined,
                    displayName: displayName,
                    ...this.adaptableApi.internalApi.buildBaseContext(),
                })
                : null;
            friendlyName =
                customFriendlyName ??
                    (isFdc3MainActionColumn ? GeneralConstants_1.ADAPTABLE_FDC3_ACTION_COLUMN_FRIENDLY_NAME : displayName);
            // Add Column Group;s friendlyname to the Column Friendly Name if its in a legitimate Column Group
            if (this.adaptableOptions.columnOptions.addColumnGroupToColumnFriendlyName &&
                ColumnGroup &&
                ColumnGroup.columnGroupId !== ColumnGroup.friendlyName) {
                friendlyName += ' [' + ColumnGroup.friendlyName + ']';
            }
        }
        const dataType = isGeneratedPivotResultColumn
            ? 'number'
            : this.deriveAdaptableColumnDataType(agGridColumn, false);
        const isTreeColumn = this.isTreeColumn(isGeneratedRowGroupColumn);
        const visible = agGridColumn.isVisible();
        const alwaysHidden = !visible &&
            !isTreeColumn &&
            colDef.lockVisible === true &&
            colDef.suppressColumnsToolPanel === true &&
            colDef.suppressFiltersToolPanel === true;
        const isGenerated = isGeneratedRowGroupColumn || isGeneratedPivotResultColumn;
        const abColumn = {
            Uuid: (0, Uuid_1.createUuid)(),
            isTreeColumn,
            columnId: ColumnId,
            field: colDef.field,
            friendlyName: friendlyName,
            isPrimaryKey: ColumnId === pkColumn,
            dataType: dataType,
            visible,
            alwaysHidden,
            readOnly: this.isColumnReadonly(colDef),
            columnGroup: ColumnGroup,
            fieldOnly: isGenerated ? false : this.isColumnFieldonly(colDef),
            sortable: isGenerated ? false : this.isColumnSortable(colDef),
            filterable: this.isColumnFilterable(colDef),
            queryable: true, // override later when we have the column object
            exportable: true, // override later when we have the column object
            groupable: isGenerated ? false : this.isColumnRowGroupable(colDef),
            pivotable: isGenerated ? false : this.isColumnPivotable(colDef),
            aggregatable: isGenerated ? false : this.isColumnAggregetable(colDef),
            availableAggregationFunctions: null,
            aggregationFunction: null,
            moveable: this.isColumnMoveable(colDef),
            hideable: this.isColumnHideable(colDef),
            isGrouped: isGenerated ? false : this.isColumnRowGrouped(colDef),
            isGeneratedRowGroupColumn,
            isGeneratedPivotResultColumn,
            isFixed: this.isColumnFixed(colDef),
            pinned: this.getColumnPinnedPosition(colDef),
            columnTypes: this.getColumnTypes(colDef),
            isSparkline: this.isColumnSparkline(colDef),
            isCalculatedColumn: this.isCalculatedColumn(colDef),
            isFreeTextColumn: this.isFreeTextColumn(colDef),
            isActionColumn: this.isActionColumn(colDef),
            isPivotTotalColumn: this.isPivotTotalColumn(colDef),
        };
        abColumn.queryable = this.isColumnQueryable(abColumn);
        abColumn.exportable = this.isColumnExportable(abColumn);
        if (abColumn.aggregatable) {
            abColumn.availableAggregationFunctions = this.getColumnAggregationFunctions(colDef);
            if (typeof colDef.aggFunc === 'string') {
                abColumn.aggregationFunction = colDef.aggFunc;
            }
        }
        return abColumn;
    }
    deriveAdaptableColumnDataType(agColumn, logWarning = true) {
        // Some columns can have no ID or Title. we return string as a consequence but it needs testing
        if (!agColumn) {
            this.logger.warn(`Column is undefined, returning 'text' for Type`);
            return 'text';
        }
        const colDefType = [].concat(agColumn.getColDef()?.type || []).filter(Boolean);
        const skippedSpecialCols = ['actionColumn', 'fdc3Column'];
        if (skippedSpecialCols.some((specialColType) => colDefType.includes(specialColType))) {
            return 'unknown';
        }
        let dataType = 'unknown';
        // get the column type if already in store (and not unknown)
        const existingColumn = this.adaptableApi.columnApi.getColumnWithColumnId(agColumn.getId(), logWarning);
        if (existingColumn && existingColumn.dataType !== 'unknown') {
            return existingColumn.dataType;
        }
        // check for colDef dataType
        const colDefDataType = agColumn.getColDef().cellDataType;
        if (typeof colDefDataType === 'string' && agGridDataTypeDefinitions_1.ALL_ADAPTABLE_DATA_TYPES.includes(colDefDataType)) {
            return colDefDataType;
        }
        // see #agGridDataTypeDefinitions
        // theoretically, if AG Grid was not able to infer the type, we should not be able to either
        // but we give it a try, AG Grid is limited when the colDef has a valueGetter, valueParser, etc
        // see https://www.ag-grid.com/javascript-data-grid/cell-data-types/#inferring-data-types
        let row = this.getAgGridApi().getDisplayedRowAtIndex(0);
        if (row == null) {
            // possible that there will be no data.
            this.logger.consoleError(`No data in grid, returning type "unknown" for Column: "${agColumn.getColId()}". This will impact several Adaptable features, such as Filters and ColumnFormats.`);
            return 'unknown';
        }
        // if it's a group we need the content of the group
        if (row.group) {
            const childNodes = row.childrenAfterGroup;
            if (ArrayExtensions_1.default.IsNullOrEmpty(childNodes)) {
                this.logger.consoleError(`No data in grid, returning type "unknown" for Column: "${agColumn.getColId()}". This will impact several Adaptable features, such as Filters and ColumnFormats.`);
                return 'unknown';
            }
            row = childNodes[0];
        }
        const value = this._agGridApi_getValue(agColumn, row);
        switch (typeof value) {
            case 'string':
                dataType = 'text';
                break;
            case 'number':
                dataType = 'number';
                break;
            case 'boolean':
                dataType = 'boolean';
                break;
            case 'object':
                dataType = 'object';
                break;
        }
        if (value instanceof Date) {
            dataType = 'date';
        }
        else if (Array.isArray(value)) {
            const arrayDataType = agGridDataTypeDefinitions_1.ALL_ADAPTABLE_DATA_TYPES.find((arrayType) => {
                const dataTypeDefinition = agGridDataTypeDefinitions_1.agGridDataTypeDefinitions[arrayType];
                const dataTypeMatching = dataTypeDefinition?.dataTypeMatcher?.(value);
                return dataTypeMatching;
            });
            if (arrayDataType) {
                dataType = arrayDataType;
            }
        }
        this.logger.consoleWarn(`No defined type for column '${agColumn.getColId()}'. Defaulting to type of first row value: ${dataType}`);
        return dataType;
    }
    isColumnReadonly(colDef) {
        if (!colDef) {
            return true;
        }
        // if the column has conditional/dynamic editability, we assume some rows may be editable
        if (typeof colDef.editable === 'function') {
            return false;
        }
        // otherwise we evaluate the colDef.editable property (columns are NOT editable by default)
        return !colDef.editable;
    }
    isColumnFieldonly(colDef) {
        if (colDef.hide == true && colDef.initialHide == true && colDef.lockVisible == true) {
            return true;
        }
        return false;
    }
    isColumnSortable(colDef) {
        if (colDef && colDef.sortable != null) {
            return colDef.sortable;
        }
        return false;
    }
    isColumnRowGroupable(colDef) {
        if (colDef && colDef.enableRowGroup != null) {
            return colDef.enableRowGroup;
        }
        return false;
    }
    isColumnPivotable(colDef) {
        if (colDef && colDef.enablePivot != null) {
            return colDef.enablePivot;
        }
        return false;
    }
    isColumnAggregetable(colDef) {
        if (colDef && colDef.enableValue != null) {
            return colDef.enableValue;
        }
        return false;
    }
    getColumnAggregationFunctions(colDef) {
        return colDef.allowedAggFuncs || ['sum', 'min', 'max', 'count', 'avg', 'first', 'last']; // those are the default fns aggrid supports out-of-the-box
    }
    isTreeColumn(isGeneratedRowGroupColumn) {
        return this.adaptableApi.gridApi.isTreeDataGrid() ? isGeneratedRowGroupColumn : false;
    }
    isColumnMoveable(colDef) {
        if (!colDef) {
            return false;
        }
        if (colDef.suppressMovable != null && colDef.suppressMovable == true) {
            return false;
        }
        if (this.isColumnFixed(colDef)) {
            return false;
        }
        return true;
    }
    isColumnQueryable(abColumn) {
        return (
            // !this.adaptableApi.columnApi.isPivotResultColumn(abColumn.columnId) &&
            (this.adaptableApi.expressionApi.isColumnQueryable(abColumn))
        );
    }
    isColumnExportable(abColumn) {
        return this.adaptableApi.exportApi.isColumnExportable(abColumn);
    }
    isColumnHideable(colDef) {
        if (!colDef) {
            return false;
        }
        if (this.adaptableApi.gridApi.isTreeDataGrid() &&
            this.adaptableApi.columnApi.isAutoRowGroupColumn(colDef.colId)) {
            return false;
        }
        if (colDef.lockVisible != null && colDef.lockVisible == true) {
            return false;
        }
        return true;
    }
    isCalculatedColumn(colDef) {
        return (this.adaptableApi.calculatedColumnApi.getCalculatedColumnForColumnId(colDef.colId) != null);
    }
    isFreeTextColumn(colDef) {
        return this.adaptableApi.freeTextColumnApi.getFreeTextColumnForColumnId(colDef.colId) != null;
    }
    isActionColumn(colDef) {
        return this.adaptableApi.actionColumnApi.getActionColumnForColumnId(colDef.colId) != null;
    }
    isPivotTotalColumn(colDef) {
        return ((0, ColumnApiImpl_1.isPivotGrandTotal)(colDef.colId) ||
            (0, isPivotColumnTotal_1.isPivotColumnTotal)(colDef.colId) ||
            (0, isPivotAggTotalColumn_1.isPivotAggTotalColumn)(colDef));
    }
    isColumnFilterable(colDef) {
        // follow agGrid logic which is that ONLY filterable if explicitly set
        if (this.adaptableApi.entitlementApi.getEntitlementAccessLevelForModule(ModuleConstants.ColumnFilterModuleId) == 'Hidden') {
            return false;
        }
        return colDef != null && colDef.filter != null && colDef.filter != false;
    }
    getColumnTypes(colDef) {
        if (!colDef.type) {
            return [];
        }
        const allTypes = typeof colDef.type === 'string' ? [colDef.type] : colDef.type;
        return allTypes;
    }
    getColumnPinnedPosition(colDef) {
        return colDef.pinned
            ? colDef.pinned === 'left' || colDef.pinned === true
                ? 'left'
                : 'right'
            : false;
    }
    // used for AG Grid when the column is FixedPinned, meaning it should never be unpinned
    isColumnFixed(colDef) {
        if (!colDef) {
            return false;
        }
        if (colDef.lockPosition != null && colDef.lockPosition == true) {
            return true;
        }
        if (colDef.lockPinned != null && colDef.lockPinned == true) {
            return true;
        }
        return false;
    }
    isColumnRowGrouped(colDef) {
        if (!colDef) {
            return false;
        }
        if (colDef.rowGroup != null && colDef.rowGroup == true) {
            return true;
        }
        if (colDef.rowGroupIndex != null) {
            return true;
        }
        return false;
    }
    isColumnSparkline(colDef) {
        // see https://www.ag-grid.com/javascript-data-grid/sparklines-overview/#enabling-sparklines
        return colDef?.cellRenderer === 'agSparklineCellRenderer';
    }
    isVisibleNode(rowNode) {
        const foundNode = this.getAgGridApi()
            ?.getRenderedNodes()
            .find((n) => n.id == rowNode.id);
        return foundNode != null;
    }
    getFlattenedColDefs(colDefs = []) {
        const flattenedColDefs = [];
        colDefs.forEach((colDef) => {
            if (colDef.children) {
                flattenedColDefs.push(...this.getFlattenedColDefs(colDef.children));
            }
            else {
                flattenedColDefs.push(colDef);
            }
        });
        this.assignColumnIdsToColDefs(flattenedColDefs);
        return flattenedColDefs;
    }
    /**
     * Mutates the colDefs to ensure that each column has a colId
     */
    assignColumnIdsToColDefs(colDefs = []) {
        const assignColId = (colDef) => {
            if (!colDef) {
                return;
            }
            if (colDef.field && !colDef.colId) {
                colDef.colId = colDef.field;
            }
            if (!colDef.colId) {
                this.logger.warn('A column is missing the colId - please check ', colDef, 'Either pass a "field" property or a "colId" property.');
            }
        };
        this.patchColDefs(colDefs, assignColId);
    }
    patchColDefs(colDefs = [], patchFn) {
        const applyPatch = (colDef) => {
            if (!colDef) {
                return;
            }
            if (!colDef.children) {
                patchFn(colDef);
            }
            if (colDef.children) {
                colDef.children.forEach((childColDef) => applyPatch(childColDef));
            }
        };
        colDefs.forEach((colDef) => applyPatch(colDef));
    }
    traverseColDefs(colDefs, modifyFn) {
        const applyModification = (colDef) => {
            if ('children' in colDef) {
                const updatedChildren = colDef.children.map(applyModification).filter(Boolean);
                return { ...colDef, children: updatedChildren };
            }
            else {
                return modifyFn(colDef);
            }
        };
        return colDefs.map(applyModification).filter(Boolean);
    }
    getDefaultColumnDefinition() {
        // for early init phase, gridApi might not be ready yet
        return this.getAgGridApi(true)?.getGridOption('defaultColDef') ?? {};
    }
    _agGridApi_getValue(colKey, rowNode, gridApi) {
        gridApi = gridApi || this.getAgGridApi();
        return gridApi.getCellValue({ colKey, rowNode });
    }
}
exports.AgGridAdapter = AgGridAdapter;
