"use strict";
/* eslint-disable complexity */
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CreateUplotOptionsMixin = void 0;
const tooltip_1 = __importDefault(require("../plugins/tooltip/tooltip"));
const cursor_1 = __importDefault(require("../plugins/cursor/cursor"));
const defaults_1 = require("../defaults");
const series_1 = require("../utils/series");
const markers_1 = __importDefault(require("../plugins/markers"));
const scales_1 = require("../utils/scales");
const axes_1 = require("../utils/axes");
const chart_1 = require("../utils/chart");
const types_1 = require("../utils/types");
const plotLines_1 = __importDefault(require("../plugins/plotLines/plotLines"));
function setIfNotSet(hooks, fn) {
    for (const hook of hooks || []) {
        if (hook === fn) {
            return;
        }
    }
    hooks === null || hooks === void 0 ? void 0 : hooks.push(fn);
}
class CreateUplotOptionsMixin {
    initMixin() {
        this._uHooks.onDraw = () => {
            if (this.state.stage === 'listen') {
                return;
            }
            this.state.stage = 'listen';
            this.execHooks('stage', { chart: this, stage: this.state.stage });
            const renderTime = performance.now() - this._startTime;
            this._meta.renderTime = renderTime;
            this.execHooks('load', {
                chart: this,
                meta: this._meta,
            });
        };
        this._uHooks.ready = () => {
            const initTime = performance.now() - this._startTime;
            this._meta.initTime = initTime;
            this.execHooks('inited', {
                chart: this,
                meta: {
                    initTime,
                },
            });
        };
        this._uHooks.drawClear = (u) => {
            const { ctx } = u;
            ctx.save();
            ctx.fillStyle = this.utils.theme.BACKGROUND;
            ctx.fillRect(defaults_1.DEFAULT_CANVAS_PIXEL_RATIO, defaults_1.DEFAULT_CANVAS_PIXEL_RATIO, u.width * defaults_1.DEFAULT_CANVAS_PIXEL_RATIO - 2 * defaults_1.DEFAULT_CANVAS_PIXEL_RATIO, u.height * defaults_1.DEFAULT_CANVAS_PIXEL_RATIO - 2 * defaults_1.DEFAULT_CANVAS_PIXEL_RATIO);
            ctx.restore();
        };
        this._uHooks.setSelect = (u) => {
            const { left, width } = u.select;
            const [_from, _to] = [
                u.posToVal(left, defaults_1.DEFAULT_X_SCALE),
                u.posToVal(left + width, defaults_1.DEFAULT_X_SCALE),
            ];
            const { timeMultiplier = defaults_1.TIME_MULTIPLIER } = this.config.chart || {};
            this.execHooks('onSelect', {
                from: Math.ceil(_from / timeMultiplier),
                to: Math.ceil(_to / timeMultiplier),
                chart: this,
            });
            u.setSelect({ width: 0, height: 0, top: 0, left: 0 }, false);
        };
        this._uHooks.setScale = (_u) => {
            const scales = this.getScales();
            this.execHooks('scaleUpdate', {
                scales,
                chart: this,
            });
        };
    }
    /**
     * @internal
     * @param reOpt If in reOpt cycle (e.g. batch update), then won't reinit hooks.
     * @description Creates uPlot options from Yagr config, sets up plugins. Non idempotent.
     * @returns uPlot options
     */
    createUplotOptions(reOpt = false) {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
        const { config } = this;
        const plugins = [];
        let tooltipInstance = (_a = this.plugins) === null || _a === void 0 ? void 0 : _a.tooltip;
        /** Setting up TooltipPugin */
        if (config.tooltip && config.tooltip.show !== false) {
            if (tooltipInstance) {
                tooltipInstance.updateOptions(config.tooltip);
            }
            else {
                tooltipInstance = (0, tooltip_1.default)(this, config.tooltip);
            }
            plugins.push(tooltipInstance.uplot);
            this.plugins.tooltip = tooltipInstance;
        }
        if (reOpt) {
            this.plugins.plotLines && plugins.push(this.plugins.plotLines.uplot);
        }
        else {
            const plotLinesPluginInstance = (0, plotLines_1.default)(this.config.plotLines || {})(this);
            this.plugins.plotLines = plotLinesPluginInstance;
            plugins.push(plotLinesPluginInstance.uplot);
        }
        Object.entries(config.plugins).forEach(([name, plugin]) => {
            const pluginInstance = plugin(this);
            plugins.push(pluginInstance.uplot);
            Object.assign(this.plugins, { [name]: pluginInstance });
        });
        const chart = config.chart;
        const options = {
            width: this.root.clientWidth,
            height: this.clientHeight,
            title: (_b = config.title) === null || _b === void 0 ? void 0 : _b.text,
            plugins: plugins,
            focus: { alpha: defaults_1.DEFAULT_FOCUS_ALPHA },
            series: [
                {
                    id: defaults_1.DEFAULT_X_SERIE_NAME,
                    $c: config.timeline,
                    scale: defaults_1.DEFAULT_X_SCALE,
                    count: config.timeline.length,
                },
            ],
            ms: chart.timeMultiplier || defaults_1.TIME_MULTIPLIER,
            hooks: config.hooks || {},
        };
        this.state.isEmptyDataSet =
            config.timeline.length === 0 ||
                config.series.length === 0 ||
                config.series.every(({ data }) => data.length === 0);
        /**
         * Setting up cursor - points on cursor, drag behavior, crosshairs
         */
        options.cursor = options.cursor || {};
        options.cursor.points = options.cursor.points || {};
        options.cursor.drag = options.cursor.drag || {
            dist: ((_c = chart.select) === null || _c === void 0 ? void 0 : _c.minWidth) || defaults_1.MIN_SELECTION_WIDTH,
            x: (_d = options.cursor.y) !== null && _d !== void 0 ? _d : true,
            y: (_e = options.cursor.y) !== null && _e !== void 0 ? _e : false,
            setScale: (_g = (_f = chart.select) === null || _f === void 0 ? void 0 : _f.zoom) !== null && _g !== void 0 ? _g : true,
        };
        if (this.utils.sync) {
            options.cursor.sync = options.cursor.sync || {
                key: this.utils.sync.key,
            };
        }
        if (config.cursor) {
            const cPlugin = (0, cursor_1.default)(this, config.cursor);
            this.plugins.cursor = cPlugin;
            plugins.push(cPlugin.uplot);
        }
        const seriesOptions = config.series || [];
        const resultingSeriesOptions = options.series;
        /**
         * Prepare series options
         */
        for (let i = seriesOptions.length - 1; i >= 0; i--) {
            const serie = (0, series_1.configureSeries)(this, seriesOptions[i] || {}, i);
            /**
             * Series with showInGraph: false must not contribute to scale
             * auto-range calculation. uPlot computes dataMin/dataMax from
             * series that have show !== false before any draw hook fires,
             * so the only way to exclude these series from the scale is to
             * give uPlot show: false from the very beginning. We preserve
             * the user-facing visibility through _tempHidden, which the
             * tooltip and other internals already respect.
             */
            if (serie.showInGraph === false && serie.show !== false) {
                serie._tempHidden = true;
                serie.show = false;
            }
            const uIdx = resultingSeriesOptions.push(serie);
            this.state.y2uIdx[serie.id || i] = uIdx - 1;
        }
        /** Setting up markers plugin after default points renderers to be settled */
        const markersPluginInstance = (0, markers_1.default)(this, config);
        plugins.push(markersPluginInstance);
        options.series = resultingSeriesOptions;
        if (!config.scales || Object.keys(config.scales).length === 0) {
            config.scales = {
                x: {},
                y: {},
            };
        }
        /** Setting up scales */
        options.scales = options.scales || {};
        options.scales = (0, scales_1.configureScales)(this, options.scales, config);
        /** Setting up minimal axes */
        options.axes = options.axes || [];
        const axes = options.axes;
        axes.push(...(0, axes_1.configureAxes)(this, config));
        /** Setting up hooks */
        options.hooks = config.hooks || {};
        options.hooks.draw = options.hooks.draw || [];
        options.hooks.ready = options.hooks.ready || [];
        options.hooks.drawClear = options.hooks.drawClear || [];
        options.hooks.setSelect = options.hooks.setSelect || [];
        options.hooks.setScale = options.hooks.setScale || [];
        setIfNotSet(options.hooks.draw, this._uHooks.onDraw);
        setIfNotSet(options.hooks.ready, this._uHooks.ready);
        setIfNotSet(options.hooks.drawClear, this._uHooks.drawClear);
        setIfNotSet(options.hooks.setSelect, this._uHooks.setSelect);
        setIfNotSet(options.hooks.setScale, this._uHooks.setScale);
        options.drawOrder = ((_h = chart.appearance) === null || _h === void 0 ? void 0 : _h.drawOrder)
            ? (_j = chart.appearance) === null || _j === void 0 ? void 0 : _j.drawOrder.filter((key) => key === types_1.DrawOrderKey.Series || key === types_1.DrawOrderKey.Axes)
            : [types_1.DrawOrderKey.Series, types_1.DrawOrderKey.Axes];
        /** Disabling uPlot legend. */
        options.legend = { show: false };
        options.padding = ((_k = config.chart.size) === null || _k === void 0 ? void 0 : _k.padding) || (0, chart_1.getPaddingByAxes)(options);
        /**
         * Pre-initialization  of legend allows to calculate
         * legend's height before actual uPlot instance
         * will be rendered, to avoid blinking height changes
         */
        (_l = this.plugins.legend) === null || _l === void 0 ? void 0 : _l.preInit(this, this.config.legend, options);
        options.height = this.clientHeight;
        options.bands = config.bands;
        this.options = options;
        return options;
    }
}
exports.CreateUplotOptionsMixin = CreateUplotOptionsMixin;
