"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CalculatedColumnInternalApi = void 0;
const tslib_1 = require("tslib");
const ApiBase_1 = require("../Implementation/ApiBase");
const ObjectFactory_1 = require("../../Utilities/ObjectFactory");
const ArrayExtensions_1 = tslib_1.__importDefault(require("../../Utilities/Extensions/ArrayExtensions"));
const StringExtensions_1 = tslib_1.__importDefault(require("../../Utilities/Extensions/StringExtensions"));
const AdaptableColumn_1 = require("../../AdaptableState/Common/AdaptableColumn");
class CalculatedColumnInternalApi extends ApiBase_1.ApiBase {
    /**
     * Returns all the references in the AdaptableState of the given CalculatedColumn
     * @param calculatedColumn CalculatedColumn to be checked
     */
    getCalculatedColumnModuleReferences(calculatedColumn) {
        const references = [];
        this.getAdaptableInternalApi()
            .getModules()
            .forEach((module) => {
            if (module
                .getModuleCalculatedColumnReferences()
                .some((moduleReference) => moduleReference.Uuid === calculatedColumn.Uuid)) {
                references.push(module.moduleInfo.FriendlyName);
            }
        });
        return references;
    }
    /**
     * Returns all Calculated Columns whose Expression contains the ColumnId
     * @param columnId ColumnId to check
     */
    getCalculatedColumnsReferencingColumnId(columnId) {
        const calcColumns = [];
        this.getCalculatedColumnApi()
            .getCalculatedColumns()
            .forEach((calculatedColumn) => {
            if (this.getExpressionApi().internalApi.isColumnReferencedInExpression(columnId, this.getExpressionApi().getAdaptableQueryExpression(calculatedColumn.Query))) {
                calcColumns.push(calculatedColumn);
            }
        });
        return calcColumns;
    }
    /**
     * Gets any ColumnIds referenced in a Calculated Column
     * @param calculatedColumn Calculated Column to check
     */
    getReferencedColumnIdsForCalculatedColumn(calculatedColumn) {
        const columnIds = this.getExpressionApi().getColumnsFromExpression(this.getExpressionApi().getAdaptableQueryExpression(calculatedColumn.Query));
        return columnIds;
    }
    /**
     * Gets any ColumnIds referenced in a Calculated Column
     * @param calculatedColumnId CalculatedColumnId to check
     */
    getReferencedColumnIdsForCalculatedColumnId(calculatedColumnId) {
        const calculatedColumn = this.getCalculatedColumnApi()
            .getCalculatedColumns()
            .find((cc) => cc.ColumnId == calculatedColumnId);
        if (calculatedColumn) {
            return this.getReferencedColumnIdsForCalculatedColumn(calculatedColumn);
        }
    }
    getCalculatedColumnsDependentOnColumn(column) {
        const calculatedColumns = this.getCalculatedColumnApi().getCalculatedColumns();
        return calculatedColumns
            .filter((calculatedColumn) => {
            const dependentColumns = this.getReferencedColumnIdsForCalculatedColumnId(calculatedColumn.ColumnId);
            return dependentColumns.includes(column.columnId);
        })
            .map((calculatedColumn) => calculatedColumn.ColumnId);
    }
    isCumulativeAggregatedExpression(input) {
        return !!this.getAdaptableApi()
            .internalApi.getQueryLanguageService()
            .getNodesFromExpression(input, 'CUMUL')?.length;
    }
    isQuantileAggregatedExpression(input) {
        return !!this.getAdaptableApi()
            .internalApi.getQueryLanguageService()
            .getNodesFromExpression(input, 'QUANT')?.length;
    }
    getExpressionFromCalculatedColumn(calculatedColumn) {
        return (calculatedColumn.Query.ScalarExpression ?? calculatedColumn.Query.AggregatedScalarExpression);
    }
    getColDefsForCalculatedColumns() {
        const defaultSpecialColumnSettings = this.getGridApi().internalApi.deriveSpecialColumnSettingsFromAgGridDefaultColDef();
        const defaultCalculatedColumnSettings = (0, ObjectFactory_1.CreateEmptyCalculatedColumn)(defaultSpecialColumnSettings).CalculatedColumnSettings;
        return this.getCalculatedColumnApi()
            .getCalculatedColumns()
            .map((calculatedColumn) => {
            const calculatedColumnSettings = {
                ...defaultCalculatedColumnSettings,
                ...calculatedColumn.CalculatedColumnSettings,
            };
            if (!calculatedColumnSettings.DataType) {
                calculatedColumnSettings.DataType = this.getAdaptableInternalApi()
                    .getCalculatedColumnExpressionService()
                    .getCalculatedColumnDataType(calculatedColumn.Query);
            }
            const columnTypes = [AdaptableColumn_1.CALCULATED_COLUMN_TYPE];
            if (ArrayExtensions_1.default.IsNotNullOrEmpty(calculatedColumnSettings.ColumnTypes)) {
                columnTypes.push(...calculatedColumnSettings.ColumnTypes);
            }
            const isExternalEvaluation = !this.getExpressionApi().internalApi.evaluateExpressionInAdaptableQL('CalculatedColumn', calculatedColumn, this.getExpressionApi().getAdaptableQueryExpression(calculatedColumn.Query));
            const valueGetter = (params) => {
                if (isExternalEvaluation) {
                    return params.data?.[calculatedColumn.ColumnId];
                }
                // if the grid data is NOT client side, we can aggregate only simple scalar expression (which depend on row data, not on other rows)
                if (this.getGridApi().getAgGridRowModelType() !== 'clientSide' &&
                    StringExtensions_1.default.IsNotNullOrEmpty(calculatedColumn.Query.AggregatedScalarExpression)) {
                    return params.data?.[calculatedColumn.ColumnId];
                }
                return this.getAdaptableInternalApi()
                    .getCalculatedColumnExpressionService()
                    .evaluateCalculatedColumnQuery(calculatedColumn, params.node);
            };
            const newColDef = {
                headerName: calculatedColumn.FriendlyName
                    ? calculatedColumn.FriendlyName
                    : calculatedColumn.ColumnId,
                colId: calculatedColumn.ColumnId,
                hide: false,
                editable: false,
                width: calculatedColumnSettings.Width,
                enableValue: calculatedColumnSettings.Aggregatable,
                filter: calculatedColumnSettings.Filterable,
                floatingFilter: calculatedColumnSettings.Filterable,
                resizable: calculatedColumnSettings.Resizable,
                enableRowGroup: calculatedColumnSettings.Groupable,
                sortable: calculatedColumnSettings.Sortable,
                enablePivot: calculatedColumnSettings.Pivotable,
                suppressHeaderMenuButton: calculatedColumnSettings.SuppressMenu,
                suppressMovable: calculatedColumnSettings.SuppressMovable,
                type: columnTypes,
                cellDataType: calculatedColumnSettings.DataType,
                valueGetter,
            };
            if (calculatedColumnSettings.ShowToolTip != null &&
                calculatedColumnSettings.ShowToolTip == true) {
                newColDef.tooltipValueGetter = () => {
                    return this.getAdaptableInternalApi().getAdaptableQueryExpressionText(calculatedColumn.Query);
                };
            }
            if (calculatedColumnSettings.HeaderToolTip) {
                newColDef.headerTooltip = calculatedColumnSettings.HeaderToolTip;
            }
            this.logInfo('Setting up Calculated Column: ' + calculatedColumn.ColumnId);
            return newColDef;
        });
    }
    validateDeletedCalculatedColumn(calculatedColumn) {
        const calculatedColumnReferences = this.getCalculatedColumnModuleReferences(calculatedColumn);
        if (calculatedColumnReferences.length) {
            const alert = {
                alertType: 'generic',
                header: 'CalculatedColumn could not be deleted',
                message: `It is still referenced in the following modules: ${calculatedColumnReferences.join(', ')}`,
                alertDefinition: (0, ObjectFactory_1.CreateInternalAlertDefinitionForMessages)('Error'),
            };
            this.getAlertApi().displayAdaptableAlertNotification(alert);
            return false;
        }
        else {
            return true;
        }
    }
}
exports.CalculatedColumnInternalApi = CalculatedColumnInternalApi;
