"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.cursorPoint = void 0;
const defaults_1 = require("../../defaults");
const colors_1 = __importDefault(require("../../utils/colors"));
const common_1 = require("../../utils/common");
const MAX_CURSORS = 50;
function paintCursorPoint(series, pt, span) {
    span || (span = pt.querySelector('span'));
    if (!span) {
        return;
    }
    pt.style.background = `${series.color}`;
    span.style.background = series.color || defaults_1.SERIE_COLOR;
    const colorRgba = colors_1.default.parseRgba(series.color) || [256, 256, 256, 0];
    pt.style.boxShadow = `0px 0px 0px 1px rgba(${colorRgba[0]}, ${colorRgba[1]}, ${colorRgba[2]}, 0.5)`;
}
/*
 * Draws HTML points for cursor to transform
 */
function cursorPoint(u, seriesIndex) {
    const serie = u.series[seriesIndex];
    const span = (0, common_1.html)('span');
    const pt = (0, common_1.html)('div', {
        class: 'yagr-point',
        'data-idx': String(seriesIndex),
    }, serie.empty ? undefined : span);
    // @TODO possibly not to render at all. Requires PR into uPlot
    if (serie.empty) {
        pt.style.display = 'none';
        return pt;
    }
    paintCursorPoint(serie, pt, span);
    return pt;
}
exports.cursorPoint = cursorPoint;
function getPointsByIdx(over, idx) {
    return idx === undefined
        ? Array.from(over.querySelectorAll('.yagr-point'))
        : [over.querySelector(`.yagr-point[data-idx="${idx}"]`)];
}
/*
 * Cursor plugin responsible for drawing cursor points and crosshairs,
 * and for syncing cursors.
 */
function CursorPlugin(yagr, opts) {
    var _a, _b, _c;
    const config = yagr.config;
    const processing = config.processing || {};
    const pInterpolation = Boolean(processing.interpolation);
    const iValue = (_a = processing.interpolation) === null || _a === void 0 ? void 0 : _a.value;
    const snapToNulls = opts.snapToValues === false ? false : opts.snapToValues || 'closest';
    const snapToInterpolated = pInterpolation
        ? ((_c = (_b = processing.interpolation) === null || _b === void 0 ? void 0 : _b.snapToValues) !== null && _c !== void 0 ? _c : 'closest')
        : false;
    let mem = {};
    /*
     * This function finds non null value index and returns
     * it's value for drawIdx hook for cursor
     */
    const snapOnValues = (self, seriesIdx, hoveredIdx) => {
        const series = self.series[seriesIdx];
        if (series.scale === defaults_1.DEFAULT_X_SCALE) {
            return hoveredIdx;
        }
        const seriesData = series.$c || self.data[seriesIdx];
        const value = seriesData[hoveredIdx];
        if (pInterpolation && value === iValue) {
            return (0, common_1.findDataIdx)(seriesData, series, hoveredIdx, snapToInterpolated, iValue);
        }
        else if (value === null) {
            return (0, common_1.findDataIdx)(seriesData, series, hoveredIdx, snapToNulls, null);
        }
        return hoveredIdx;
    };
    return {
        showPoints: (idx) => {
            const over = yagr.uplot.over;
            if (!over) {
                return;
            }
            const points = getPointsByIdx(over, idx);
            points.forEach((pt) => {
                pt.style.visibility = 'visible';
            });
        },
        hidePoints: (idx) => {
            const over = yagr.uplot.over;
            if (!over) {
                return;
            }
            const points = getPointsByIdx(over, idx);
            points.forEach((pt) => {
                pt.style.visibility = 'hidden';
            });
        },
        pin: (pinState) => {
            var _a;
            const over = yagr.root.querySelector('.u-over');
            if (!over) {
                return;
            }
            if (pinState) {
                const pointsHolder = document.createElement('div');
                pointsHolder.classList.add('yagr-points-holder');
                over.querySelectorAll('.yagr-point').forEach((elem) => {
                    const newElem = elem.cloneNode(true);
                    pointsHolder.appendChild(newElem);
                    const idx = newElem.dataset['idx'];
                    if (idx) {
                        mem[idx] = newElem;
                    }
                });
                over.appendChild(pointsHolder);
            }
            else {
                mem = {};
                (_a = over.querySelector('.yagr-points-holder')) === null || _a === void 0 ? void 0 : _a.remove();
            }
        },
        updatePoints: () => {
            yagr.root.querySelectorAll('.yagr-point').forEach((pt) => {
                const idx = Number(pt.dataset['idx']);
                if (isNaN(idx)) {
                    return;
                }
                const series = yagr.uplot.series[idx];
                paintCursorPoint(series, pt);
            });
        },
        focus: (serieIdx, focus) => {
            Object.entries(mem).forEach(([idx, item]) => {
                if (serieIdx === null) {
                    item.style.display = focus ? 'block' : 'none';
                    return;
                }
                item.style.display = idx === String(serieIdx) && focus ? 'block' : 'none';
            });
        },
        uplot: {
            opts: (_, uplotOptions) => {
                var _a;
                uplotOptions.cursor = uplotOptions.cursor || {};
                let emptyLines = 0;
                let hiddenLines = 0;
                for (const s of uplotOptions.series) {
                    if (s.empty) {
                        emptyLines += 1;
                    }
                    if (!s.show) {
                        hiddenLines += 1;
                    }
                }
                const totalLines = uplotOptions.series.length - 1;
                const maxCursors = (_a = opts === null || opts === void 0 ? void 0 : opts.maxMarkers) !== null && _a !== void 0 ? _a : MAX_CURSORS;
                uplotOptions.cursor.points = {
                    show: totalLines - emptyLines - hiddenLines <= maxCursors ? cursorPoint : false,
                    size: (u, seriesIdx) => {
                        const serie = u.series[seriesIdx];
                        return ((serie.cursorOptions
                            ? serie.cursorOptions.markersSize
                            : opts === null || opts === void 0 ? void 0 : opts.markersSize) || defaults_1.MARKER_DIAMETER);
                    },
                };
                uplotOptions.cursor.dataIdx = snapOnValues;
            },
            hooks: {
                ...(opts.hideMarkers && {
                    setCursor: (u) => {
                        var _a, _b;
                        const idx = u.cursor.idx;
                        if ((0, common_1.isNil)(idx)) {
                            return;
                        }
                        for (let i = 1; i < u.series.length; i++) {
                            const seriesValue = u.series[i].$c[idx];
                            if (opts.hideMarkers(seriesValue, i)) {
                                (_a = yagr.plugins.cursor) === null || _a === void 0 ? void 0 : _a.hidePoints(i);
                            }
                            else {
                                (_b = yagr.plugins.cursor) === null || _b === void 0 ? void 0 : _b.showPoints(i);
                            }
                        }
                    },
                }),
                init: (u) => {
                    const cX = u.root.querySelector('.u-cursor-x');
                    if (cX) {
                        if (opts.x && opts.x.visible === false) {
                            cX.style.display = 'none';
                        }
                        cX.style.borderRight = (opts.x && opts.x.style) || defaults_1.CURSOR_STYLE;
                    }
                    const cY = u.root.querySelector('.u-cursor-y');
                    if (cY) {
                        if (opts.y && opts.y.visible !== false) {
                            cY.style.borderBottom = opts.y.style || defaults_1.CURSOR_STYLE;
                        }
                        else {
                            cY.style.display = 'none';
                        }
                    }
                },
            },
        },
    };
}
exports.default = CursorPlugin;
