"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AgGridColumnAdapter = exports.getEditorsForColumnTypes = void 0;
const tslib_1 = require("tslib");
const core_1 = require("ag-grid-community");
const merge_1 = tslib_1.__importDefault(require("lodash/merge"));
const FilterWrapper_1 = require("./FilterWrapper");
const FloatingFilterWrapper_1 = require("./FloatingFilterWrapper");
const StyleHelper_1 = require("../Utilities/Helpers/StyleHelper");
const StringExtensions_1 = tslib_1.__importDefault(require("../Utilities/Extensions/StringExtensions"));
const ObjectFactory_1 = require("../Utilities/ObjectFactory");
const tinycolor2_1 = tslib_1.__importDefault(require("tinycolor2"));
const UIHelper_1 = tslib_1.__importDefault(require("../View/UIHelper"));
const PercentBarRenderer_1 = require("./PercentBarRenderer");
const BadgeRenderer_1 = require("./BadgeRenderer");
const Helper_1 = tslib_1.__importDefault(require("../Utilities/Helpers/Helper"));
const AdaptableNumberEditor_1 = require("./editors/AdaptableNumberEditor");
const AdaptableDateEditor_1 = require("./editors/AdaptableDateEditor");
function getEditorsForColumnTypes(variant) {
    return {
        abColDefNumber: variant === 'react' ? AdaptableNumberEditor_1.AdaptableReactNumberEditor : AdaptableNumberEditor_1.AdaptableNumberEditor,
        abColDefDate: variant === 'react' ? AdaptableDateEditor_1.AdaptableReactDateEditor : AdaptableDateEditor_1.AdaptableDateEditor,
    };
}
exports.getEditorsForColumnTypes = getEditorsForColumnTypes;
class AgGridColumnAdapter {
    constructor(adaptableInstance) {
        this.adaptableInstance = adaptableInstance;
        this.colDefPropertyCache = new Map();
    }
    getVariant() {
        return this.adaptableInstance.variant;
    }
    destroy() {
        this.adaptableInstance = null;
        this.colDefPropertyCache.clear();
        this.colDefPropertyCache = null;
    }
    get adaptableApi() {
        return this.adaptableInstance.api;
    }
    get adaptableOptions() {
        return this.adaptableInstance.adaptableOptions;
    }
    get agGridApi() {
        return this.adaptableInstance.agGridAdapter.getAgGridApi();
    }
    setColDefProperty(col, propertyName, propertyGetter) {
        var _a;
        const colId = col.getColId();
        const colDef = col.getColDef();
        const colSetupInfo = {
            col,
            colDef,
            colId,
        };
        const userKey = `user.${colId}.${propertyName}`;
        const adaptableKey = `adaptable.${colId}.${propertyName}`;
        const value = colDef[propertyName];
        const isUserDefined = value !== this.colDefPropertyCache.get(adaptableKey);
        if (isUserDefined) {
            this.colDefPropertyCache.set(userKey, value);
        }
        const userValue = this.colDefPropertyCache.get(userKey);
        const adaptableValue = propertyGetter(userValue);
        if (adaptableValue != null) {
            this.colDefPropertyCache.set(adaptableKey, adaptableValue);
        }
        let theValue = adaptableValue !== null && adaptableValue !== void 0 ? adaptableValue : userValue;
        this.adaptableInstance.forPlugins((plugin) => {
            if (plugin.interceptSetupColumnProperty) {
                theValue = plugin.interceptSetupColumnProperty(colSetupInfo, propertyName, theValue, this.adaptableApi);
            }
        });
        if (propertyName === 'aggFunc') {
            if (colDef[propertyName] !== (theValue !== null && theValue !== void 0 ? theValue : null)) {
                (_a = this.agGridApi) === null || _a === void 0 ? void 0 : _a.setColumnAggFunc(colId, theValue !== null && theValue !== void 0 ? theValue : null);
            }
        }
        if (theValue === undefined && colDef[propertyName] === undefined) {
            // already undefined, so don't set an own property to the same undefined value
            return;
        }
        colDef[propertyName] = theValue;
    }
    getUserColDefProperty(columnId, propertyName) {
        const userKey = `user.${columnId}.${propertyName}`;
        return this.colDefPropertyCache.get(userKey);
    }
    setupColumns() {
        const cols = this.agGridApi.getColumns();
        // this needs to be here, before the other setup below
        // so the setup methods below reference the correct columns in adaptable store
        cols.forEach((col) => {
            const colDef = col.getColDef();
            const colId = col.getColId();
            const abColumn = this.adaptableApi.columnApi.getColumnWithColumnId(colId);
            const colSetupInfo = {
                col,
                colDef,
                colId,
                abColumn,
            };
            this.setupColumnCellRenderer(colSetupInfo);
            this.setupColumnCellStyle(colSetupInfo);
            this.setupColumnCellClass(colSetupInfo);
            this.setupColumnTooltipValueGetter(colSetupInfo);
            this.setupColumnValueGetter(colSetupInfo);
            this.setupColumnFilter(colSetupInfo);
            this.setupColumnFloatingFilter(colSetupInfo);
            this.setupColumnValueFormatter(colSetupInfo);
            this.setupColumnEditable(colSetupInfo);
            this.setupColumnValueSetter(colSetupInfo);
            this.setupColumnComparator(colSetupInfo);
            this.setupColumnCellEditor(colSetupInfo);
            this.setupColumnHeader(colSetupInfo);
            this.setupColumnQuickFilerText(colSetupInfo);
            this.setupColumnAllowedAggFuncs(colSetupInfo);
            // this is just to make sure that AG Grid does NOT infer the cellDataType
            // https://github.com/AdaptableTools/adaptable/issues/2230 should render it obsolete
            this.setupColumnCellDataType(colSetupInfo);
        });
    }
    setupColumnValueGetter({ col }) {
        // need this here if we want plugins to intercept
        this.setColDefProperty(col, 'valueGetter', (userValue) => {
            return userValue;
        });
    }
    setupColumnCellClass({ col, colId, abColumn }) {
        this.setColDefProperty(col, 'cellClass', (userCellClass) => {
            const formatColumns = this.adaptableApi.formatColumnApi.internalApi.getFormatColumnWithStyleClassNameForColumn(abColumn);
            const quickSearchStyleClassName = this.adaptableApi.quickSearchApi.getQuickSearchStyle().ClassName;
            const hasQuickSearchStyleClassName = StringExtensions_1.default.IsNotNullOrEmpty(quickSearchStyleClassName);
            const cellClass = (params) => {
                const gridCell = this.adaptableApi.gridApi.getGridCellFromRowNode(params.node, abColumn.columnId);
                // if a Visual Data export is in progress, we are interested only in the Excel Style Class
                if (this.adaptableApi.exportApi.internalApi.isVisualDataExportInProgress()) {
                    const userDefinedCellClass = typeof userCellClass === 'function' ? userCellClass(params) : userCellClass;
                    const cellClassKey = this.getExcelClassNameForCell(colId, gridCell.primaryKeyValue, userDefinedCellClass);
                    return this.adaptableApi.exportApi.internalApi.getExcelStyleIdForCellClassKey(cellClassKey);
                }
                const isQuickSearchActive = hasQuickSearchStyleClassName && this.isQuickSearchActive(gridCell, params);
                const editableClassName = this.getEditableCellClass(gridCell, params);
                const readonlyClassName = this.getReadonlyCellClass(gridCell, params);
                const editedClassName = this.getEditedCellClass(gridCell, params);
                const highlightAlertClassName = this.getAlertCellClass(gridCell, params);
                const flashingClassName = this.getFlashingCellClass(gridCell, params);
                const styledColumn = this.adaptableApi.styledColumnApi.getStyledColumnForColumnId(colId);
                const hasStyledColumn = !!styledColumn && !styledColumn.IsSuspended;
                const noteClassName = this.getNoteCellClassName(gridCell, params);
                const commentsClassName = this.getCommentCellClassName(gridCell, params);
                const returnValue = [
                    typeof userCellClass === 'function' ? userCellClass(params) : userCellClass,
                    !hasStyledColumn && formatColumns.length
                        ? this.getFormatColumnCellClass(formatColumns, abColumn, params)
                        : null,
                    isQuickSearchActive ? quickSearchStyleClassName : null,
                    editableClassName,
                    readonlyClassName,
                    editedClassName,
                    highlightAlertClassName,
                    flashingClassName,
                    noteClassName,
                    commentsClassName,
                ]
                    // we flatten the array because some rules ('userCellClass' etc)  might return a string[]
                    .flat()
                    .filter((x) => !!x);
                const result = returnValue.length ? returnValue : undefined;
                return result;
            };
            return cellClass;
        });
    }
    setupColumnCellStyle({ col, colId, abColumn }) {
        this.setColDefProperty(col, 'cellStyle', (userCellStyle) => {
            const quickSearchStyle = this.getQuickSearchCellStyle();
            const hasQuickSearchStyle = quickSearchStyle != undefined;
            const cellStyle = (params) => {
                const gridCell = this.adaptableInstance.getGridCellFromRowNode(params.node, abColumn.columnId);
                const isQuickSearchActive = hasQuickSearchStyle && this.isQuickSearchActive(gridCell, params);
                const userDefined = typeof userCellStyle === 'function' ? userCellStyle(params) : userCellStyle;
                const result = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, userDefined), this.getReadOnlyCellStyle(gridCell, params)), this.getEditableCellStyle(gridCell, params)), this.getEditedCellStyle(gridCell, params)), this.getFormatColumnAndStyledColumnCellStyle(gridCell, params)), (isQuickSearchActive ? quickSearchStyle : {})), this.getAlertCellStyle(gridCell, params)), this.getFlashingCellStyle(gridCell, params)), this.getCellHighlightStyle(gridCell, params));
                return (0, StyleHelper_1.normalizeStyleForAgGrid)(result);
            };
            return cellStyle;
        });
    }
    setupColumnCellEditor({ colId, col }) {
        const adaptableColumn = this.adaptableApi.columnApi.getColumnWithColumnId(colId);
        const editLookUpItem = this.adaptableApi.userInterfaceApi.getEditLookUpItemForColumn(adaptableColumn);
        const hasRichSelectCellEditor = this.adaptableInstance.agGridAdapter.isModulePresent(core_1.ModuleNames.RichSelectModule);
        this.setColDefProperty(col, 'cellEditor', () => {
            if (editLookUpItem) {
                return hasRichSelectCellEditor ? 'agRichSelectCellEditor' : 'agSelectCellEditor';
            }
            else {
                const colDef = col.getColDef();
                if (colDef.cellEditor) {
                    return colDef.cellEditor;
                }
                const columnTypeToCellEditor = getEditorsForColumnTypes(this.getVariant());
                return (adaptableColumn.columnTypes || []).reduce((cellEditor, colType) => {
                    var _a;
                    return (_a = columnTypeToCellEditor[colType]) !== null && _a !== void 0 ? _a : cellEditor;
                }, undefined);
            }
        });
        this.setColDefProperty(col, 'cellEditorPopup', () => {
            // as specified in https://www.ag-grid.com/react-data-grid/provided-cell-editors/#rich-select-cell-editor
            // agRichSelectCellEditor should always set cellEditorPopup=true. Otherwise the editor will be clipped to the cell contents
            if (editLookUpItem && hasRichSelectCellEditor) {
                return true;
            }
        });
        this.setColDefProperty(col, 'cellEditorParams', (params) => {
            if (editLookUpItem) {
                return (params) => {
                    const gridCell = this.adaptableInstance.getGridCellFromRowNode(params === null || params === void 0 ? void 0 : params.node, colId);
                    return {
                        values: this.adaptableApi.userInterfaceApi.getEditLookUpValuesForEditLookUpItem(editLookUpItem, gridCell),
                    };
                };
            }
        });
    }
    setupColumnCellRenderer({ col, colId, abColumn }) {
        this.setColDefProperty(col, 'cellRenderer', () => {
            const styledColumn = this.adaptableApi.styledColumnApi.getStyledColumnForColumnId(abColumn.columnId);
            if (styledColumn && !styledColumn.IsSuspended) {
                if (styledColumn.PercentBarStyle) {
                    return (0, PercentBarRenderer_1.getPercentBarRendererForColumn)(styledColumn, abColumn, this.adaptableApi);
                }
                if (styledColumn.BadgeStyle) {
                    return (0, BadgeRenderer_1.getBadgeRendererForColumn)(styledColumn.BadgeStyle, abColumn, this.adaptableApi);
                }
                if (styledColumn.SparkLineStyle) {
                    return 'agSparklineCellRenderer';
                }
            }
        });
        this.setColDefProperty(col, 'cellRendererParams', (userDefined) => {
            const styledColumn = this.adaptableApi.styledColumnApi.getStyledColumnForColumnId(abColumn.columnId);
            if (styledColumn && !styledColumn.IsSuspended) {
                if (styledColumn.SparkLineStyle) {
                    const sparklineOptions = (0, merge_1.default)({}, userDefined === null || userDefined === void 0 ? void 0 : userDefined.sparklineOptions, styledColumn.SparkLineStyle.options);
                    return Object.assign(Object.assign({}, userDefined), { sparklineOptions });
                }
            }
        });
    }
    setupColumnTooltipValueGetter({ col, colId, abColumn }) {
        let hasTooptip = false;
        this.setColDefProperty(col, 'tooltipValueGetter', () => {
            const styledColumn = this.adaptableApi.styledColumnApi.getStyledColumnForColumnId(colId);
            if (styledColumn &&
                !styledColumn.IsSuspended &&
                styledColumn.PercentBarStyle &&
                styledColumn.PercentBarStyle.ToolTipText) {
                hasTooptip = true;
                if (styledColumn === null || styledColumn === void 0 ? void 0 : styledColumn.PercentBarStyle) {
                    return (params) => {
                        const min = this.adaptableApi.styledColumnApi.internalApi.getNumericStyleMinValue(styledColumn, abColumn, params.node, params.value);
                        const max = this.adaptableApi.styledColumnApi.internalApi.getNumericStyleMaxValue(styledColumn, abColumn, params.node, params.value);
                        const textOptions = styledColumn.PercentBarStyle.ToolTipText;
                        let returnValue = '';
                        if (textOptions.includes('CellValue')) {
                            returnValue = params.value;
                        }
                        if (textOptions.includes('PercentageValue')) {
                            const clampedValue = Helper_1.default.clamp(params.value, min, max);
                            const percentageValue = ((clampedValue - min) / (max - min)) * 100;
                            returnValue += ' ' + `(${percentageValue.toFixed(0)}%)`;
                        }
                        return returnValue ? returnValue : params.value;
                    };
                }
            }
        });
    }
    setupColumnQuickFilerText({ col, abColumn }) {
        this.setColDefProperty(col, 'getQuickFilterText', (userGetQuickFilterText) => {
            if (userGetQuickFilterText) {
                return userGetQuickFilterText;
            }
            return (params) => {
                const visibleCoulmnsMap = this.adaptableApi.layoutApi.getCurrentVisibleColumnIdsMap();
                const isVisible = visibleCoulmnsMap[abColumn.columnId];
                if (!isVisible) {
                    return '';
                }
                return this.adaptableInstance.getDisplayValueFromRowNode(params.node, abColumn.columnId);
            };
        });
    }
    setupColumnAllowedAggFuncs({ col, abColumn }) {
        this.setColDefProperty(col, 'allowedAggFuncs', () => {
            return abColumn.availableAggregationFunctions;
        });
    }
    setupColumnCellDataType(columnSetupInfo) {
        const { col } = columnSetupInfo;
        // AG Grid introduced since v30.x an inferred cellDataType
        // the problem is that it breaks the default value formatter and/or editor (especially for Date columns)
        this.setColDefProperty(col, 'cellDataType', () => {
            return false;
        });
    }
    setupColumnHeader({ col, abColumn }) {
        var _a, _b;
        const previousColumnHeader = (_a = col === null || col === void 0 ? void 0 : col.getColDef()) === null || _a === void 0 ? void 0 : _a.headerName;
        this.setColDefProperty(col, 'headerName', (userHeaderName) => {
            var _a;
            // set the default to the AG Grid provided values
            // from https://github.com/ag-grid/ag-grid/blob/v26.1.0/community-modules/core/src/ts/columns/columnModel.ts#L2515
            let resultHeaderName = userHeaderName !== null && userHeaderName !== void 0 ? userHeaderName : StringExtensions_1.default.CamelCaseToHumanText(col.getColDef().field);
            const layoutCustomHeader = (_a = this.adaptableApi.layoutApi.getCurrentLayout().ColumnHeadersMap) === null || _a === void 0 ? void 0 : _a[col.getColId()];
            if (layoutCustomHeader) {
                resultHeaderName = layoutCustomHeader;
            }
            // required here for the initial layout rendering
            // Removed by JW, 3 october 2023; i don't think we need it and it overrides stuff unnecessarily
            //  abColumn.friendlyName = resultHeaderName;
            return resultHeaderName;
        });
        const newColumnHeader = (_b = col === null || col === void 0 ? void 0 : col.getColDef()) === null || _b === void 0 ? void 0 : _b.headerName;
        return previousColumnHeader !== newColumnHeader;
    }
    setupColumnFilter({ col, colDef }) {
        this.setColDefProperty(col, 'filter', () => {
            if (!colDef.filter) {
                return;
            }
            if (!this.adaptableOptions.columnFilterOptions.useAdaptableColumnFiltering) {
                return;
            }
            this.agGridApi.destroyFilter(col);
            return (0, FilterWrapper_1.FilterWrapperFactory)(this.adaptableInstance);
        });
    }
    setupColumnFloatingFilterTemporarily(initialGridOptions) {
        var _a;
        (_a = initialGridOptions.columnDefs) === null || _a === void 0 ? void 0 : _a.filter((colDef) => !this.isColGroupDef(colDef)).map((colDef) => {
            var _a;
            const isFloatingFilterEnabled = ((_a = initialGridOptions.defaultColDef) === null || _a === void 0 ? void 0 : _a.floatingFilter) || colDef.floatingFilter;
            if (isFloatingFilterEnabled) {
                colDef.floatingFilterComponent = (0, FloatingFilterWrapper_1.FloatingFilterWrapperFactory)(this.adaptableInstance);
            }
        });
    }
    setupColumnFloatingFilter({ col, colDef }) {
        const isFloatingFilterDisabled = !colDef.floatingFilter ||
            !this.adaptableOptions.columnFilterOptions.useAdaptableColumnFiltering;
        this.adaptableOptions.columnFilterOptions.quickFilterOptions.showQuickFilter;
        this.setColDefProperty(col, 'floatingFilterComponent', () => {
            if (isFloatingFilterDisabled) {
                return;
            }
            return (0, FloatingFilterWrapper_1.FloatingFilterWrapperFactory)(this.adaptableInstance);
        });
        this.setColDefProperty(col, 'floatingFilter', (original_floatingFilter) => {
            if (isFloatingFilterDisabled) {
                return;
            }
            return (0, FloatingFilterWrapper_1.FloatingFilterWrapperFactory)(this.adaptableInstance);
        });
        this.setColDefProperty(col, 'suppressFloatingFilterButton', () => {
            return !isFloatingFilterDisabled;
        });
    }
    setupColumnValueFormatter({ col, abColumn }) {
        this.setColDefProperty(col, 'valueFormatter', (userPropertyValue) => {
            const activeFormatColumnsWithDisplayFormat = this.adaptableApi.formatColumnApi.internalApi.getFormatColumnsWithDisplayFormatForColumn(abColumn);
            if (!activeFormatColumnsWithDisplayFormat.length) {
                return;
            }
            return (params) => {
                var _a, _b, _c, _d, _e, _f;
                const { node, value } = params;
                const mostRelevantFormatColumn = this.adaptableApi.formatColumnApi.internalApi.getMostRelevantFormatColumnForColumn(activeFormatColumnsWithDisplayFormat, abColumn, { node, value });
                if (!mostRelevantFormatColumn) {
                    // ALL FormatColumns are conditional and NONE of them are relevant for this row
                    return value;
                }
                const options = mostRelevantFormatColumn.DisplayFormat.Options;
                if (mostRelevantFormatColumn.DisplayFormat.Formatter === 'NumberFormatter') {
                    // change the Number format - if the scope allows it
                    if (this.adaptableApi.columnScopeApi.isColumnInNumericScope(abColumn, mostRelevantFormatColumn.Scope)) {
                        let cellValue = params.value;
                        if (typeof ((_a = params.value) === null || _a === void 0 ? void 0 : _a.toNumber) === 'function' &&
                            typeof ((_b = params.value) === null || _b === void 0 ? void 0 : _b.toString) === 'function') {
                            // aggregation values are wrapped in an AG Grid specific object
                            cellValue = params.value.toNumber();
                        }
                        return this.adaptableApi.formatColumnApi.internalApi.getNumberFormattedValue(cellValue, params.node, abColumn, options);
                    }
                }
                if (mostRelevantFormatColumn.DisplayFormat.Formatter === 'DateFormatter') {
                    // change the Date format - if the scope allows it
                    if (this.adaptableApi.columnScopeApi.isColumnInDateScope(abColumn, mostRelevantFormatColumn.Scope)) {
                        let cellValue = params.value;
                        if (typeof ((_c = params.value) === null || _c === void 0 ? void 0 : _c.toNumber) === 'function' &&
                            typeof ((_d = params.value) === null || _d === void 0 ? void 0 : _d.toString) === 'function') {
                            // aggregation values are wrapped in an AG Grid specific object
                            cellValue = params.value.toString();
                        }
                        return this.adaptableApi.formatColumnApi.internalApi.getDateFormattedValue(cellValue, params.node, abColumn, options);
                    }
                }
                if (mostRelevantFormatColumn.DisplayFormat.Formatter === 'StringFormatter') {
                    // change the String format - if the scope allows it
                    if (this.adaptableApi.columnScopeApi.isColumnInStringsScope(abColumn, mostRelevantFormatColumn.Scope)) {
                        let cellValue = params.value;
                        if (typeof ((_e = params.value) === null || _e === void 0 ? void 0 : _e.toNumber) === 'function' &&
                            typeof ((_f = params.value) === null || _f === void 0 ? void 0 : _f.toString) === 'function') {
                            // aggregation values are wrapped in an AG Grid specific object
                            cellValue = params.value.toString();
                        }
                        return this.adaptableApi.formatColumnApi.internalApi.getStringFormattedValue(cellValue, params.node, abColumn, options);
                    }
                }
                // should NEVER arrive at this line, but just to be sure
                return value;
            };
        });
    }
    setupColumnEditable({ col }) {
        this.setColDefProperty(col, 'editable', (original_editable) => {
            // cell is NOT editable by default
            const editableCallback = (params) => {
                const getOriginalColDefEditable = () => {
                    if (typeof original_editable === 'function') {
                        return original_editable(params);
                    }
                    else {
                        return original_editable;
                    }
                };
                // 1. evaluate EditOptions.isCellEditable if provided
                if (this.adaptableApi.gridApi.internalApi.hasCellEditableAccordingToEditOptions()) {
                    const gridCell = this.adaptableInstance.getGridCellFromRowNode(params.node, params.column.getColId());
                    const editOptionsEditability = this.adaptableApi.gridApi.internalApi.isCellEditableAccordingToEditOptions(gridCell, getOriginalColDefEditable());
                    if (editOptionsEditability) {
                        return editOptionsEditability;
                    }
                }
                // 2. otherwise, fallback to colDef.editable
                return getOriginalColDefEditable();
            };
            return editableCallback;
        });
    }
    setupColumnValueSetter({ col, colId, abColumn }) {
        this.setColDefProperty(col, 'valueSetter', (userValueSetter) => {
            var _a;
            const preventEditAlertsForColumn = this.adaptableApi.alertApi.internalApi
                .getAlertDefinitionsWithPreventEdit()
                .filter((alertDefinition) => {
                return this.adaptableApi.columnScopeApi.isColumnInScope(abColumn, alertDefinition.Scope);
            });
            const noValidations = !preventEditAlertsForColumn.length && !((_a = this.adaptableOptions.editOptions) === null || _a === void 0 ? void 0 : _a.validateOnServer);
            if (noValidations) {
                return;
            }
            const valueSetter = (params) => {
                var _a;
                const field = params.column.getColDef().field;
                if (noValidations) {
                    //TODO also consider the case when userValueSetter is a string
                    if (typeof userValueSetter === 'function') {
                        return userValueSetter(params);
                    }
                    // we allowed it go reach this point
                    // just to run isCellEditable
                    // and since this has already run and we have no other validations
                    // just assign the new value and exit
                    if (field) {
                        params.data[field] = params.newValue;
                    }
                    return true;
                }
                const cellDataChangedInfo = this.adaptableApi.internalApi.buildDataChangedInfo({
                    oldValue: params.oldValue,
                    newValue: params.newValue,
                    column: this.adaptableApi.columnApi.getColumnWithColumnId(params.column.getColId()),
                    primaryKeyValue: this.adaptableInstance.getPrimaryKeyValueFromRowNode(params.node, params.api),
                    rowNode: params.node,
                    trigger: 'edit',
                });
                if (cellDataChangedInfo.oldValue === cellDataChangedInfo.newValue) {
                    return true;
                }
                /**
                 * Validate on the future row, with the new value.
                 * structuredClone fails, it contains functions.
                 */
                const newRow = Object.assign(Object.assign({}, params.node), { data: Object.assign({}, params.node.data) });
                newRow.data[field] = params.newValue;
                const cellDataChangeInfoForSyncValidation = Object.assign(Object.assign({}, cellDataChangedInfo), { rowNode: newRow });
                if (!this.adaptableInstance.ValidationService.performValidation(cellDataChangeInfoForSyncValidation)) {
                    return false;
                }
                const onServerValidationCompleted = () => { };
                if ((_a = this.adaptableOptions.editOptions) === null || _a === void 0 ? void 0 : _a.validateOnServer) {
                    this.adaptableInstance.ValidationService.performServerValidation(cellDataChangedInfo, {
                        onServerValidationCompleted,
                    })();
                }
                //TODO also consider the case when userValueSetter is a string
                if (typeof userValueSetter === 'function') {
                    return userValueSetter(params);
                }
                if (field) {
                    params.data[field] = params.newValue;
                }
                else {
                    throw `Cannot edit a column without a field - column id was ${colId}`;
                }
                return true;
            };
            return valueSetter;
        });
    }
    setupColumnComparator({ col, colId, abColumn }) {
        const customSort = this.adaptableApi.customSortApi.getCustomSortForColumn(colId);
        const columnSortComparer = this.adaptableApi.customSortApi.internalApi.getCustomSortComparer(abColumn.columnId);
        const comparatorGetter = (propName) => {
            return () => {
                return this.adaptableApi.columnApi.internalApi.getActiveColumnComparator(colId, customSort, columnSortComparer);
            };
        };
        this.setColDefProperty(col, 'comparator', comparatorGetter('comparator'));
        this.setColDefProperty(col, 'pivotComparator', comparatorGetter('pivotComparator'));
    }
    getExcelClassNameForCell(colId, primaryKeyValue, userDefinedCellClass) {
        let excelClassName = `--excel-cell-${colId}-${primaryKeyValue}`;
        if (excelClassName.indexOf(' ') > 0) {
            excelClassName = excelClassName.replace(/\s/g, '_');
        }
        return userDefinedCellClass != null
            ? `${excelClassName}-${Array.isArray(userDefinedCellClass)
                ? userDefinedCellClass.join('-')
                : userDefinedCellClass}`
            : excelClassName;
    }
    isQuickSearchActive(gridCell, params) {
        let quickSearchValue = this.adaptableApi.quickSearchApi.getQuickSearchValue();
        if (StringExtensions_1.default.IsNullOrEmpty(quickSearchValue)) {
            return false;
        }
        if (gridCell.column.isExcludedFromQuickSearch) {
            return false;
        }
        if (!params.node) {
            return false;
        }
        if (!gridCell.isPivotCell &&
            !this.adaptableApi.optionsApi.getQuickSearchOptions().runQuickSearchOnRowGroups &&
            params.node.group) {
            return false;
        }
        if (!this.adaptableApi.optionsApi.getQuickSearchOptions().runQuickSearchOnPivotColumns &&
            gridCell.isPivotCell) {
            return false;
        }
        if (this.adaptableApi.optionsApi.getQuickSearchOptions().runQuickSearchOnPivotColumns &&
            gridCell.isPivotCell) {
            gridCell.displayValue = params.value;
        }
        const ignoreCase = !this.adaptableOptions.quickSearchOptions.runQuickSearchWithCaseSensitivity;
        const displayValue = ignoreCase
            ? String(gridCell.displayValue).toLocaleLowerCase()
            : String(gridCell.displayValue);
        const i = ignoreCase ? String(quickSearchValue).toLocaleLowerCase() : String(quickSearchValue);
        const applyQuickSearchFunction = this.adaptableOptions.quickSearchOptions.runBespokeQuickSearch;
        if (applyQuickSearchFunction) {
            const quickSearchContext = Object.assign(Object.assign({}, (0, ObjectFactory_1.createBaseContext)(this.adaptableApi)), { gridCell, quickSearchValue: quickSearchValue });
            return applyQuickSearchFunction(quickSearchContext);
        }
        return displayValue.indexOf(i) !== -1;
    }
    getEditableCellClass(gridCell, params) {
        const editableCellStyle = this.adaptableApi.userInterfaceApi.getEditableCellStyle();
        if (!(editableCellStyle === null || editableCellStyle === void 0 ? void 0 : editableCellStyle.ClassName)) {
            return null;
        }
        const isCellEditable = this.adaptableApi.gridApi.isCellEditable(gridCell);
        return isCellEditable ? editableCellStyle.ClassName : null;
    }
    getReadonlyCellClass(gridCell, params) {
        const readonlyCellStyle = this.adaptableApi.userInterfaceApi.getReadOnlyCellStyle();
        if (!(readonlyCellStyle === null || readonlyCellStyle === void 0 ? void 0 : readonlyCellStyle.ClassName)) {
            return null;
        }
        const isCellReadonly = !this.adaptableApi.gridApi.isCellEditable(gridCell);
        return isCellReadonly ? readonlyCellStyle.ClassName : null;
    }
    getEditedCellClass(gridCell, params) {
        const editedCellStyle = this.adaptableApi.userInterfaceApi.getEditedCellStyle();
        if (!(editedCellStyle === null || editedCellStyle === void 0 ? void 0 : editedCellStyle.ClassName)) {
            return null;
        }
        const isCellEdited = this.adaptableApi.gridApi.isCellEdited(gridCell);
        return isCellEdited ? editedCellStyle.ClassName : null;
    }
    getAlertCellClass(gridCell, params) {
        var _a, _b;
        const alert = this.adaptableApi.alertApi.internalApi.getAdaptableAlertWithHighlightCell(gridCell.column.columnId, params.node);
        const highlightCell = (_b = (_a = alert === null || alert === void 0 ? void 0 : alert.alertDefinition) === null || _a === void 0 ? void 0 : _a.AlertProperties) === null || _b === void 0 ? void 0 : _b.HighlightCell;
        return typeof highlightCell === 'object' && (highlightCell === null || highlightCell === void 0 ? void 0 : highlightCell.ClassName)
            ? highlightCell === null || highlightCell === void 0 ? void 0 : highlightCell.ClassName
            : null;
    }
    getFlashingCellClass(gridcell, params) {
        var _a, _b, _c;
        const primaryKey = params.node.aggData ? params.node.id : gridcell.primaryKeyValue;
        const flashingCell = this.adaptableApi.flashingCellApi.internalApi.getAdaptableFlashingCellFor(primaryKey, gridcell.column.columnId);
        if (!flashingCell) {
            return;
        }
        return flashingCell.direction === 'up'
            ? (_a = flashingCell.flashingCellDefinition.UpChangeStyle) === null || _a === void 0 ? void 0 : _a.ClassName
            : flashingCell.direction === 'down'
                ? (_b = flashingCell.flashingCellDefinition.DownChangeStyle) === null || _b === void 0 ? void 0 : _b.ClassName
                : flashingCell.direction === 'neutral'
                    ? (_c = flashingCell.flashingCellDefinition.NeutralChangeStyle) === null || _c === void 0 ? void 0 : _c.ClassName
                    : undefined;
    }
    getNoteCellClassName(gridCell, params) {
        if (!this.adaptableApi.internalApi.getModuleService().isModuleAvailable('Note')) {
            return;
        }
        if (!this.adaptableApi.noteApi.internalApi.areNotesSupported()) {
            return;
        }
        const cellPosition = {
            PrimaryKeyValue: gridCell.primaryKeyValue,
            ColumnId: gridCell.column.columnId,
        };
        const cellNote = this.adaptableApi.noteApi.getNoteForCell(cellPosition);
        if (!cellNote) {
            return undefined;
        }
        return 'ab-Cell-Note';
    }
    getCommentCellClassName(gridCell, params) {
        if (!this.adaptableApi.internalApi.getModuleService().isModuleAvailable('Comment')) {
            return;
        }
        if (!this.adaptableApi.commentApi.internalApi.areCommentsSupported()) {
            return;
        }
        const position = {
            PrimaryKeyValue: gridCell.primaryKeyValue,
            ColumnId: gridCell.column.columnId,
        };
        const cellComments = this.adaptableApi.commentApi.getCommentThread(position);
        if (!cellComments) {
            return undefined;
        }
        return 'ab-Cell-Comment';
    }
    getFormatColumnCellClass(formatColumns, abColumn, params) {
        const classNames = formatColumns
            .map((formatColumn) => {
            var _a, _b;
            if (((_a = formatColumn.Style) === null || _a === void 0 ? void 0 : _a.ClassName) &&
                this.adaptableApi.formatColumnApi.internalApi.formatColumnShouldRender(formatColumn, abColumn, params.node, params.value)) {
                return (_b = formatColumn.Style) === null || _b === void 0 ? void 0 : _b.ClassName;
            }
        })
            .filter((x) => !!x);
        return classNames;
    }
    getQuickSearchCellStyle() {
        const quickSearchStyle = this.adaptableApi.quickSearchApi.getQuickSearchStyle();
        if (!quickSearchStyle || StringExtensions_1.default.IsNotNullOrEmpty(quickSearchStyle.ClassName)) {
            return undefined;
        }
        return (0, StyleHelper_1.convertAdaptableStyleToCSS)(quickSearchStyle);
    }
    getReadOnlyCellStyle(gridCell, params) {
        const editableCellStyle = this.adaptableApi.userInterfaceApi.getReadOnlyCellStyle();
        if (!editableCellStyle) {
            return undefined;
        }
        if (gridCell) {
            if (!this.adaptableApi.gridApi.isCellEditable(gridCell)) {
                return (0, StyleHelper_1.convertAdaptableStyleToCSS)(editableCellStyle);
            }
        }
        return undefined;
    }
    getEditableCellStyle(gridCell, params) {
        const editableCellStyle = this.adaptableApi.userInterfaceApi.getEditableCellStyle();
        if (!editableCellStyle) {
            return undefined;
        }
        if (gridCell) {
            if (this.adaptableApi.gridApi.isCellEditable(gridCell)) {
                return (0, StyleHelper_1.convertAdaptableStyleToCSS)(editableCellStyle);
            }
        }
        return undefined;
    }
    getEditedCellStyle(gridCell, params) {
        const editedCellStyle = this.adaptableApi.userInterfaceApi.getEditedCellStyle();
        if (!editedCellStyle) {
            return undefined;
        }
        if (gridCell) {
            if (this.adaptableApi.gridApi.isCellEdited(gridCell)) {
                return (0, StyleHelper_1.convertAdaptableStyleToCSS)(editedCellStyle);
            }
        }
        return undefined;
    }
    /**
     * The combination of styled column and format cells
     * This functiond decides when the two can be merged.
     */
    getFormatColumnAndStyledColumnCellStyle(gridCell, params) {
        let styledColumn = this.adaptableApi.styledColumnApi.getStyledColumnForColumnId(gridCell.column.columnId);
        let styledColumnStyle = {};
        if (styledColumn && !(styledColumn === null || styledColumn === void 0 ? void 0 : styledColumn.IsSuspended)) {
            const styledCellStyle = this.getStyledColumnStyle(styledColumn, gridCell.column, params);
            // for percentbar we want to merge
            if (styledColumn.PercentBarStyle || styledColumn.BadgeStyle || styledColumn.GradientStyle) {
                styledColumnStyle = styledCellStyle;
            }
            else {
                // For other ones wo do not want to merge
                return styledCellStyle;
            }
        }
        const activeFormatColumnsWithStyle = this.adaptableApi.formatColumnApi.internalApi.getFormatColumnsWithStyleForColumn(gridCell.column);
        // background color of styledColumn.GradientStyle has precedence and wins over FormatColumn
        return Object.assign(Object.assign({}, this.getFormatColumnCellStyle(gridCell.column, activeFormatColumnsWithStyle, params)), styledColumnStyle);
    }
    getStyledColumnStyle(styledColumn, abColumn, params) {
        var _a;
        let style = {};
        const gradientStyle = styledColumn === null || styledColumn === void 0 ? void 0 : styledColumn.GradientStyle;
        if (params.value === undefined) {
            return;
        }
        let colValue = params.value;
        if (this.adaptableApi.gridApi.isGroupRowNode(params.node)) {
            return style;
            // if (styledColumn.IncludeGroupedRows) {
            //   const minColumnValue =
            //     this.adaptableApi.styledColumnApi.internalApi.getMinValueForNumericColumn(abColumn);
            //   const maxColumnValue =
            //     this.adaptableApi.styledColumnApi.internalApi.getMaxValueForNumericColumn(abColumn);
            //   /**
            //    * Color should always be in bounds, it should not overflow.
            //    * If the value is out of range, it shoul set the maximum/minimum color.
            //    */
            //   colValue = clamp(params.value, minColumnValue, maxColumnValue);
            // } else {
            //   return style;
            // }
        }
        if (styledColumn.BadgeStyle &&
            !((_a = styledColumn.BadgeStyle.RowScope) === null || _a === void 0 ? void 0 : _a.ExcludeSummaryRows) &&
            this.adaptableApi.gridApi.isSummaryNode(params === null || params === void 0 ? void 0 : params.node)) {
            return style;
        }
        if (gradientStyle) {
            const min = this.adaptableApi.styledColumnApi.internalApi.getNumericStyleMinValue(styledColumn, abColumn, params.node, colValue);
            const max = this.adaptableApi.styledColumnApi.internalApi.getNumericStyleMaxValue(styledColumn, abColumn, params.node, colValue);
            let cellBackColor;
            let reverseGradient = false;
            if (gradientStyle.ColumnComparison) {
                cellBackColor = gradientStyle.ColumnComparison.Color;
            }
            else {
                const matchingRange = this.adaptableApi.styledColumnApi.internalApi.findRangeForColumn(gradientStyle.CellRanges, abColumn, gradientStyle.RangeValueType, colValue);
                if (matchingRange) {
                    cellBackColor = matchingRange.Color;
                    reverseGradient = matchingRange.ReverseGradient;
                }
            }
            const increase = Math.abs(max - min);
            const percentage = ((colValue - min) / increase) * 100;
            let alpha = Number((percentage / 100).toPrecision(2));
            if (reverseGradient) {
                alpha = 1 - alpha;
            }
            const preparedColor = (0, StyleHelper_1.getVariableColor)(cellBackColor);
            // if no range match, do not apply color (black in this case)
            if (cellBackColor) {
                style.backgroundColor = (0, tinycolor2_1.default)(preparedColor).setAlpha(alpha).toRgbString();
            }
        }
        if (styledColumn.PercentBarStyle && styledColumn.PercentBarStyle.CellText) {
            style.paddingTop = 0;
            style.paddingBottom = 0;
        }
        return style;
    }
    getFormatColumnCellStyle(abColumn, activeFormatColumnsWithStyle, params) {
        if (!activeFormatColumnsWithStyle.length) {
            return {};
        }
        const relevantFormatColumnsWithStyle = activeFormatColumnsWithStyle.filter((formatColumn) => {
            return this.adaptableApi.formatColumnApi.internalApi.formatColumnShouldRender(formatColumn, abColumn, params.node, params.value);
        });
        return this.getFormatColumnAdaptableStyle(relevantFormatColumnsWithStyle);
    }
    getFormatColumnAdaptableStyle(formatColumns) {
        // first has more precedence, then they need to be applied in reverse order
        return formatColumns.reduceRight((style, formatColumn) => {
            const formatColumnStyle = formatColumn.Style
                ? (0, StyleHelper_1.convertAdaptableStyleToCSS)(formatColumn.Style)
                : {};
            if (formatColumn.CellAlignment) {
                switch (formatColumn.CellAlignment) {
                    case 'Left':
                        style.textAlign = 'left';
                        break;
                    case 'Right':
                        style.textAlign = 'right';
                        break;
                    case 'Center':
                        style.textAlign = 'center';
                        break;
                }
            }
            return Object.assign(Object.assign({}, style), formatColumnStyle);
        }, {});
    }
    getAlertCellStyle(gridCell, params) {
        const alert = this.adaptableApi.alertApi.internalApi.getAdaptableAlertWithHighlightCell(gridCell.column.columnId, params.node);
        if (alert) {
            const highlightCell = alert.alertDefinition.AlertProperties.HighlightCell;
            if (typeof highlightCell === 'object') {
                return (0, StyleHelper_1.convertAdaptableStyleToCSS)(highlightCell);
            }
            return {
                backgroundColor: UIHelper_1.default.getColorByMessageType(alert.alertDefinition.MessageType),
            };
        }
    }
    getFlashingCellStyle(gridCell, params) {
        var _a;
        const primaryKey = params.node.aggData ? params.node.id : gridCell.primaryKeyValue;
        const flashingCell = this.adaptableApi.flashingCellApi.internalApi.getAdaptableFlashingCellFor(primaryKey, gridCell.column.columnId);
        if (!flashingCell) {
            return {};
        }
        return (0, StyleHelper_1.convertAdaptableStyleToCSS)((_a = (flashingCell.direction === 'up'
            ? flashingCell.flashingCellDefinition.UpChangeStyle
            : flashingCell.direction === 'down'
                ? flashingCell.flashingCellDefinition.DownChangeStyle
                : flashingCell.flashingCellDefinition.NeutralChangeStyle)) !== null && _a !== void 0 ? _a : {});
    }
    getCellHighlightStyle(gridCell, params) {
        const cellHightlight = this.adaptableApi.internalApi
            .getSystemState()
            .HighlightedCells.find((cellHighlightInfo) => {
            return (gridCell.column.columnId === cellHighlightInfo.columnId &&
                cellHighlightInfo.primaryKeyValue === gridCell.primaryKeyValue);
        });
        if (cellHightlight) {
            return (0, StyleHelper_1.convertAdaptableStyleToCSS)(cellHightlight.highlightStyle);
        }
    }
    isColGroupDef(columnDefinition) {
        // @ts-ignore
        return columnDefinition['children'] != null;
    }
}
exports.AgGridColumnAdapter = AgGridColumnAdapter;
