"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateColumnType = exports.getNumericValue = exports.handleColumnFunction = exports.extractParameters = exports.extractParameter = exports.extractColumnParameters = exports.extractColumnParameter = exports.evaluateExpressionNode = exports.handleWhereFunction = exports.getGridChangeLog$ = exports.getDataChangeLog$ = exports.isTextSearchCaseInsensitive = exports.getStringValue = exports.getStringValues = void 0;
const tslib_1 = require("tslib");
const ExpressionEvaluationError_1 = require("../../parser/src/ExpressionEvaluationError");
const StringExtensions_1 = tslib_1.__importDefault(require("../Extensions/StringExtensions"));
const operators_1 = require("rxjs/operators");
const toNumber_1 = tslib_1.__importDefault(require("../utils/toNumber"));
const evaluator_1 = require("../../parser/src/evaluator");
// string functions may be case (in)sensitive, see internalApi.isTextComparisonCaseSensitive()
// if case is insensitive, we convert ALL involved strings to lower case
const getStringValues = (context, ...stringArguments) => {
    return (0, exports.isTextSearchCaseInsensitive)(context)
        ? stringArguments.map((string) => string.toLowerCase())
        : stringArguments;
};
exports.getStringValues = getStringValues;
const getStringValue = (context, stringArgument) => {
    return (0, exports.isTextSearchCaseInsensitive)(context) ? stringArgument.toLowerCase() : stringArgument;
};
exports.getStringValue = getStringValue;
const isTextSearchCaseInsensitive = (context) => !context.adaptableApi.expressionApi.useCaseSensitivity();
exports.isTextSearchCaseInsensitive = isTextSearchCaseInsensitive;
// returns an observable which filters the source$ emissions and emits only if the CellDataChangedInfo relates to the given column
// optionally, if a filter function (where clause) is provided, it is also evaluated
const getDataChangeLog$ = (context, columnNameFilter) => {
    let dataChangeLog$ = context.adaptableApi.internalApi.getDataService().cellDataChangeLog$;
    // filter only the given column changes
    dataChangeLog$ = dataChangeLog$.pipe((0, operators_1.filter)((dataChangeLog) => dataChangeLog.column.columnId === columnNameFilter));
    // filter based on the WHERE clause
    if (context.filterFn) {
        dataChangeLog$ = dataChangeLog$.pipe((0, operators_1.filter)((value) => {
            return context.filterFn(value.rowNode);
        }));
    }
    return dataChangeLog$;
};
exports.getDataChangeLog$ = getDataChangeLog$;
const getGridChangeLog$ = (context, rowChangeType) => {
    const gridChangeLog$ = context.adaptableApi.internalApi.getDataService().rowDataChangeLog$;
    let gridChangeStream$ = gridChangeLog$.pipe((0, operators_1.filter)((rowDataChangedInfo) => rowDataChangedInfo.rowTrigger === rowChangeType));
    // filter based on the WHERE clause
    if (context.filterFn) {
        gridChangeStream$ = gridChangeStream$.pipe((0, operators_1.filter)((value) => value.rowNodes.some((node) => context.filterFn(node))));
    }
    return gridChangeStream$;
};
exports.getGridChangeLog$ = getGridChangeLog$;
const handleWhereFunction = (args, context) => {
    const reactiveExpressionNode = args[0];
    const whereClauseExpressionNode = args[1];
    const filterFn = (rowNode) => {
        // whereClauseResult
        return (0, evaluator_1.evaluateNode)(whereClauseExpressionNode, {
            node: rowNode,
            functions: context.whereClauseFunctions,
            evaluateCustomQueryVariable: context.adaptableApi.internalApi.getQueryLanguageService().evaluateCustomQueryVariable,
            ...context.adaptableApi.internalApi.buildBaseContext(),
        });
    };
    // observableExpressionResult
    return (0, exports.evaluateExpressionNode)(reactiveExpressionNode, context, filterFn);
};
exports.handleWhereFunction = handleWhereFunction;
const evaluateExpressionNode = (expressionNode, context, filterFn = context.filterFn) => {
    return (0, evaluator_1.evaluateNode)(expressionNode, {
        node: context.node,
        functions: context.functions,
        filterFn,
        evaluateCustomQueryVariable: context.adaptableApi.internalApi.getQueryLanguageService().evaluateCustomQueryVariable,
        ...context.adaptableApi.internalApi.buildBaseContext(),
    });
};
exports.evaluateExpressionNode = evaluateExpressionNode;
const extractColumnParameter = (consumingFunctionName, args) => {
    return (0, exports.extractParameter)(consumingFunctionName, 'config', ['COL'], args);
};
exports.extractColumnParameter = extractColumnParameter;
const extractColumnParameters = (consumingFunctionName, args) => {
    return (0, exports.extractParameters)(consumingFunctionName, 'config', ['COL'], args);
};
exports.extractColumnParameters = extractColumnParameters;
const extractParameter = (consumingFunctionName, allowedType, allowedOperands, args, config) => {
    const parameters = (0, exports.extractParameters)(consumingFunctionName, allowedType, allowedOperands, args, config);
    if (parameters == undefined) {
        return;
    }
    if (parameters.length > 1) {
        throw new ExpressionEvaluationError_1.ExpressionEvaluationError(consumingFunctionName, `expects only 1 argument of type '${[...new Set(parameters.map((op) => op.name))].join(`' / '`)}'`);
    }
    return parameters[0];
};
exports.extractParameter = extractParameter;
const extractParameters = (consumingFunctionName, allowedType, allowedOperands, args, config) => {
    const { isOptional } = config ?? {};
    const result = args.filter((arg) => arg?.type === allowedType && allowedOperands.includes(arg?.name));
    if (isOptional && !result.length) {
        return;
    }
    if (!result.length) {
        throw new ExpressionEvaluationError_1.ExpressionEvaluationError(consumingFunctionName, `expects an argument of type '${allowedOperands.join(`' / '`)}'`);
    }
    return result;
};
exports.extractParameters = extractParameters;
const handleColumnFunction = (args, context) => {
    if (StringExtensions_1.default.IsNullOrEmpty(args[0])) {
        throw new ExpressionEvaluationError_1.ExpressionEvaluationError('COL', `no column name is provided`);
    }
    validateColumnId(args[0], context.adaptableApi);
    const result = {
        type: 'config',
        name: 'COL',
        value: args[0],
    };
    return result;
};
exports.handleColumnFunction = handleColumnFunction;
const getNumericValue = (input, returnRawValue) => {
    if (typeof input === 'number') {
        return input;
    }
    const numericValue = (0, toNumber_1.default)(input);
    if (returnRawValue === true) {
        return numericValue;
    }
    return isNaN(numericValue) ? 0 : numericValue;
};
exports.getNumericValue = getNumericValue;
const validateColumnType = (columnId, validColumnTypes, consumingFunction, api) => {
    const columnType = api.columnApi.getColumnDataTypeForColumnId(columnId);
    if (!validColumnTypes.some((validType) => validType === columnType)) {
        throw new ExpressionEvaluationError_1.ExpressionEvaluationError(consumingFunction, `expects a column of type ${validColumnTypes.join(' or ')}`);
    }
    return columnType;
};
exports.validateColumnType = validateColumnType;
const validateColumnId = (columnId, api) => {
    const column = api.columnApi.getColumnWithColumnId(columnId);
    if (!column) {
        throw new ExpressionEvaluationError_1.ExpressionEvaluationError('', `Column name "${columnId}" is not found`);
    }
    if (!column.queryable) {
        throw new ExpressionEvaluationError_1.ExpressionEvaluationError('', `Column name "${columnId}" is not queryable`);
    }
};
