/* *
 *
 *  (c) 2009-2019 Øystein Moseng
 *
 *  Accessibility component for chart legend.
 *
 *  License: www.highcharts.com/license
 *
 * */

'use strict';

import H from '../../../parts/Globals.js';
import AccessibilityComponent from '../AccessibilityComponent.js';
import KeyboardNavigationHandler from '../KeyboardNavigationHandler.js';
import A11yUtilities from '../utilities.js';

var stripHTMLTags = A11yUtilities.stripHTMLTagsFromString;


/**
 * Highlight legend item by index.
 *
 * @private
 * @function Highcharts.Chart#highlightLegendItem
 *
 * @param {number} ix
 *
 * @return {boolean}
 */
H.Chart.prototype.highlightLegendItem = function (ix) {
    var items = this.legend.allItems,
        oldIx = this.highlightedLegendItemIx;

    if (items[ix]) {
        if (items[oldIx]) {
            H.fireEvent(
                items[oldIx].legendGroup.element,
                'mouseout'
            );
        }
        // Scroll if we have to
        if (items[ix].pageIx !== undefined &&
            items[ix].pageIx + 1 !== this.legend.currentPage) {
            this.legend.scroll(1 + items[ix].pageIx - this.legend.currentPage);
        }
        // Focus
        this.setFocusToElement(
            items[ix].legendItem, items[ix].a11yProxyElement
        );
        H.fireEvent(items[ix].legendGroup.element, 'mouseover');
        return true;
    }
    return false;
};

// Keep track of pressed state for legend items
H.addEvent(H.Legend, 'afterColorizeItem', function (e) {
    var chart = this.chart,
        a11yOptions = chart.options.accessibility,
        legendItem = e.item;
    if (a11yOptions.enabled && legendItem && legendItem.a11yProxyElement) {
        legendItem.a11yProxyElement.setAttribute(
            'aria-pressed', e.visible ? 'false' : 'true'
        );
    }
});


/**
 * The LegendComponent class
 *
 * @private
 * @class
 * @name Highcharts.LegendComponent
 * @param {Highcharts.Chart} chart
 *        Chart object
 */
var LegendComponent = function (chart) {
    this.initBase(chart);
};
LegendComponent.prototype = new AccessibilityComponent();
H.extend(LegendComponent.prototype, /** @lends Highcharts.LegendComponent */ {

    /**
     * The legend needs updates on every render, in order to update positioning
     * of the proxy overlays.
     */
    onChartRender: function () {
        var chart = this.chart,
            a11yOptions = chart.options.accessibility,
            items = chart.legend && chart.legend.allItems,
            component = this;

        // Ignore render after proxy clicked. No need to destroy it, and
        // destroying also kills focus.
        if (component.legendProxyButtonClicked) {
            delete component.legendProxyButtonClicked;
            return;
        }

        // Always Remove group if exists
        this.removeElement(this.legendProxyGroup);

        // Skip everything if we do not have legend items, or if we have a
        // color axis
        if (
            !items || !items.length ||
            chart.colorAxis && chart.colorAxis.length ||
            !chart.options.legend.accessibility.enabled
        ) {
            return;
        }

        // Add proxy group
        this.legendProxyGroup = this.addProxyGroup({
            'aria-label': chart.langFormat(
                'accessibility.legendLabel'
            ),
            'role': a11yOptions.landmarkVerbosity === 'all' ?
                'region' : null
        });

        // Proxy the legend items
        items.forEach(function (item) {
            if (item.legendItem && item.legendItem.element) {
                item.a11yProxyElement = component.createProxyButton(
                    item.legendItem,
                    component.legendProxyGroup,
                    {
                        tabindex: -1,
                        'aria-pressed': !item.visible,
                        'aria-label': chart.langFormat(
                            'accessibility.legendItem',
                            {
                                chart: chart,
                                itemName: stripHTMLTags(item.name)
                            }
                        )
                    },
                    // Consider useHTML
                    item.legendGroup.div ? item.legendItem : item.legendGroup,
                    // Additional click event (fires first)
                    function () {
                        // Keep track of when we should ignore next render
                        component.legendProxyButtonClicked = true;
                    }
                );
            }
        });
    },


    /**
     * Get keyboard navigation handler for this component.
     * @return {Highcharts.KeyboardNavigationHandler}
     */
    getKeyboardNavigation: function () {
        var keys = this.keyCodes,
            component = this,
            chart = this.chart,
            a11yOptions = chart.options.accessibility;
        return new KeyboardNavigationHandler(chart, {
            keyCodeMap: [
                // Arrow key handling
                [[
                    keys.left, keys.right, keys.up, keys.down
                ], function (keyCode) {
                    var direction = (
                        keyCode === keys.left || keyCode === keys.up
                    ) ? -1 : 1;

                    // Try to highlight next/prev legend item
                    var res = chart.highlightLegendItem(
                        component.highlightedLegendItemIx + direction
                    );
                    if (res) {
                        component.highlightedLegendItemIx += direction;
                        return this.response.success;
                    }

                    // Failed, can we wrap around?
                    if (
                        chart.legend.allItems.length > 1 &&
                        a11yOptions.keyboardNavigation.wrapAround
                    ) {
                        // Wrap around if we failed and have more than 1 item
                        this.init(direction);
                        return this.response.success;
                    }

                    // No wrap, move
                    return this.response[direction > 0 ? 'next' : 'prev'];
                }],

                // Click item
                [[
                    keys.enter, keys.space
                ], function () {
                    var legendItem = chart.legend.allItems[
                        component.highlightedLegendItemIx
                    ];
                    if (legendItem && legendItem.a11yProxyElement) {
                        H.fireEvent(legendItem.a11yProxyElement, 'click');
                    }
                    return this.response.success;
                }]
            ],

            // Only run this module if we have at least one legend - wait for
            // it - item. Don't run if the legend is populated by a colorAxis.
            // Don't run if legend navigation is disabled.
            validate: function () {
                var legendOptions = chart.options.legend;
                return chart.legend && chart.legend.allItems &&
                    chart.legend.display &&
                    !(chart.colorAxis && chart.colorAxis.length) &&
                    legendOptions &&
                    legendOptions.accessibility &&
                    legendOptions.accessibility.enabled &&
                    legendOptions.accessibility.keyboardNavigation &&
                    legendOptions.accessibility.keyboardNavigation.enabled;
            },


            // Focus first/last item
            init: function (direction) {
                var ix = direction > 0 ? 0 : chart.legend.allItems.length - 1;
                chart.highlightLegendItem(ix);
                component.highlightedLegendItemIx = ix;
            }
        });
    }

});

export default LegendComponent;
