/**
 * DevExtreme (cjs/viz/sparklines/sparkline.js)
 * Version: 23.2.6 (build 24140-0112)
 * Build date: Sun May 19 2024
 *
 * Copyright (c) 2012 - 2024 Developer Express Inc. ALL RIGHTS RESERVED
 * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
 */
"use strict";
exports.default = void 0;
var _base_sparkline = _interopRequireDefault(require("./base_sparkline"));
var _data_validator = require("../components/data_validator");
var _base_series = require("../series/base_series");
var _utils = require("../core/utils");
var _type = require("../../core/utils/type");
var _component_registrator = _interopRequireDefault(require("../../core/component_registrator"));
var _data_source = require("../core/data_source");

function _interopRequireDefault(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    }
}
const MIN_BAR_WIDTH = 1;
const MAX_BAR_WIDTH = 50;
const DEFAULT_BAR_INTERVAL = 4;
const DEFAULT_CANVAS_WIDTH = 250;
const DEFAULT_CANVAS_HEIGHT = 30;
const DEFAULT_POINT_BORDER = 2;
const ALLOWED_TYPES = {
    line: true,
    spline: true,
    stepline: true,
    area: true,
    steparea: true,
    splinearea: true,
    bar: true,
    winloss: true
};
const _math = Math;
const _abs = _math.abs;
const _round = _math.round;
const _max = _math.max;
const _min = _math.min;
const _isFinite = isFinite;
const _Number = Number;
const _String = String;

function findMinMax(data, valField) {
    const firstItem = data[0] || {};
    const firstValue = firstItem[valField] || 0;
    let min = firstValue;
    let max = firstValue;
    let minIndexes = [0];
    let maxIndexes = [0];
    const dataLength = data.length;
    let value;
    let i;
    for (i = 1; i < dataLength; i++) {
        value = data[i][valField];
        if (value < min) {
            min = value;
            minIndexes = [i]
        } else if (value === min) {
            minIndexes.push(i)
        }
        if (value > max) {
            max = value;
            maxIndexes = [i]
        } else if (value === max) {
            maxIndexes.push(i)
        }
    }
    if (max === min) {
        minIndexes = maxIndexes = []
    }
    return {
        minIndexes: minIndexes,
        maxIndexes: maxIndexes
    }
}

function parseNumericDataSource(data, argField, valField, ignoreEmptyPoints) {
    return (0, _utils.map)(data, (function(dataItem, index) {
        let item = null;
        let isDataNumber;
        let value;
        if (void 0 !== dataItem) {
            item = {};
            isDataNumber = _isFinite(dataItem);
            item[argField] = isDataNumber ? _String(index) : dataItem[argField];
            value = isDataNumber ? dataItem : dataItem[valField];
            item[valField] = null === value ? ignoreEmptyPoints ? void 0 : value : _Number(value);
            item = void 0 !== item[argField] && void 0 !== item[valField] ? item : null
        }
        return item
    }))
}

function parseWinlossDataSource(data, argField, valField, target) {
    return (0, _utils.map)(data, (function(dataItem) {
        const item = {};
        item[argField] = dataItem[argField];
        if (_abs(dataItem[valField] - target) < 1e-4) {
            item[valField] = 0
        } else if (dataItem[valField] > target) {
            item[valField] = 1
        } else {
            item[valField] = -1
        }
        return item
    }))
}

function selectPointColor(color, options, index, pointIndexes) {
    if (index === pointIndexes.first || index === pointIndexes.last) {
        color = options.firstLastColor
    }
    if ((pointIndexes.min || []).indexOf(index) >= 0) {
        color = options.minColor
    }
    if ((pointIndexes.max || []).indexOf(index) >= 0) {
        color = options.maxColor
    }
    return color
}

function createLineCustomizeFunction(pointIndexes, options) {
    return function() {
        const color = selectPointColor(void 0, options, this.index, pointIndexes);
        return color ? {
            visible: true,
            border: {
                color: color
            }
        } : {}
    }
}

function createBarCustomizeFunction(pointIndexes, options, winlossData) {
    return function() {
        const index = this.index;
        const isWinloss = "winloss" === options.type;
        const target = isWinloss ? options.winlossThreshold : 0;
        const value = isWinloss ? winlossData[index][options.valueField] : this.value;
        const positiveColor = isWinloss ? options.winColor : options.barPositiveColor;
        const negativeColor = isWinloss ? options.lossColor : options.barNegativeColor;
        return {
            color: selectPointColor(value >= target ? positiveColor : negativeColor, options, index, pointIndexes)
        }
    }
}
const dxSparkline = _base_sparkline.default.inherit({
    _rootClassPrefix: "dxsl",
    _rootClass: "dxsl-sparkline",
    _themeSection: "sparkline",
    _defaultSize: {
        width: 250,
        height: 30
    },
    _initCore: function() {
        this.callBase();
        this._createSeries()
    },
    _initialChanges: ["DATA_SOURCE"],
    _dataSourceChangedHandler: function() {
        this._requestChange(["UPDATE"])
    },
    _updateWidgetElements: function() {
        this._updateSeries();
        this.callBase()
    },
    _disposeWidgetElements: function() {
        this._series && this._series.dispose();
        this._series = this._seriesGroup = this._seriesLabelGroup = null
    },
    _cleanWidgetElements: function() {
        this._seriesGroup.remove();
        this._seriesLabelGroup.remove();
        this._seriesGroup.clear();
        this._seriesLabelGroup.clear();
        this._series.removeGraphicElements();
        this._series.removePointElements();
        this._series.removeBordersGroup()
    },
    _drawWidgetElements: function() {
        if (this._dataIsLoaded()) {
            this._drawSeries();
            this._drawn()
        }
    },
    _getCorrectCanvas: function() {
        const options = this._allOptions;
        const canvas = this._canvas;
        const halfPointSize = options.pointSize && Math.ceil(options.pointSize / 2) + 2;
        const type = options.type;
        if ("bar" !== type && "winloss" !== type && (options.showFirstLast || options.showMinMax)) {
            return {
                width: canvas.width,
                height: canvas.height,
                left: canvas.left + halfPointSize,
                right: canvas.right + halfPointSize,
                top: canvas.top + halfPointSize,
                bottom: canvas.bottom + halfPointSize
            }
        }
        return canvas
    },
    _prepareOptions: function() {
        const that = this;
        that._allOptions = that.callBase();
        that._allOptions.type = (0, _utils.normalizeEnum)(that._allOptions.type);
        if (!ALLOWED_TYPES[that._allOptions.type]) {
            that._allOptions.type = "line"
        }
    },
    _createHtmlElements: function() {
        this._seriesGroup = this._renderer.g().attr({
            class: "dxsl-series"
        });
        this._seriesLabelGroup = this._renderer.g().attr({
            class: "dxsl-series-labels"
        })
    },
    _createSeries: function() {
        this._series = new _base_series.Series({
            renderer: this._renderer,
            seriesGroup: this._seriesGroup,
            labelsGroup: this._seriesLabelGroup,
            argumentAxis: this._argumentAxis,
            valueAxis: this._valueAxis,
            incidentOccurred: this._incidentOccurred
        }, {
            widgetType: "chart",
            type: "line"
        })
    },
    _updateSeries: function() {
        const singleSeries = this._series;
        this._prepareDataSource();
        const seriesOptions = this._prepareSeriesOptions();
        singleSeries.updateOptions(seriesOptions);
        const groupsData = {
            groups: [{
                series: [singleSeries]
            }]
        };
        groupsData.argumentOptions = {
            type: "bar" === seriesOptions.type ? "discrete" : void 0
        };
        this._simpleDataSource = (0, _data_validator.validateData)(this._simpleDataSource, groupsData, this._incidentOccurred, {
            checkTypeForAllData: false,
            convertToAxisDataType: true,
            sortingMethod: true
        })[singleSeries.getArgumentField()];
        seriesOptions.customizePoint = this._getCustomizeFunction();
        singleSeries.updateData(this._simpleDataSource);
        singleSeries.createPoints();
        this._groupsDataCategories = groupsData.categories
    },
    _optionChangesMap: {
        dataSource: "DATA_SOURCE"
    },
    _optionChangesOrder: ["DATA_SOURCE"],
    _change_DATA_SOURCE: function() {
        this._updateDataSource()
    },
    _prepareDataSource: function() {
        const that = this;
        const options = that._allOptions;
        const argField = options.argumentField;
        const valField = options.valueField;
        const dataSource = that._dataSourceItems() || [];
        const data = parseNumericDataSource(dataSource, argField, valField, that.option("ignoreEmptyPoints"));
        if ("winloss" === options.type) {
            that._winlossDataSource = data;
            that._simpleDataSource = parseWinlossDataSource(data, argField, valField, options.winlossThreshold)
        } else {
            that._simpleDataSource = data
        }
    },
    _prepareSeriesOptions: function() {
        const options = this._allOptions;
        const type = "winloss" === options.type ? "bar" : options.type;
        return {
            visible: true,
            argumentField: options.argumentField,
            valueField: options.valueField,
            color: options.lineColor,
            width: options.lineWidth,
            widgetType: "chart",
            name: "",
            type: type,
            opacity: -1 !== type.indexOf("area") ? this._allOptions.areaOpacity : void 0,
            point: {
                size: options.pointSize,
                symbol: options.pointSymbol,
                border: {
                    visible: true,
                    width: 2
                },
                color: options.pointColor,
                visible: false,
                hoverStyle: {
                    border: {}
                },
                selectionStyle: {
                    border: {}
                }
            },
            border: {
                color: options.lineColor,
                width: options.lineWidth,
                visible: "bar" !== type
            }
        }
    },
    _getCustomizeFunction: function() {
        const that = this;
        const options = that._allOptions;
        const dataSource = that._winlossDataSource || that._simpleDataSource;
        const drawnPointIndexes = that._getExtremumPointsIndexes(dataSource);
        let customizeFunction;
        if ("winloss" === options.type || "bar" === options.type) {
            customizeFunction = createBarCustomizeFunction(drawnPointIndexes, options, that._winlossDataSource)
        } else {
            customizeFunction = createLineCustomizeFunction(drawnPointIndexes, options)
        }
        return customizeFunction
    },
    _getExtremumPointsIndexes: function(data) {
        const that = this;
        const options = that._allOptions;
        const lastIndex = data.length - 1;
        const indexes = {};
        that._minMaxIndexes = findMinMax(data, options.valueField);
        if (options.showFirstLast) {
            indexes.first = 0;
            indexes.last = lastIndex
        }
        if (options.showMinMax) {
            indexes.min = that._minMaxIndexes.minIndexes;
            indexes.max = that._minMaxIndexes.maxIndexes
        }
        return indexes
    },
    _getStick: function() {
        return {
            stick: "bar" !== this._series.type
        }
    },
    _updateRange: function() {
        const series = this._series;
        const type = series.type;
        const isBarType = "bar" === type;
        const isWinlossType = "winloss" === type;
        const rangeData = series.getRangeData();
        const minValue = this._allOptions.minValue;
        const hasMinY = (0, _type.isDefined)(minValue) && _isFinite(minValue);
        const maxValue = this._allOptions.maxValue;
        const hasMaxY = (0, _type.isDefined)(maxValue) && _isFinite(maxValue);
        let argCoef;
        const valCoef = .15 * (rangeData.val.max - rangeData.val.min);
        if (isBarType || isWinlossType || "area" === type) {
            if (0 !== rangeData.val.min) {
                rangeData.val.min -= valCoef
            }
            if (0 !== rangeData.val.max) {
                rangeData.val.max += valCoef
            }
        } else {
            rangeData.val.min -= valCoef;
            rangeData.val.max += valCoef
        }
        if (hasMinY || hasMaxY) {
            if (hasMinY && hasMaxY) {
                rangeData.val.minVisible = _min(minValue, maxValue);
                rangeData.val.maxVisible = _max(minValue, maxValue)
            } else {
                rangeData.val.minVisible = hasMinY ? _Number(minValue) : void 0;
                rangeData.val.maxVisible = hasMaxY ? _Number(maxValue) : void 0
            }
            if (isWinlossType) {
                rangeData.val.minVisible = hasMinY ? _max(rangeData.val.minVisible, -1) : void 0;
                rangeData.val.maxVisible = hasMaxY ? _min(rangeData.val.maxVisible, 1) : void 0
            }
        }
        if (series.getPoints().length > 1) {
            if (isBarType) {
                argCoef = .1 * (rangeData.arg.max - rangeData.arg.min);
                rangeData.arg.min = rangeData.arg.min - argCoef;
                rangeData.arg.max = rangeData.arg.max + argCoef
            }
        }
        rangeData.arg.categories = this._groupsDataCategories;
        this._ranges = rangeData
    },
    _getBarWidth: function(pointsCount) {
        const canvas = this._canvas;
        const intervalWidth = 4 * pointsCount;
        const rangeWidth = canvas.width - canvas.left - canvas.right - intervalWidth;
        let width = _round(rangeWidth / pointsCount);
        if (width < 1) {
            width = 1
        }
        if (width > 50) {
            width = 50
        }
        return width
    },
    _correctPoints: function() {
        const that = this;
        const seriesType = that._allOptions.type;
        const seriesPoints = that._series.getPoints();
        const pointsLength = seriesPoints.length;
        let barWidth;
        let i;
        if ("bar" === seriesType || "winloss" === seriesType) {
            barWidth = that._getBarWidth(pointsLength);
            for (i = 0; i < pointsLength; i++) {
                seriesPoints[i].correctCoordinates({
                    width: barWidth,
                    offset: 0
                })
            }
        }
    },
    _drawSeries: function() {
        const that = this;
        if (that._simpleDataSource.length > 0) {
            that._correctPoints();
            that._series.draw();
            that._seriesGroup.append(that._renderer.root)
        }
    },
    _isTooltipEnabled: function() {
        return !!this._simpleDataSource.length
    },
    _getTooltipData: function() {
        const options = this._allOptions;
        const dataSource = this._winlossDataSource || this._simpleDataSource;
        const tooltip = this._tooltip;
        if (0 === dataSource.length) {
            return {}
        }
        const minMax = this._minMaxIndexes;
        const valueField = options.valueField;
        const first = dataSource[0][valueField];
        const last = dataSource[dataSource.length - 1][valueField];
        const min = (0, _type.isDefined)(minMax.minIndexes[0]) ? dataSource[minMax.minIndexes[0]][valueField] : first;
        const max = (0, _type.isDefined)(minMax.maxIndexes[0]) ? dataSource[minMax.maxIndexes[0]][valueField] : first;
        const formattedFirst = tooltip.formatValue(first);
        const formattedLast = tooltip.formatValue(last);
        const formattedMin = tooltip.formatValue(min);
        const formattedMax = tooltip.formatValue(max);
        const customizeObject = {
            firstValue: formattedFirst,
            lastValue: formattedLast,
            minValue: formattedMin,
            maxValue: formattedMax,
            originalFirstValue: first,
            originalLastValue: last,
            originalMinValue: min,
            originalMaxValue: max,
            valueText: ["Start:", formattedFirst, "End:", formattedLast, "Min:", formattedMin, "Max:", formattedMax]
        };
        if ("winloss" === options.type) {
            customizeObject.originalThresholdValue = options.winlossThreshold;
            customizeObject.thresholdValue = tooltip.formatValue(options.winlossThreshold)
        }
        return customizeObject
    }
});
(0, _utils.map)(["lossColor", "lineColor", "lineWidth", "areaOpacity", "minColor", "maxColor", "barPositiveColor", "barNegativeColor", "winColor", "lessColor", "firstLastColor", "pointSymbol", "pointColor", "pointSize", "type", "argumentField", "valueField", "winlossThreshold", "showFirstLast", "showMinMax", "ignoreEmptyPoints", "minValue", "maxValue"], (function(name) {
    dxSparkline.prototype._optionChangesMap[name] = "OPTIONS"
}));
(0, _component_registrator.default)("dxSparkline", dxSparkline);
var _default = dxSparkline;
exports.default = _default;
dxSparkline.addPlugin(_data_source.plugin);
module.exports = exports.default;
module.exports.default = exports.default;
