import { __assign } from "tslib";
import { bin as d3Bin, extent as d3Extent, sum as d3Sum, min as d3Min, max as d3Max, range as d3Range, } from 'd3-array';
import { scaleLinear as d3ScaleLinear } from 'd3-scale';
import { DataVizPalette, getColorFromToken, getNextColor } from '../../utilities/colors';
import { GaugeChartVariant } from '../GaugeChart/index';
import { findNumericMinMaxOfY } from '../../utilities/utilities';
import { isArrayOfType, isArrayOrTypedArray, isDate, isDateArray, isNumberArray, isLineData, } from '@fluentui/chart-utilities';
import { timeParse } from 'd3-time-format';
import { curveCardinal as d3CurveCardinal } from 'd3-shape';
var dashOptions = {
    dot: {
        strokeDasharray: '1, 5',
        strokeLinecap: 'round',
        strokeWidth: '2',
        lineBorderWidth: '4',
    },
    dash: {
        strokeDasharray: '5, 5',
        strokeLinecap: 'butt',
        strokeWidth: '2',
        lineBorderWidth: '4',
    },
    longdash: {
        strokeDasharray: '10, 5',
        strokeLinecap: 'butt',
        strokeWidth: '2',
        lineBorderWidth: '4',
    },
    dashdot: {
        strokeDasharray: '5, 5, 1, 5',
        strokeLinecap: 'butt',
        strokeWidth: '2',
        lineBorderWidth: '4',
    },
    longdashdot: {
        strokeDasharray: '10, 5, 1, 5',
        strokeLinecap: 'butt',
        strokeWidth: '2',
        lineBorderWidth: '4',
    },
    solid: {
        strokeDasharray: '0',
        strokeLinecap: 'butt',
        strokeWidth: '2',
        lineBorderWidth: '4',
    },
};
var isMonth = function (possiblyMonthValue) {
    var parseFullMonth = timeParse('%B');
    var parseShortMonth = timeParse('%b');
    return parseFullMonth(possiblyMonthValue) !== null || parseShortMonth(possiblyMonthValue) !== null;
};
export var isMonthArray = function (data) {
    return isArrayOfType(data, isMonth);
};
var getLegend = function (series, index) {
    return series.name || "Series ".concat(index + 1);
};
function getTitles(layout) {
    var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
    var titles = {
        chartTitle: typeof (layout === null || layout === void 0 ? void 0 : layout.title) === 'string' ? layout.title : (_b = (_a = layout === null || layout === void 0 ? void 0 : layout.title) === null || _a === void 0 ? void 0 : _a.text) !== null && _b !== void 0 ? _b : '',
        xAxisTitle: typeof ((_c = layout === null || layout === void 0 ? void 0 : layout.xaxis) === null || _c === void 0 ? void 0 : _c.title) === 'string' ? (_d = layout === null || layout === void 0 ? void 0 : layout.xaxis) === null || _d === void 0 ? void 0 : _d.title : (_g = (_f = (_e = layout === null || layout === void 0 ? void 0 : layout.xaxis) === null || _e === void 0 ? void 0 : _e.title) === null || _f === void 0 ? void 0 : _f.text) !== null && _g !== void 0 ? _g : '',
        yAxisTitle: typeof ((_h = layout === null || layout === void 0 ? void 0 : layout.yaxis) === null || _h === void 0 ? void 0 : _h.title) === 'string' ? (_j = layout === null || layout === void 0 ? void 0 : layout.yaxis) === null || _j === void 0 ? void 0 : _j.title : (_m = (_l = (_k = layout === null || layout === void 0 ? void 0 : layout.yaxis) === null || _k === void 0 ? void 0 : _k.title) === null || _l === void 0 ? void 0 : _l.text) !== null && _m !== void 0 ? _m : '',
    };
    return titles;
}
export var correctYearMonth = function (xValues) {
    var presentYear = new Date().getFullYear();
    if (xValues.length > 0 && Array.isArray(xValues[0])) {
        throw new Error('updateXValues:: 2D array not supported');
    }
    var dates = xValues.map(function (possiblyMonthValue) {
        var parsedDate = "".concat(possiblyMonthValue, " 01, ").concat(presentYear);
        return isDate(parsedDate) ? new Date(parsedDate) : null;
    });
    for (var i = dates.length - 1; i > 0; i--) {
        var currentMonth = dates[i].getMonth();
        var previousMonth = dates[i - 1].getMonth();
        var currentYear = dates[i].getFullYear();
        var previousYear = dates[i - 1].getFullYear();
        if (previousMonth >= currentMonth) {
            dates[i - 1].setFullYear(dates[i].getFullYear() - 1);
        }
        else if (previousYear > currentYear) {
            dates[i - 1].setFullYear(currentYear);
        }
    }
    xValues = xValues.map(function (month, index) {
        return "".concat(month, " 01, ").concat(dates[index].getFullYear());
    });
    return xValues;
};
export var getColor = function (legendLabel, colorMap, isDarkTheme) {
    if (!colorMap.current.has(legendLabel)) {
        var nextColor = getNextColor(colorMap.current.size + 1, 0, isDarkTheme);
        colorMap.current.set(legendLabel, nextColor);
        return nextColor;
    }
    return colorMap.current.get(legendLabel);
};
var usesSecondaryYScale = function (series) {
    return series.yaxis === 'y2';
};
var getSecondaryYAxisValues = function (data, layout, maxAllowedMinY, minAllowedMaxY) {
    var _a, _b, _c, _d;
    var containsSecondaryYAxis = false;
    var yMinValue;
    var yMaxValue;
    data.forEach(function (series) {
        if (usesSecondaryYScale(series)) {
            containsSecondaryYAxis = true;
            var yValues = series.y;
            if (yValues) {
                yMinValue = Math.min.apply(Math, yValues);
                yMaxValue = Math.max.apply(Math, yValues);
            }
        }
    });
    if (!containsSecondaryYAxis) {
        return {};
    }
    if (typeof yMinValue === 'number' && typeof maxAllowedMinY === 'number') {
        yMinValue = Math.min(yMinValue, maxAllowedMinY);
    }
    if (typeof yMaxValue === 'number' && typeof minAllowedMaxY === 'number') {
        yMaxValue = Math.max(yMaxValue, minAllowedMaxY);
    }
    if ((_a = layout === null || layout === void 0 ? void 0 : layout.yaxis2) === null || _a === void 0 ? void 0 : _a.range) {
        yMinValue = layout.yaxis2.range[0];
        yMaxValue = layout.yaxis2.range[1];
    }
    return {
        secondaryYAxistitle: typeof ((_b = layout === null || layout === void 0 ? void 0 : layout.yaxis2) === null || _b === void 0 ? void 0 : _b.title) === 'string'
            ? layout.yaxis2.title
            : typeof ((_d = (_c = layout === null || layout === void 0 ? void 0 : layout.yaxis2) === null || _c === void 0 ? void 0 : _c.title) === null || _d === void 0 ? void 0 : _d.text) === 'string'
                ? layout.yaxis2.title.text
                : undefined,
        secondaryYScaleOptions: {
            yMinValue: yMinValue,
            yMaxValue: yMaxValue,
        },
    };
};
export var transformPlotlyJsonToDonutProps = function (input, colorMap, isDarkTheme) {
    var _a, _b, _c, _d, _e, _f, _g;
    var firstData = input.data[0];
    var mapLegendToDataPoint = {};
    (_a = firstData.labels) === null || _a === void 0 ? void 0 : _a.forEach(function (label, index) {
        var _a;
        var color = getColor(label, colorMap, isDarkTheme);
        //ToDo how to handle string data?
        var value = typeof ((_a = firstData.values) === null || _a === void 0 ? void 0 : _a[index]) === 'number' ? firstData.values[index] : 1;
        if (!mapLegendToDataPoint[label]) {
            mapLegendToDataPoint[label] = {
                legend: label,
                data: value,
                color: color,
            };
        }
        else {
            mapLegendToDataPoint[label].data += value;
        }
    });
    var width = (_c = (_b = input.layout) === null || _b === void 0 ? void 0 : _b.width) !== null && _c !== void 0 ? _c : 440;
    var height = (_e = (_d = input.layout) === null || _d === void 0 ? void 0 : _d.height) !== null && _e !== void 0 ? _e : 220;
    var hideLabels = firstData.textinfo
        ? !['value', 'percent', 'label+percent'].includes(firstData.textinfo)
        : false;
    var donutMarginHorizontal = hideLabels ? 0 : 80;
    var donutMarginVertical = 40 + (hideLabels ? 0 : 40);
    var innerRadius = firstData.hole
        ? firstData.hole * (Math.min(width - donutMarginHorizontal, height - donutMarginVertical) / 2)
        : 0;
    var chartTitle = getTitles(input.layout).chartTitle;
    return {
        data: {
            chartTitle: chartTitle,
            chartData: Object.values(mapLegendToDataPoint),
        },
        hideLegend: ((_f = input.layout) === null || _f === void 0 ? void 0 : _f.showlegend) === false ? true : false,
        width: (_g = input.layout) === null || _g === void 0 ? void 0 : _g.width,
        height: height,
        innerRadius: innerRadius,
        hideLabels: hideLabels,
        showLabelsInPercent: firstData.textinfo ? ['percent', 'label+percent'].includes(firstData.textinfo) : true,
    };
};
export var transformPlotlyJsonToVSBCProps = function (input, colorMap, isDarkTheme, fallbackVSBC) {
    var _a, _b, _c;
    var mapXToDataPoints = {};
    var yMaxValue = 0;
    var secondaryYAxisValues = getSecondaryYAxisValues(input.data, input.layout);
    input.data.forEach(function (series, index1) {
        var _a;
        (_a = series.x) === null || _a === void 0 ? void 0 : _a.forEach(function (x, index2) {
            var _a, _b;
            if (!mapXToDataPoints[x]) {
                mapXToDataPoints[x] = { xAxisPoint: x, chartData: [], lineData: [] };
            }
            var legend = getLegend(series, index1);
            var yVal = (_b = (_a = series.y) === null || _a === void 0 ? void 0 : _a[index2]) !== null && _b !== void 0 ? _b : 0;
            if (series.type === 'bar') {
                var color = getColor(legend, colorMap, isDarkTheme);
                mapXToDataPoints[x].chartData.push({
                    legend: legend,
                    data: yVal,
                    color: color,
                });
                yMaxValue = Math.max(yMaxValue, yVal);
            }
            else if (series.type === 'scatter' || isLineData(series) || !!fallbackVSBC) {
                var color = getColor(legend, colorMap, isDarkTheme);
                var lineOptions = getLineOptions(series.line);
                mapXToDataPoints[x].lineData.push(__assign(__assign({ legend: legend, y: yVal, color: color }, (lineOptions ? { lineOptions: lineOptions } : {})), { useSecondaryYScale: usesSecondaryYScale(series) }));
                if (!usesSecondaryYScale(series)) {
                    yMaxValue = Math.max(yMaxValue, yVal);
                }
            }
        });
    });
    var _d = getTitles(input.layout), chartTitle = _d.chartTitle, xAxisTitle = _d.xAxisTitle, yAxisTitle = _d.yAxisTitle;
    return __assign(__assign({ data: Object.values(mapXToDataPoints), width: (_a = input.layout) === null || _a === void 0 ? void 0 : _a.width, height: (_c = (_b = input.layout) === null || _b === void 0 ? void 0 : _b.height) !== null && _c !== void 0 ? _c : 350, barWidth: 'auto', yMaxValue: yMaxValue, chartTitle: chartTitle, xAxisTitle: xAxisTitle, yAxisTitle: yAxisTitle, mode: 'plotly' }, secondaryYAxisValues), { hideTickOverlap: true });
};
export var transformPlotlyJsonToGVBCProps = function (input, colorMap, isDarkTheme) {
    var _a, _b, _c;
    var mapXToDataPoints = {};
    var secondaryYAxisValues = getSecondaryYAxisValues(input.data, input.layout, 0, 0);
    input.data.forEach(function (series, index1) {
        var _a;
        (_a = series.x) === null || _a === void 0 ? void 0 : _a.forEach(function (x, xIndex) {
            var _a, _b;
            if (!mapXToDataPoints[x]) {
                mapXToDataPoints[x] = { name: x.toString(), series: [] };
            }
            if (series.type === 'bar') {
                var legend_1 = getLegend(series, index1);
                var color = getColor(legend_1, colorMap, isDarkTheme);
                var dataValue = (_b = (_a = series.y) === null || _a === void 0 ? void 0 : _a[xIndex]) !== null && _b !== void 0 ? _b : 0;
                // As per the dataset
                // https://github.com/microsoft/fluentui-charting-contrib/blob/main/apps/plotly_examples/src/data/data_385.json
                // for the same series, for the same x value there can be multiple y values with the same legend
                // So we need to check if the key already exists in the series and sum the data values if key exists
                var existingDataPointIndex = mapXToDataPoints[x].series.findIndex(function (dp) { return dp.key === legend_1; });
                if (existingDataPointIndex !== -1) {
                    // If the key exists, sum the data values
                    mapXToDataPoints[x].series[existingDataPointIndex].data += dataValue;
                }
                else {
                    // Otherwise, add a new data point
                    mapXToDataPoints[x].series.push({
                        key: legend_1,
                        data: dataValue,
                        xAxisCalloutData: x,
                        color: color,
                        legend: legend_1,
                        useSecondaryYScale: usesSecondaryYScale(series),
                    });
                }
            }
        });
    });
    var _d = getTitles(input.layout), chartTitle = _d.chartTitle, xAxisTitle = _d.xAxisTitle, yAxisTitle = _d.yAxisTitle;
    return __assign(__assign({ data: Object.values(mapXToDataPoints), width: (_a = input.layout) === null || _a === void 0 ? void 0 : _a.width, height: (_c = (_b = input.layout) === null || _b === void 0 ? void 0 : _b.height) !== null && _c !== void 0 ? _c : 350, barwidth: 'auto', chartTitle: chartTitle, xAxisTitle: xAxisTitle, yAxisTitle: yAxisTitle, mode: 'plotly' }, secondaryYAxisValues), { hideTickOverlap: true });
};
export var transformPlotlyJsonToVBCProps = function (input, colorMap, isDarkTheme) {
    var _a, _b, _c;
    var vbcData = [];
    input.data.forEach(function (series, seriesIdx) {
        var _a, _b, _c;
        if (!series.x) {
            return;
        }
        var isXString = isStringArray(series.x);
        // TODO: In case of a single bin, add an empty bin of the same size to prevent the
        // default bar width from being used and ensure the bar spans the full intended range.
        var xBins = createBins(series.x, (_a = series.xbins) === null || _a === void 0 ? void 0 : _a.start, (_b = series.xbins) === null || _b === void 0 ? void 0 : _b.end, (_c = series.xbins) === null || _c === void 0 ? void 0 : _c.size);
        var yBins = xBins.map(function () { return []; });
        var total = 0;
        series.x.forEach(function (xVal, index) {
            var _a, _b;
            var binIdx = findBinIndex(xBins, xVal, isXString);
            if (binIdx !== -1) {
                yBins[binIdx].push((_b = (_a = series.y) === null || _a === void 0 ? void 0 : _a[index]) !== null && _b !== void 0 ? _b : 1);
            }
        });
        var y = yBins.map(function (bin) {
            var yVal = calculateHistFunc(series.histfunc, bin);
            total += yVal;
            return yVal;
        });
        xBins.forEach(function (bin, index) {
            var legend = getLegend(series, seriesIdx);
            var color = getColor(legend, colorMap, isDarkTheme);
            var yVal = calculateHistNorm(series.histnorm, y[index], total, isXString ? bin.length : getBinSize(bin));
            vbcData.push(__assign({ x: isXString ? bin.join(', ') : getBinCenter(bin), y: yVal, legend: legend, color: color }, (isXString
                ? {}
                : { xAxisCalloutData: "[".concat(bin.x0, " - ").concat(bin.x1, ")") })));
        });
    });
    var _d = getTitles(input.layout), chartTitle = _d.chartTitle, xAxisTitle = _d.xAxisTitle, yAxisTitle = _d.yAxisTitle;
    return {
        data: vbcData,
        width: (_a = input.layout) === null || _a === void 0 ? void 0 : _a.width,
        height: (_c = (_b = input.layout) === null || _b === void 0 ? void 0 : _b.height) !== null && _c !== void 0 ? _c : 350,
        supportNegativeData: true,
        chartTitle: chartTitle,
        xAxisTitle: xAxisTitle,
        yAxisTitle: yAxisTitle,
        mode: 'histogram',
        hideTickOverlap: true,
        maxBarWidth: 50,
    };
};
export var transformPlotlyJsonToScatterChartProps = function (input, isAreaChart, colorMap, isDarkTheme) {
    var _a, _b, _c, _d, _e, _f;
    var secondaryYAxisValues = getSecondaryYAxisValues(input.data, input.layout, isAreaChart ? 0 : undefined, isAreaChart ? 0 : undefined);
    var mode = 'tonexty';
    var chartData = input.data.map(function (series, index) {
        var xValues = series.x;
        var isString = typeof xValues[0] === 'string';
        var isXDate = isDateArray(xValues);
        var isXNumber = isNumberArray(xValues);
        var legend = getLegend(series, index);
        var lineColor = getColor(legend, colorMap, isDarkTheme);
        mode = series.fill === 'tozeroy' ? 'tozeroy' : 'tonexty';
        var lineOptions = getLineOptions(series.line);
        return __assign(__assign({ legend: legend, data: xValues.map(function (x, i) {
                var _a, _b;
                return (__assign({ x: isString ? (isXDate ? new Date(x) : isXNumber ? parseFloat(x) : x) : x, y: series.y[i] }, (Array.isArray((_a = series.marker) === null || _a === void 0 ? void 0 : _a.size)
                    ? { markerSize: series.marker.size[i] }
                    : typeof ((_b = series.marker) === null || _b === void 0 ? void 0 : _b.size) === 'number'
                        ? { markerSize: series.marker.size }
                        : {})));
            }), color: lineColor }, (lineOptions ? { lineOptions: lineOptions } : {})), { useSecondaryYScale: usesSecondaryYScale(series) });
    });
    var yMinMaxValues = findNumericMinMaxOfY(chartData);
    var _g = getTitles(input.layout), chartTitle = _g.chartTitle, xAxisTitle = _g.xAxisTitle, yAxisTitle = _g.yAxisTitle;
    var chartProps = {
        chartTitle: chartTitle,
        lineChartData: chartData,
    };
    if (isAreaChart) {
        return __assign(__assign({ data: chartProps, supportNegativeData: true, xAxisTitle: xAxisTitle, yAxisTitle: yAxisTitle }, secondaryYAxisValues), { mode: mode, width: (_a = input.layout) === null || _a === void 0 ? void 0 : _a.width, height: (_c = (_b = input.layout) === null || _b === void 0 ? void 0 : _b.height) !== null && _c !== void 0 ? _c : 350, hideTickOverlap: true });
    }
    else {
        return __assign(__assign({ data: chartProps, supportNegativeData: true, xAxisTitle: xAxisTitle, yAxisTitle: yAxisTitle }, secondaryYAxisValues), { roundedTicks: true, yMinValue: yMinMaxValues.startValue, yMaxValue: yMinMaxValues.endValue, width: (_d = input.layout) === null || _d === void 0 ? void 0 : _d.width, height: (_f = (_e = input.layout) === null || _e === void 0 ? void 0 : _e.height) !== null && _f !== void 0 ? _f : 350, hideTickOverlap: true, enableReflow: false });
    }
};
export var transformPlotlyJsonToHorizontalBarWithAxisProps = function (input, colorMap, isDarkTheme) {
    var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
    var chartData = input.data
        .map(function (series, index) {
        return series.y.map(function (yValue, i) {
            var _a;
            var legendName = (_a = series.name) !== null && _a !== void 0 ? _a : yValue;
            var color = getColor(legendName, colorMap, isDarkTheme);
            return {
                x: series.x[i],
                y: yValue,
                legend: legendName,
                color: color,
            };
        });
    })
        .reverse()
        .flat()
        //reversing the order to invert the Y bars order as required by plotly.
        .reverse();
    var chartHeight = (_b = (_a = input.layout) === null || _a === void 0 ? void 0 : _a.height) !== null && _b !== void 0 ? _b : 450;
    var margin = (_e = (_d = (_c = input.layout) === null || _c === void 0 ? void 0 : _c.margin) === null || _d === void 0 ? void 0 : _d.l) !== null && _e !== void 0 ? _e : 0;
    var padding = (_h = (_g = (_f = input.layout) === null || _f === void 0 ? void 0 : _f.margin) === null || _g === void 0 ? void 0 : _g.pad) !== null && _h !== void 0 ? _h : 0;
    var availableHeight = chartHeight - margin - padding;
    var numberOfBars = input.data.reduce(function (total, item) {
        var _a;
        return total + (((_a = item.y) === null || _a === void 0 ? void 0 : _a.length) || 0);
    }, 0);
    var scalingFactor = 0.01;
    var gapFactor = 1 / (1 + scalingFactor * numberOfBars);
    var barHeight = availableHeight / (numberOfBars * (1 + gapFactor));
    var _s = getTitles(input.layout), chartTitle = _s.chartTitle, xAxisTitle = _s.xAxisTitle, yAxisTitle = _s.yAxisTitle;
    return {
        data: chartData,
        chartTitle: chartTitle,
        xAxisTitle: xAxisTitle,
        yAxisTitle: yAxisTitle,
        secondaryYAxistitle: typeof ((_k = (_j = input.layout) === null || _j === void 0 ? void 0 : _j.yaxis2) === null || _k === void 0 ? void 0 : _k.title) === 'string'
            ? (_m = (_l = input.layout) === null || _l === void 0 ? void 0 : _l.yaxis2) === null || _m === void 0 ? void 0 : _m.title
            : ((_q = (_p = (_o = input.layout) === null || _o === void 0 ? void 0 : _o.yaxis2) === null || _p === void 0 ? void 0 : _p.title) === null || _q === void 0 ? void 0 : _q.text) || '',
        barHeight: barHeight,
        showYAxisLables: true,
        height: chartHeight,
        width: (_r = input.layout) === null || _r === void 0 ? void 0 : _r.width,
        hideTickOverlap: true,
    };
};
export var transformPlotlyJsonToHeatmapProps = function (input) {
    var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
    var firstData = input.data[0];
    var heatmapDataPoints = [];
    var zMin = Number.POSITIVE_INFINITY;
    var zMax = Number.NEGATIVE_INFINITY;
    if (firstData.type === 'histogram2d') {
        var isXString_1 = isStringArray(firstData.x);
        var isYString_1 = isStringArray(firstData.y);
        var xBins_1 = createBins(firstData.x, (_a = firstData.xbins) === null || _a === void 0 ? void 0 : _a.start, (_b = firstData.xbins) === null || _b === void 0 ? void 0 : _b.end, (_c = firstData.xbins) === null || _c === void 0 ? void 0 : _c.size);
        var yBins_1 = createBins(firstData.y, (_d = firstData.ybins) === null || _d === void 0 ? void 0 : _d.start, (_e = firstData.ybins) === null || _e === void 0 ? void 0 : _e.end, (_f = firstData.ybins) === null || _f === void 0 ? void 0 : _f.size);
        var zBins_1 = yBins_1.map(function () { return xBins_1.map(function () { return []; }); });
        var total_1 = 0;
        (_g = firstData.x) === null || _g === void 0 ? void 0 : _g.forEach(function (xVal, index) {
            var _a, _b, _c;
            var xBinIdx = findBinIndex(xBins_1, xVal, isXString_1);
            var yBinIdx = findBinIndex(yBins_1, (_a = firstData.y) === null || _a === void 0 ? void 0 : _a[index], isYString_1);
            if (xBinIdx !== -1 && yBinIdx !== -1) {
                zBins_1[yBinIdx][xBinIdx].push((_c = (_b = firstData.z) === null || _b === void 0 ? void 0 : _b[index]) !== null && _c !== void 0 ? _c : 1);
            }
        });
        var z_1 = zBins_1.map(function (row) {
            return row.map(function (bin) {
                var zVal = calculateHistFunc(firstData.histfunc, bin);
                total_1 += zVal;
                return zVal;
            });
        });
        xBins_1.forEach(function (xBin, xIdx) {
            yBins_1.forEach(function (yBin, yIdx) {
                var zVal = calculateHistNorm(firstData.histnorm, z_1[yIdx][xIdx], total_1, isXString_1 ? xBin.length : getBinSize(xBin), isYString_1 ? yBin.length : getBinSize(yBin));
                heatmapDataPoints.push({
                    x: isXString_1 ? xBin.join(', ') : getBinCenter(xBin),
                    y: isYString_1 ? yBin.join(', ') : getBinCenter(yBin),
                    value: zVal,
                    rectText: zVal,
                });
                if (typeof zVal === 'number') {
                    zMin = Math.min(zMin, zVal);
                    zMax = Math.max(zMax, zVal);
                }
            });
        });
    }
    else {
        (_h = firstData.x) === null || _h === void 0 ? void 0 : _h.forEach(function (xVal, xIdx) {
            var _a;
            (_a = firstData.y) === null || _a === void 0 ? void 0 : _a.forEach(function (yVal, yIdx) {
                var _a, _b, _c, _d, _e, _f;
                var zVal = (_b = (_a = firstData.z) === null || _a === void 0 ? void 0 : _a[yIdx]) === null || _b === void 0 ? void 0 : _b[xIdx];
                heatmapDataPoints.push({
                    x: ((_d = (_c = input.layout) === null || _c === void 0 ? void 0 : _c.xaxis) === null || _d === void 0 ? void 0 : _d.type) === 'date' ? xVal : xVal !== null && xVal !== void 0 ? xVal : 0,
                    y: ((_f = (_e = input.layout) === null || _e === void 0 ? void 0 : _e.yaxis) === null || _f === void 0 ? void 0 : _f.type) === 'date' ? yVal : yVal,
                    value: zVal,
                    rectText: zVal,
                });
                if (typeof zVal === 'number') {
                    zMin = Math.min(zMin, zVal);
                    zMax = Math.max(zMax, zVal);
                }
            });
        });
    }
    var heatmapData = {
        legend: (_j = firstData.name) !== null && _j !== void 0 ? _j : '',
        data: heatmapDataPoints,
        value: 0,
    };
    // Initialize domain and range to default values
    var defaultDomain = [zMin, (zMax + zMin) / 2, zMax];
    var defaultRange = [
        getColorFromToken(DataVizPalette.color1),
        getColorFromToken(DataVizPalette.color2),
        getColorFromToken(DataVizPalette.color3),
    ];
    var domainValuesForColorScale = Array.isArray(firstData.colorscale)
        ? firstData.colorscale.map(function (arr) { return arr[0] * (zMax - zMin) + zMin; })
        : defaultDomain;
    var rangeValuesForColorScale = Array.isArray(firstData.colorscale)
        ? firstData.colorscale.map(function (arr) { return arr[1]; })
        : defaultRange;
    var _o = getTitles(input.layout), chartTitle = _o.chartTitle, xAxisTitle = _o.xAxisTitle, yAxisTitle = _o.yAxisTitle;
    return {
        data: [heatmapData],
        domainValuesForColorScale: domainValuesForColorScale,
        rangeValuesForColorScale: rangeValuesForColorScale,
        hideLegend: true,
        showYAxisLables: true,
        chartTitle: chartTitle,
        xAxisTitle: xAxisTitle,
        yAxisTitle: yAxisTitle,
        sortOrder: 'none',
        width: (_k = input.layout) === null || _k === void 0 ? void 0 : _k.width,
        height: (_m = (_l = input.layout) === null || _l === void 0 ? void 0 : _l.height) !== null && _m !== void 0 ? _m : 350,
        hideTickOverlap: true,
    };
};
export var transformPlotlyJsonToSankeyProps = function (input, colorMap, isDarkTheme) {
    var _a, _b, _c, _d, _e, _f, _g, _h;
    var _j = input.data[0], link = _j.link, node = _j.node;
    var validLinks = ((_a = link === null || link === void 0 ? void 0 : link.value) !== null && _a !== void 0 ? _a : [])
        .map(function (val, index) { return ({
        value: val,
        source: link === null || link === void 0 ? void 0 : link.source[index],
        target: link === null || link === void 0 ? void 0 : link.target[index],
    }); })
        // eslint-disable-next-line @typescript-eslint/no-shadow
        // Filter out negative nodes, unequal nodes and self-references (circular links)
        .filter(function (x) { return x.source >= 0 && x.target >= 0 && x.source !== x.target; });
    var sankeyChartData = {
        nodes: (_b = node.label) === null || _b === void 0 ? void 0 : _b.map(function (label, index) {
            var color = getColor(label, colorMap, isDarkTheme);
            return {
                nodeId: index,
                name: label,
                color: color,
            };
        }),
        links: validLinks.map(function (validLink, index) {
            return __assign({}, validLink);
        }),
    };
    var styles = {
        root: __assign({}, (((_d = (_c = input.layout) === null || _c === void 0 ? void 0 : _c.font) === null || _d === void 0 ? void 0 : _d.size) ? { fontSize: (_e = input.layout.font) === null || _e === void 0 ? void 0 : _e.size } : {})),
    };
    var chartTitle = getTitles(input.layout).chartTitle;
    return {
        data: {
            chartTitle: chartTitle,
            SankeyChartData: sankeyChartData,
        },
        width: (_f = input.layout) === null || _f === void 0 ? void 0 : _f.width,
        height: (_h = (_g = input.layout) === null || _g === void 0 ? void 0 : _g.height) !== null && _h !== void 0 ? _h : 468,
        styles: styles,
        enableReflow: true,
    };
};
export var transformPlotlyJsonToGaugeProps = function (input, colorMap, isDarkTheme) {
    var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6;
    var firstData = input.data[0];
    var segments = ((_b = (_a = firstData.gauge) === null || _a === void 0 ? void 0 : _a.steps) === null || _b === void 0 ? void 0 : _b.length)
        ? firstData.gauge.steps.map(function (step, index) {
            var _a, _b;
            var legend = step.name || "Segment ".concat(index + 1);
            var color = getColor(legend, colorMap, isDarkTheme);
            return {
                legend: legend,
                size: ((_a = step.range) === null || _a === void 0 ? void 0 : _a[1]) - ((_b = step.range) === null || _b === void 0 ? void 0 : _b[0]),
                color: color,
            };
        })
        : [
            {
                legend: 'Current',
                size: (_c = firstData.value) !== null && _c !== void 0 ? _c : 0 - ((_g = (_f = (_e = (_d = firstData.gauge) === null || _d === void 0 ? void 0 : _d.axis) === null || _e === void 0 ? void 0 : _e.range) === null || _f === void 0 ? void 0 : _f[0]) !== null && _g !== void 0 ? _g : 0),
                color: getColor('Current', colorMap, isDarkTheme),
            },
            {
                legend: 'Target',
                size: ((_l = (_k = (_j = (_h = firstData.gauge) === null || _h === void 0 ? void 0 : _h.axis) === null || _j === void 0 ? void 0 : _j.range) === null || _k === void 0 ? void 0 : _k[1]) !== null && _l !== void 0 ? _l : 100) - ((_m = firstData.value) !== null && _m !== void 0 ? _m : 0),
                color: DataVizPalette.disabled,
            },
        ];
    var sublabel;
    var sublabelColor;
    if ((_o = firstData.delta) === null || _o === void 0 ? void 0 : _o.reference) {
        var diff = firstData.value - firstData.delta.reference;
        if (diff >= 0) {
            sublabel = "\u25B2 ".concat(diff);
            var color = getColorFromToken(DataVizPalette.success, isDarkTheme);
            sublabelColor = color;
        }
        else {
            sublabel = "\u25BC ".concat(Math.abs(diff));
            var color = getColorFromToken(DataVizPalette.error, isDarkTheme);
            sublabelColor = color;
        }
    }
    var styles = {
        sublabel: {
            fill: sublabelColor,
        },
    };
    var chartTitle = getTitles(input.layout).chartTitle;
    return {
        segments: segments,
        chartValue: (_p = firstData.value) !== null && _p !== void 0 ? _p : 0,
        chartTitle: chartTitle,
        sublabel: sublabel,
        // range values can be null
        minValue: typeof ((_s = (_r = (_q = firstData.gauge) === null || _q === void 0 ? void 0 : _q.axis) === null || _r === void 0 ? void 0 : _r.range) === null || _s === void 0 ? void 0 : _s[0]) === 'number' ? (_v = (_u = (_t = firstData.gauge) === null || _t === void 0 ? void 0 : _t.axis) === null || _u === void 0 ? void 0 : _u.range) === null || _v === void 0 ? void 0 : _v[0] : undefined,
        maxValue: typeof ((_y = (_x = (_w = firstData.gauge) === null || _w === void 0 ? void 0 : _w.axis) === null || _x === void 0 ? void 0 : _x.range) === null || _y === void 0 ? void 0 : _y[1]) === 'number' ? (_1 = (_0 = (_z = firstData.gauge) === null || _z === void 0 ? void 0 : _z.axis) === null || _0 === void 0 ? void 0 : _0.range) === null || _1 === void 0 ? void 0 : _1[1] : undefined,
        chartValueFormat: function () { var _a, _b; return (_b = (_a = firstData.value) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : ''; },
        width: (_2 = input.layout) === null || _2 === void 0 ? void 0 : _2.width,
        height: (_4 = (_3 = input.layout) === null || _3 === void 0 ? void 0 : _3.height) !== null && _4 !== void 0 ? _4 : 220,
        styles: styles,
        variant: ((_6 = (_5 = firstData.gauge) === null || _5 === void 0 ? void 0 : _5.steps) === null || _6 === void 0 ? void 0 : _6.length) ? GaugeChartVariant.MultipleSegments : GaugeChartVariant.SingleSegment,
    };
};
export var projectPolarToCartesian = function (input) {
    var projection = __assign({}, input);
    for (var sindex = 0; sindex < input.data.length; sindex++) {
        var series = input.data[sindex];
        series.x = [];
        series.y = [];
        for (var ptindex = 0; ptindex < series.r.length; ptindex++) {
            var thetaRad = (series.theta[ptindex] * Math.PI) / 180;
            var radius = series.r[ptindex];
            series.x[ptindex] = radius * Math.cos(thetaRad);
            series.y[ptindex] = radius * Math.sin(thetaRad);
        }
        projection.data[sindex] = series;
    }
    return projection;
};
function isPlainObject(obj) {
    if (window && window.process && window.process.versions) {
        return Object.prototype.toString.call(obj) === '[object Object]';
    }
    return (Object.prototype.toString.call(obj) === '[object Object]' &&
        Object.getPrototypeOf(obj).hasOwnProperty('hasOwnProperty'));
}
var arrayAttributes = [];
var stack = [];
var isArrayStack = [];
var baseContainer, baseAttrName;
/**
 * Interate iteratively through the trace object and find all the array attributes.
 * 1 trace record = 1 series of data
 * @param trace
 */
export function findArrayAttributes(trace) {
    // Init basecontainer and baseAttrName
    crawlIntoTrace(baseContainer, 0, '');
}
function crawlIntoTrace(container, i, astrPartial) {
    var item = container[stack[i]];
    var newAstrPartial = astrPartial + stack[i];
    if (i === stack.length - 1) {
        if (isArrayOrTypedArray(item)) {
            arrayAttributes.push(baseAttrName + newAstrPartial);
        }
    }
    else {
        if (isArrayStack[i]) {
            if (Array.isArray(item)) {
                for (var j = 0; j < item.length; j++) {
                    if (isPlainObject(item[j])) {
                        crawlIntoTrace(item[j], i + 1, newAstrPartial + '[' + j + '].');
                    }
                }
            }
        }
        else if (isPlainObject(item)) {
            crawlIntoTrace(item, i + 1, newAstrPartial + '.');
        }
    }
}
function getLineOptions(line) {
    if (!line) {
        return;
    }
    var lineOptions = {};
    if (line.dash) {
        lineOptions = __assign(__assign({}, lineOptions), dashOptions[line.dash]);
    }
    switch (line.shape) {
        case 'spline':
            var smoothing = typeof line.smoothing === 'number' ? line.smoothing : 1;
            lineOptions.curve = d3CurveCardinal.tension(1 - smoothing / 1.3);
            break;
        case 'hv':
            lineOptions.curve = 'stepAfter';
            break;
        case 'vh':
            lineOptions.curve = 'stepBefore';
            break;
        case 'hvh':
            lineOptions.curve = 'step';
            break;
        default:
            lineOptions.curve = 'linear';
    }
    return Object.keys(lineOptions).length > 0 ? lineOptions : undefined;
}
var isStringArray = function (arr) {
    return isArrayOfType(arr, function (value) { return typeof value === 'string'; });
};
// TODO: Use binary search to find the appropriate bin for numeric value.
var findBinIndex = function (bins, value, isString) {
    if (typeof value === 'undefined' || value === null) {
        return -1;
    }
    return isString
        ? bins.findIndex(function (bin) { return bin.includes(value); })
        : bins.findIndex(function (bin, index) {
            return value >= bin.x0 &&
                (index === bins.length - 1 ? value <= bin.x1 : value < bin.x1);
        });
};
var getBinSize = function (bin) {
    return bin.x1 - bin.x0;
};
var getBinCenter = function (bin) {
    return (bin.x1 + bin.x0) / 2;
};
// TODO: Add support for date axes
var createBins = function (data, binStart, binEnd, binSize) {
    if (!data || data.length === 0) {
        return [];
    }
    if (isStringArray(data)) {
        var categories_1 = Array.from(new Set(data));
        var start = typeof binStart === 'number' ? Math.ceil(binStart) : 0;
        var stop_1 = typeof binEnd === 'number' ? Math.floor(binEnd) + 1 : categories_1.length;
        var step_1 = typeof binSize === 'number' ? binSize : 1;
        return d3Range(start, stop_1, step_1).map(function (i) { return categories_1.slice(i, i + step_1); });
    }
    var scale = d3ScaleLinear()
        .domain(d3Extent(data))
        .nice();
    var _a = scale.domain(), minVal = _a[0], maxVal = _a[1];
    minVal = typeof binStart === 'number' ? binStart : minVal;
    maxVal = typeof binEnd === 'number' ? binEnd : maxVal;
    var binGenerator = d3Bin().domain([minVal, maxVal]);
    if (typeof binSize === 'number' && binSize > 0) {
        var thresholds = [];
        var precision = Math.max(getPrecision(minVal), getPrecision(binSize));
        var th = precisionRound(minVal, precision);
        while (th < precisionRound(maxVal + binSize, precision)) {
            thresholds.push(th);
            th = precisionRound(th + binSize, precision);
        }
        minVal = thresholds[0];
        maxVal = thresholds[thresholds.length - 1];
        binGenerator.domain([minVal, maxVal]).thresholds(thresholds);
        // When the domain ends at the last threshold (maxVal), d3Bin creates an extra final bin where
        // both x0 and x1 are equal to maxVal and inclusive. The previous bin also has x1 equal to maxVal,
        // but it is exclusive. To maintain consistent bin widths, remove the final bin,
        // making the previous bin the last one, with both x0 and x1 inclusive.
        return binGenerator(data).slice(0, -1);
    }
    return binGenerator(data);
};
var calculateHistFunc = function (histfunc, bin) {
    var _a, _b;
    switch (histfunc) {
        case 'sum':
            return d3Sum(bin);
        case 'avg':
            return bin.length === 0 ? 0 : d3Sum(bin) / bin.length;
        case 'min':
            return (_a = d3Min(bin)) !== null && _a !== void 0 ? _a : 0;
        case 'max':
            return (_b = d3Max(bin)) !== null && _b !== void 0 ? _b : 0;
        default:
            return bin.length;
    }
};
var calculateHistNorm = function (histnorm, value, total, dx, dy) {
    if (dy === void 0) { dy = 1; }
    switch (histnorm) {
        case 'percent':
            return total === 0 ? 0 : (value / total) * 100;
        case 'probability':
            return total === 0 ? 0 : value / total;
        case 'density':
            return dx * dy === 0 ? 0 : value / (dx * dy);
        case 'probability density':
            return total * dx * dy === 0 ? 0 : value / (total * dx * dy);
        default:
            return value;
    }
};
var getPrecision = function (value) {
    var _a, _b;
    return (_b = (_a = value.toString().split('.')[1]) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
};
var precisionRound = function (value, precision) {
    var factor = Math.pow(10, precision);
    return Math.round(value * factor) / factor;
};
//# sourceMappingURL=PlotlySchemaAdapter.js.map