/* *
 *
 *  (c) 2010-2021 Highsoft AS
 *
 *  Author: Paweł Potaczek
 *
 *  License: www.highcharts.com/license
 *
 *  !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
 *
 * */
'use strict';
import BubbleLegendDefaults from './BubbleLegendDefaults.js';
import BubbleLegendItem from './BubbleLegendItem.js';
import D from '../../Core/DefaultOptions.js';
var setOptions = D.setOptions;
import U from '../../Core/Utilities.js';
var addEvent = U.addEvent, objectEach = U.objectEach, wrap = U.wrap;
/* *
 *
 *  Namespace
 *
 * */
var BubbleLegendComposition;
(function (BubbleLegendComposition) {
    /* *
     *
     *  Constants
     *
     * */
    var composedClasses = [];
    /* *
     *
     *  Functions
     *
     * */
    /* eslint-disable valid-jsdoc */
    /**
     * If ranges are not specified, determine ranges from rendered bubble series
     * and render legend again.
     */
    function chartDrawChartBox(proceed, options, callback) {
        var chart = this, legend = chart.legend, bubbleSeries = getVisibleBubbleSeriesIndex(chart) >= 0;
        var bubbleLegendOptions, bubbleSizes;
        if (legend && legend.options.enabled && legend.bubbleLegend &&
            legend.options.bubbleLegend.autoRanges && bubbleSeries) {
            bubbleLegendOptions = legend.bubbleLegend.options;
            bubbleSizes = legend.bubbleLegend.predictBubbleSizes();
            legend.bubbleLegend.updateRanges(bubbleSizes[0], bubbleSizes[1]);
            // Disable animation on init
            if (!bubbleLegendOptions.placed) {
                legend.group.placed = false;
                legend.allItems.forEach(function (item) {
                    item.legendGroup.translateY = null;
                });
            }
            // Create legend with bubbleLegend
            legend.render();
            chart.getMargins();
            chart.axes.forEach(function (axis) {
                if (axis.visible) { // #11448
                    axis.render();
                }
                if (!bubbleLegendOptions.placed) {
                    axis.setScale();
                    axis.updateNames();
                    // Disable axis animation on init
                    objectEach(axis.ticks, function (tick) {
                        tick.isNew = true;
                        tick.isNewLabel = true;
                    });
                }
            });
            bubbleLegendOptions.placed = true;
            // After recalculate axes, calculate margins again.
            chart.getMargins();
            // Call default 'drawChartBox' method.
            proceed.call(chart, options, callback);
            // Check bubble legend sizes and correct them if necessary.
            legend.bubbleLegend.correctSizes();
            // Correct items positions with different dimensions in legend.
            retranslateItems(legend, getLinesHeights(legend));
        }
        else {
            proceed.call(chart, options, callback);
            // Allow color change on static bubble legend after click on legend
            if (legend && legend.options.enabled && legend.bubbleLegend) {
                legend.render();
                retranslateItems(legend, getLinesHeights(legend));
            }
        }
    }
    /**
     * Compose classes for use with Bubble series.
     * @private
     *
     * @param {Highcharts.Chart} ChartClass
     * Core chart class to use with Bubble series.
     *
     * @param {Highcharts.Legend} LegendClass
     * Core legend class to use with Bubble series.
     *
     * @param {Highcharts.Series} SeriesClass
     * Core series class to use with Bubble series.
     */
    function compose(ChartClass, LegendClass, SeriesClass) {
        if (composedClasses.indexOf(ChartClass) === -1) {
            composedClasses.push(ChartClass);
            setOptions({
                // Set default bubble legend options
                legend: {
                    bubbleLegend: BubbleLegendDefaults
                }
            });
            wrap(ChartClass.prototype, 'drawChartBox', chartDrawChartBox);
        }
        if (composedClasses.indexOf(LegendClass) === -1) {
            composedClasses.push(LegendClass);
            addEvent(LegendClass, 'afterGetAllItems', onLegendAfterGetAllItems);
        }
        if (composedClasses.indexOf(SeriesClass) === -1) {
            composedClasses.push(SeriesClass);
            addEvent(SeriesClass, 'legendItemClick', onSeriesLegendItemClick);
        }
    }
    BubbleLegendComposition.compose = compose;
    /**
     * Check if there is at least one visible bubble series.
     *
     * @private
     * @function getVisibleBubbleSeriesIndex
     * @param {Highcharts.Chart} chart
     * Chart to check.
     * @return {number}
     * First visible bubble series index
     */
    function getVisibleBubbleSeriesIndex(chart) {
        var series = chart.series;
        var i = 0;
        while (i < series.length) {
            if (series[i] &&
                series[i].isBubble &&
                series[i].visible &&
                series[i].zData.length) {
                return i;
            }
            i++;
        }
        return -1;
    }
    /**
     * Calculate height for each row in legend.
     *
     * @private
     * @function getLinesHeights
     *
     * @param {Highcharts.Legend} legend
     * Legend to calculate from.
     *
     * @return {Array<Highcharts.Dictionary<number>>}
     * Informations about line height and items amount
     */
    function getLinesHeights(legend) {
        var items = legend.allItems, lines = [], length = items.length;
        var lastLine, i = 0, j = 0;
        for (i = 0; i < length; i++) {
            if (items[i].legendItemHeight) {
                // for bubbleLegend
                items[i].itemHeight = items[i].legendItemHeight;
            }
            if ( // Line break
            items[i] === items[length - 1] ||
                items[i + 1] &&
                    items[i]._legendItemPos[1] !==
                        items[i + 1]._legendItemPos[1]) {
                lines.push({ height: 0 });
                lastLine = lines[lines.length - 1];
                // Find the highest item in line
                for (j; j <= i; j++) {
                    if (items[j].itemHeight > lastLine.height) {
                        lastLine.height = items[j].itemHeight;
                    }
                }
                lastLine.step = i;
            }
        }
        return lines;
    }
    /**
     * Start the bubble legend creation process.
     */
    function onLegendAfterGetAllItems(e) {
        var legend = this, bubbleLegend = legend.bubbleLegend, legendOptions = legend.options, options = legendOptions.bubbleLegend, bubbleSeriesIndex = getVisibleBubbleSeriesIndex(legend.chart);
        // Remove unnecessary element
        if (bubbleLegend && bubbleLegend.ranges && bubbleLegend.ranges.length) {
            // Allow change the way of calculating ranges in update
            if (options.ranges.length) {
                options.autoRanges =
                    !!options.ranges[0].autoRanges;
            }
            // Update bubbleLegend dimensions in each redraw
            legend.destroyItem(bubbleLegend);
        }
        // Create bubble legend
        if (bubbleSeriesIndex >= 0 &&
            legendOptions.enabled &&
            options.enabled) {
            options.seriesIndex = bubbleSeriesIndex;
            legend.bubbleLegend = new BubbleLegendItem(options, legend);
            legend.bubbleLegend.addToLegend(e.allItems);
        }
    }
    /**
     * Toggle bubble legend depending on the visible status of bubble series.
     */
    function onSeriesLegendItemClick() {
        var series = this, chart = series.chart, visible = series.visible, legend = series.chart.legend;
        var status;
        if (legend && legend.bubbleLegend) {
            // Temporary correct 'visible' property
            series.visible = !visible;
            // Save future status for getRanges method
            series.ignoreSeries = visible;
            // Check if at lest one bubble series is visible
            status = getVisibleBubbleSeriesIndex(chart) >= 0;
            // Hide bubble legend if all bubble series are disabled
            if (legend.bubbleLegend.visible !== status) {
                // Show or hide bubble legend
                legend.update({
                    bubbleLegend: { enabled: status }
                });
                legend.bubbleLegend.visible = status; // Restore default status
            }
            series.visible = visible;
        }
    }
    /**
     * Correct legend items translation in case of different elements heights.
     *
     * @private
     * @function Highcharts.Legend#retranslateItems
     *
     * @param {Highcharts.Legend} legend
     * Legend to translate in.
     *
     * @param {Array<Highcharts.Dictionary<number>>} lines
     * Informations about line height and items amount
     */
    function retranslateItems(legend, lines) {
        var items = legend.allItems, rtl = legend.options.rtl;
        var orgTranslateX, orgTranslateY, movementX, actualLine = 0;
        items.forEach(function (item, index) {
            orgTranslateX = item.legendGroup.translateX;
            orgTranslateY = item._legendItemPos[1];
            movementX = item.movementX;
            if (movementX || (rtl && item.ranges)) {
                movementX = rtl ?
                    orgTranslateX - item.options.maxSize / 2 :
                    orgTranslateX + movementX;
                item.legendGroup.attr({ translateX: movementX });
            }
            if (index > lines[actualLine].step) {
                actualLine++;
            }
            item.legendGroup.attr({
                translateY: Math.round(orgTranslateY + lines[actualLine].height / 2)
            });
            item._legendItemPos[1] = orgTranslateY +
                lines[actualLine].height / 2;
        });
    }
    /* eslint-disable valid-jsdoc */
})(BubbleLegendComposition || (BubbleLegendComposition = {}));
/* *
 *
 *  Default Export
 *
 * */
export default BubbleLegendComposition;
