"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CalculatedColumnExpressionService = void 0;
const ModuleConstants_1 = require("../Constants/ModuleConstants");
const AggregatedScalarLiveValue_1 = require("./AggregatedScalarLiveValue");
class CalculatedColumnExpressionService {
    constructor(adaptableApi) {
        this.adaptableApi = adaptableApi;
        this.aggregatedScalarLiveValuesMap = new Map();
        this.adaptableApi = adaptableApi;
        this.adaptableApi.internalApi
            .getDataService()
            .on('CellDataChanged', (cellDataChangedInfo) => {
            if (cellDataChangedInfo.trigger === 'aggChange') {
                // do NOT handle changes on group rows
                return;
            }
            const refreshedCalculatedColumns = [];
            this.aggregatedScalarLiveValuesMap.forEach((aggregatedScalarLiveValue, calculatedColumnId) => {
                const calculatedColumn = this.adaptableApi.calculatedColumnApi.getCalculatedColumnById(calculatedColumnId);
                const columnDependencies = this.adaptableApi.calculatedColumnApi.internalApi.getReferencedColumnIdsForCalculatedColumn(calculatedColumn);
                if (columnDependencies.includes(cellDataChangedInfo.column.columnId)) {
                    aggregatedScalarLiveValue.refresh();
                    refreshedCalculatedColumns.push(calculatedColumn.ColumnId);
                }
            });
            if (refreshedCalculatedColumns.length) {
                this.adaptableApi.gridApi.refreshCells(null, refreshedCalculatedColumns);
            }
        });
        this.adaptableApi.eventApi.on('GridDataChanged', () => {
            const refreshedCalculatedColumns = [];
            this.aggregatedScalarLiveValuesMap.forEach((aggregatedScalarLiveValue, calculatedColumnId) => {
                const calculatedColumn = this.adaptableApi.calculatedColumnApi.getCalculatedColumnById(calculatedColumnId);
                aggregatedScalarLiveValue.refresh();
                refreshedCalculatedColumns.push(calculatedColumn.ColumnId);
            });
            if (refreshedCalculatedColumns.length) {
                this.adaptableApi.gridApi.refreshCells(null, refreshedCalculatedColumns);
            }
        });
    }
    destroy() {
        this.aggregatedScalarLiveValuesMap.clear();
        this.aggregatedScalarLiveValuesMap = null;
    }
    getCalculatedColumnDataType(calculatedColumnQuery) {
        try {
            if (calculatedColumnQuery.AggregatedScalarExpression) {
                // currently AggregatedScalarExpression support only numerical values
                // TODO AFL try to derive the type from the aggregatedColumn?
                // we definitely don't want to aggregate everything only to get the data type
                return 'Number';
            }
            let firstRowNode = this.adaptableApi.gridApi.getFirstRowNode();
            let firstRowValue = this.adaptableApi.internalApi
                .getQueryLanguageService()
                .evaluateScalarExpression(calculatedColumnQuery.ScalarExpression, ModuleConstants_1.CalculatedColumnModuleId, firstRowNode);
            if (firstRowValue instanceof Date) {
                return 'Date';
            }
            if (typeof firstRowValue === 'boolean') {
                return 'Boolean';
            }
            if (typeof firstRowValue === 'string') {
                return 'String';
            }
            if (typeof firstRowValue === 'number') {
                return 'Number';
            }
            if (Array.isArray(firstRowValue)) {
                return 'NumberArray';
            }
        }
        catch (e) {
            this.adaptableApi.logError(`Invalid CalculatedColumn expression ${this.adaptableApi.expressionApi.getAdaptableQueryExpression(calculatedColumnQuery)} :: ${e}`);
            return 'Number';
        }
    }
    isCalculatedColumnQueryValid(calculatedColumnQuery) {
        if (calculatedColumnQuery.ScalarExpression) {
            try {
                // TODO AFL add a cached validation for ScalarExpression, just like for all the other types
                let firstRowNode = this.adaptableApi.gridApi.getFirstRowNode();
                this.adaptableApi.internalApi
                    .getQueryLanguageService()
                    .evaluateScalarExpression(calculatedColumnQuery.ScalarExpression, ModuleConstants_1.CalculatedColumnModuleId, firstRowNode);
                return true;
            }
            catch (e) {
                // no logging as this method is used only in the UI
                return false;
            }
        }
        if (calculatedColumnQuery.AggregatedScalarExpression) {
            const validationResult = this.adaptableApi.expressionApi.isValidAggregatedScalarExpression(calculatedColumnQuery.AggregatedScalarExpression, ModuleConstants_1.CalculatedColumnModuleId);
            return validationResult;
        }
        // if query has neither a ScalarExpression nor an AggregatedScalarExpression => it can only be false
        return false;
    }
    evaluateCalculatedColumnQuery(calculatedColumn, rowNode) {
        var _a, _b, _c, _d, _e;
        try {
            if (this.adaptableApi.gridApi.isGroupRowNode(rowNode)) {
                return undefined;
            }
            // no validation here, this function has to be as performant as possible
            if ((_a = calculatedColumn === null || calculatedColumn === void 0 ? void 0 : calculatedColumn.Query) === null || _a === void 0 ? void 0 : _a.ScalarExpression) {
                return this.adaptableApi.internalApi
                    .getQueryLanguageService()
                    .evaluateScalarExpression(calculatedColumn.Query.ScalarExpression, ModuleConstants_1.CalculatedColumnModuleId, rowNode);
            }
            if ((_b = calculatedColumn === null || calculatedColumn === void 0 ? void 0 : calculatedColumn.Query) === null || _b === void 0 ? void 0 : _b.AggregatedScalarExpression) {
                const aggregatedScalarLiveValue = this.aggregatedScalarLiveValuesMap.get(calculatedColumn.Uuid);
                return aggregatedScalarLiveValue === null || aggregatedScalarLiveValue === void 0 ? void 0 : aggregatedScalarLiveValue.getAggregatedValueForRow(rowNode);
            }
        }
        catch (error) {
            this.adaptableApi.logError(`Invalid CalculatedColumn expression ${(_d = (_c = calculatedColumn === null || calculatedColumn === void 0 ? void 0 : calculatedColumn.Query) === null || _c === void 0 ? void 0 : _c.ScalarExpression) !== null && _d !== void 0 ? _d : (_e = calculatedColumn === null || calculatedColumn === void 0 ? void 0 : calculatedColumn.Query) === null || _e === void 0 ? void 0 : _e.AggregatedScalarExpression} :: ${error}`);
            return null;
        }
    }
    createAggregatedScalarLiveValue(calculatedColumn) {
        var _a, _b, _c;
        // if there is already an aggregated scalar, delete it (possible when editing)
        this.destroyAggregatedScalarLiveValue(calculatedColumn);
        if ((_a = calculatedColumn.Query) === null || _a === void 0 ? void 0 : _a.AggregatedScalarExpression) {
            try {
                const aggregatedScalarLiveValue = new AggregatedScalarLiveValue_1.AggregatedScalarLiveValue({
                    aggregatedScalarExpression: (_b = calculatedColumn.Query) === null || _b === void 0 ? void 0 : _b.AggregatedScalarExpression,
                }, ModuleConstants_1.CalculatedColumnModuleId, this.adaptableApi);
                this.aggregatedScalarLiveValuesMap.set(calculatedColumn.Uuid, aggregatedScalarLiveValue);
            }
            catch (e) {
                this.adaptableApi.logError(`Creating CalculatedColumn ('${(_c = calculatedColumn.Query) === null || _c === void 0 ? void 0 : _c.AggregatedScalarExpression}') failed!`, e.message);
            }
        }
    }
    destroyAggregatedScalarLiveValue(calculatedColumn) {
        this.aggregatedScalarLiveValuesMap.delete(calculatedColumn.Uuid);
    }
}
exports.CalculatedColumnExpressionService = CalculatedColumnExpressionService;
