/* *
 *
 *  GUI generator for Stock tools
 *
 *  (c) 2009-2017 Sebastian Bochan
 *
 *  License: www.highcharts.com/license
 *
 *  !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
 *
 * */
'use strict';
import H from '../parts/Globals.js';
import U from '../parts/Utilities.js';
var addEvent = U.addEvent, createElement = U.createElement, css = U.css, extend = U.extend, fireEvent = U.fireEvent, getStyle = U.getStyle, isArray = U.isArray, merge = U.merge, pick = U.pick;
var win = H.win, DIV = 'div', SPAN = 'span', UL = 'ul', LI = 'li', PREFIX = 'highcharts-', activeClass = PREFIX + 'active';
H.setOptions({
    /**
     * @optionparent lang
     */
    lang: {
        /**
         * Configure the stockTools GUI titles(hints) in the chart. Requires
         * the `stock-tools.js` module to be loaded.
         *
         * @product highstock
         * @since   7.0.0
         */
        stockTools: {
            gui: {
                // Main buttons:
                simpleShapes: 'Simple shapes',
                lines: 'Lines',
                crookedLines: 'Crooked lines',
                measure: 'Measure',
                advanced: 'Advanced',
                toggleAnnotations: 'Toggle annotations',
                verticalLabels: 'Vertical labels',
                flags: 'Flags',
                zoomChange: 'Zoom change',
                typeChange: 'Type change',
                saveChart: 'Save chart',
                indicators: 'Indicators',
                currentPriceIndicator: 'Current Price Indicators',
                // Other features:
                zoomX: 'Zoom X',
                zoomY: 'Zoom Y',
                zoomXY: 'Zooom XY',
                fullScreen: 'Fullscreen',
                typeOHLC: 'OHLC',
                typeLine: 'Line',
                typeCandlestick: 'Candlestick',
                // Basic shapes:
                circle: 'Circle',
                label: 'Label',
                rectangle: 'Rectangle',
                // Flags:
                flagCirclepin: 'Flag circle',
                flagDiamondpin: 'Flag diamond',
                flagSquarepin: 'Flag square',
                flagSimplepin: 'Flag simple',
                // Measures:
                measureXY: 'Measure XY',
                measureX: 'Measure X',
                measureY: 'Measure Y',
                // Segment, ray and line:
                segment: 'Segment',
                arrowSegment: 'Arrow segment',
                ray: 'Ray',
                arrowRay: 'Arrow ray',
                line: 'Line',
                arrowLine: 'Arrow line',
                horizontalLine: 'Horizontal line',
                verticalLine: 'Vertical line',
                infinityLine: 'Infinity line',
                // Crooked lines:
                crooked3: 'Crooked 3 line',
                crooked5: 'Crooked 5 line',
                elliott3: 'Elliott 3 line',
                elliott5: 'Elliott 5 line',
                // Counters:
                verticalCounter: 'Vertical counter',
                verticalLabel: 'Vertical label',
                verticalArrow: 'Vertical arrow',
                // Advanced:
                fibonacci: 'Fibonacci',
                pitchfork: 'Pitchfork',
                parallelChannel: 'Parallel channel'
            }
        },
        navigation: {
            popup: {
                // Annotations:
                circle: 'Circle',
                rectangle: 'Rectangle',
                label: 'Label',
                segment: 'Segment',
                arrowSegment: 'Arrow segment',
                ray: 'Ray',
                arrowRay: 'Arrow ray',
                line: 'Line',
                arrowLine: 'Arrow line',
                horizontalLine: 'Horizontal line',
                verticalLine: 'Vertical line',
                crooked3: 'Crooked 3 line',
                crooked5: 'Crooked 5 line',
                elliott3: 'Elliott 3 line',
                elliott5: 'Elliott 5 line',
                verticalCounter: 'Vertical counter',
                verticalLabel: 'Vertical label',
                verticalArrow: 'Vertical arrow',
                fibonacci: 'Fibonacci',
                pitchfork: 'Pitchfork',
                parallelChannel: 'Parallel channel',
                infinityLine: 'Infinity line',
                measure: 'Measure',
                measureXY: 'Measure XY',
                measureX: 'Measure X',
                measureY: 'Measure Y',
                // Flags:
                flags: 'Flags',
                // GUI elements:
                addButton: 'add',
                saveButton: 'save',
                editButton: 'edit',
                removeButton: 'remove',
                series: 'Series',
                volume: 'Volume',
                connector: 'Connector',
                // Field names:
                innerBackground: 'Inner background',
                outerBackground: 'Outer background',
                crosshairX: 'Crosshair X',
                crosshairY: 'Crosshair Y',
                tunnel: 'Tunnel',
                background: 'Background'
            }
        }
    },
    /**
     * Configure the stockTools gui strings in the chart. Requires the
     * [stockTools module]() to be loaded. For a description of the module
     * and information on its features, see [Highcharts StockTools]().
     *
     * @product highstock
     *
     * @sample stock/demo/stock-tools-gui Stock Tools GUI
     *
     * @sample stock/demo/stock-tools-custom-gui Stock Tools customized GUI
     *
     * @since        7.0.0
     * @optionparent stockTools
     */
    stockTools: {
        /**
         * Definitions of buttons in Stock Tools GUI.
         */
        gui: {
            /**
             * Path where Highcharts will look for icons. Change this to use
             * icons from a different server.
             *
             * Since 7.1.3 use [iconsURL](#navigation.iconsURL) for popup and
             * stock tools.
             *
             * @deprecated
             * @apioption stockTools.gui.iconsURL
             *
             */
            /**
             * Enable or disable the stockTools gui.
             */
            enabled: true,
            /**
             * A CSS class name to apply to the stocktools' div,
             * allowing unique CSS styling for each chart.
             */
            className: 'highcharts-bindings-wrapper',
            /**
             * A CSS class name to apply to the container of buttons,
             * allowing unique CSS styling for each chart.
             */
            toolbarClassName: 'stocktools-toolbar',
            /**
             * A collection of strings pointing to config options for the
             * toolbar items. Each name refers to unique key from definitions
             * object.
             *
             * @default [
             *   'indicators',
             *   'separator',
             *   'simpleShapes',
             *   'lines',
             *   'crookedLines',
             *   'measure',
             *   'advanced',
             *   'toggleAnnotations',
             *   'separator',
             *   'verticalLabels',
             *   'flags',
             *   'separator',
             *   'zoomChange',
             *   'fullScreen',
             *   'typeChange',
             *   'separator',
             *   'currentPriceIndicator',
             *   'saveChart'
             * ]
             */
            buttons: [
                'indicators',
                'separator',
                'simpleShapes',
                'lines',
                'crookedLines',
                'measure',
                'advanced',
                'toggleAnnotations',
                'separator',
                'verticalLabels',
                'flags',
                'separator',
                'zoomChange',
                'fullScreen',
                'typeChange',
                'separator',
                'currentPriceIndicator',
                'saveChart'
            ],
            /**
             * An options object of the buttons definitions. Each name refers to
             * unique key from buttons array.
             */
            definitions: {
                separator: {
                    /**
                     * A predefined background symbol for the button.
                     */
                    symbol: 'separator.svg'
                },
                simpleShapes: {
                    /**
                     * A collection of strings pointing to config options for
                     * the items.
                     *
                     * @type {array}
                     * @default [
                     *   'label',
                     *   'circle',
                     *   'rectangle'
                     * ]
                     *
                     */
                    items: [
                        'label',
                        'circle',
                        'rectangle'
                    ],
                    circle: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         *
                         */
                        symbol: 'circle.svg'
                    },
                    rectangle: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         *
                         */
                        symbol: 'rectangle.svg'
                    },
                    label: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         *
                         */
                        symbol: 'label.svg'
                    }
                },
                flags: {
                    /**
                     * A collection of strings pointing to config options for
                     * the items.
                     *
                     * @type {array}
                     * @default [
                     *   'flagCirclepin',
                     *   'flagDiamondpin',
                     *   'flagSquarepin',
                     *   'flagSimplepin'
                     * ]
                     *
                     */
                    items: [
                        'flagCirclepin',
                        'flagDiamondpin',
                        'flagSquarepin',
                        'flagSimplepin'
                    ],
                    flagSimplepin: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         *
                         */
                        symbol: 'flag-basic.svg'
                    },
                    flagDiamondpin: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         *
                         */
                        symbol: 'flag-diamond.svg'
                    },
                    flagSquarepin: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'flag-trapeze.svg'
                    },
                    flagCirclepin: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'flag-elipse.svg'
                    }
                },
                lines: {
                    /**
                     * A collection of strings pointing to config options for
                     * the items.
                     *
                     * @type {array}
                     * @default [
                     *   'segment',
                     *   'arrowSegment',
                     *   'ray',
                     *   'arrowRay',
                     *   'line',
                     *   'arrowLine',
                     *   'horizontalLine',
                     *   'verticalLine'
                     * ]
                     */
                    items: [
                        'segment',
                        'arrowSegment',
                        'ray',
                        'arrowRay',
                        'line',
                        'arrowLine',
                        'horizontalLine',
                        'verticalLine'
                    ],
                    segment: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'segment.svg'
                    },
                    arrowSegment: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'arrow-segment.svg'
                    },
                    ray: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'ray.svg'
                    },
                    arrowRay: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'arrow-ray.svg'
                    },
                    line: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'line.svg'
                    },
                    arrowLine: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'arrow-line.svg'
                    },
                    verticalLine: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'vertical-line.svg'
                    },
                    horizontalLine: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'horizontal-line.svg'
                    }
                },
                crookedLines: {
                    /**
                     * A collection of strings pointing to config options for
                     * the items.
                     *
                     * @type {array}
                     * @default [
                     *   'elliott3',
                     *   'elliott5',
                     *   'crooked3',
                     *   'crooked5'
                     * ]
                     *
                     */
                    items: [
                        'elliott3',
                        'elliott5',
                        'crooked3',
                        'crooked5'
                    ],
                    crooked3: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'crooked-3.svg'
                    },
                    crooked5: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'crooked-5.svg'
                    },
                    elliott3: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'elliott-3.svg'
                    },
                    elliott5: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'elliott-5.svg'
                    }
                },
                verticalLabels: {
                    /**
                     * A collection of strings pointing to config options for
                     * the items.
                     *
                     * @type {array}
                     * @default [
                     *   'verticalCounter',
                     *   'verticalLabel',
                     *   'verticalArrow'
                     * ]
                     */
                    items: [
                        'verticalCounter',
                        'verticalLabel',
                        'verticalArrow'
                    ],
                    verticalCounter: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'vertical-counter.svg'
                    },
                    verticalLabel: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'vertical-label.svg'
                    },
                    verticalArrow: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'vertical-arrow.svg'
                    }
                },
                advanced: {
                    /**
                     * A collection of strings pointing to config options for
                     * the items.
                     *
                     * @type {array}
                     * @default [
                     *   'fibonacci',
                     *   'pitchfork',
                     *   'parallelChannel'
                     * ]
                     */
                    items: [
                        'fibonacci',
                        'pitchfork',
                        'parallelChannel'
                    ],
                    pitchfork: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'pitchfork.svg'
                    },
                    fibonacci: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'fibonacci.svg'
                    },
                    parallelChannel: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'parallel-channel.svg'
                    }
                },
                measure: {
                    /**
                     * A collection of strings pointing to config options for
                     * the items.
                     *
                     * @type {array}
                     * @default [
                     *   'measureXY',
                     *   'measureX',
                     *   'measureY'
                     * ]
                     */
                    items: [
                        'measureXY',
                        'measureX',
                        'measureY'
                    ],
                    measureX: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'measure-x.svg'
                    },
                    measureY: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'measure-y.svg'
                    },
                    measureXY: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'measure-xy.svg'
                    }
                },
                toggleAnnotations: {
                    /**
                     * A predefined background symbol for the button.
                     *
                     * @type   {string}
                     */
                    symbol: 'annotations-visible.svg'
                },
                currentPriceIndicator: {
                    /**
                     * A predefined background symbol for the button.
                     *
                     * @type   {string}
                     */
                    symbol: 'current-price-show.svg'
                },
                indicators: {
                    /**
                     * A predefined background symbol for the button.
                     *
                     * @type   {string}
                     */
                    symbol: 'indicators.svg'
                },
                zoomChange: {
                    /**
                     * A collection of strings pointing to config options for
                     * the items.
                     *
                     * @type {array}
                     * @default [
                     *   'zoomX',
                     *   'zoomY',
                     *   'zoomXY'
                     * ]
                     */
                    items: [
                        'zoomX',
                        'zoomY',
                        'zoomXY'
                    ],
                    zoomX: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'zoom-x.svg'
                    },
                    zoomY: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'zoom-y.svg'
                    },
                    zoomXY: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'zoom-xy.svg'
                    }
                },
                typeChange: {
                    /**
                     * A collection of strings pointing to config options for
                     * the items.
                     *
                     * @type {array}
                     * @default [
                     *   'typeOHLC',
                     *   'typeLine',
                     *   'typeCandlestick'
                     * ]
                     */
                    items: [
                        'typeOHLC',
                        'typeLine',
                        'typeCandlestick'
                    ],
                    typeOHLC: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'series-ohlc.svg'
                    },
                    typeLine: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'series-line.svg'
                    },
                    typeCandlestick: {
                        /**
                         * A predefined background symbol for the button.
                         *
                         * @type   {string}
                         */
                        symbol: 'series-candlestick.svg'
                    }
                },
                fullScreen: {
                    /**
                     * A predefined background symbol for the button.
                     *
                     * @type   {string}
                     */
                    symbol: 'fullscreen.svg'
                },
                saveChart: {
                    /**
                     * A predefined background symbol for the button.
                     *
                     * @type   {string}
                     */
                    symbol: 'save-chart.svg'
                }
            }
        }
    }
});
/* eslint-disable no-invalid-this, valid-jsdoc */
// Run HTML generator
addEvent(H.Chart, 'afterGetContainer', function () {
    this.setStockTools();
});
addEvent(H.Chart, 'getMargins', function () {
    var listWrapper = this.stockTools && this.stockTools.listWrapper, offsetWidth = listWrapper && ((listWrapper.startWidth +
        getStyle(listWrapper, 'padding-left') +
        getStyle(listWrapper, 'padding-right')) || listWrapper.offsetWidth);
    if (offsetWidth && offsetWidth < this.plotWidth) {
        this.plotLeft += offsetWidth;
    }
});
addEvent(H.Chart, 'destroy', function () {
    if (this.stockTools) {
        this.stockTools.destroy();
    }
});
addEvent(H.Chart, 'redraw', function () {
    if (this.stockTools && this.stockTools.guiEnabled) {
        this.stockTools.redraw();
    }
});
/**
 * Toolbar Class
 * @private
 * @constructor
 * @param {Object} - options of toolbar
 * @param {Chart} - Reference to chart
 */
H.Toolbar = function (options, langOptions, chart) {
    this.chart = chart;
    this.options = options;
    this.lang = langOptions;
    // set url for icons.
    this.iconsURL = this.getIconsURL();
    this.guiEnabled = options.enabled;
    this.visible = pick(options.visible, true);
    this.placed = pick(options.placed, false);
    // General events collection which should be removed upon destroy/update:
    this.eventsToUnbind = [];
    if (this.guiEnabled) {
        this.createHTML();
        this.init();
        this.showHideNavigatorion();
    }
    fireEvent(this, 'afterInit');
};
extend(H.Chart.prototype, {
    /**
     * Verify if Toolbar should be added.
     * @private
     * @param {Highcharts.StockToolsOptions} - chart options
     * @return {void}
     */
    setStockTools: function (options) {
        var chartOptions = this.options, lang = chartOptions.lang, guiOptions = merge(chartOptions.stockTools && chartOptions.stockTools.gui, options && options.gui), langOptions = lang.stockTools && lang.stockTools.gui;
        this.stockTools = new H.Toolbar(guiOptions, langOptions, this);
        if (this.stockTools.guiEnabled) {
            this.isDirtyBox = true;
        }
    }
});
H.Toolbar.prototype = {
    /**
     * Initialize the toolbar. Create buttons and submenu for each option
     * defined in `stockTools.gui`.
     * @private
     */
    init: function () {
        var _self = this, lang = this.lang, guiOptions = this.options, toolbar = this.toolbar, addSubmenu = _self.addSubmenu, buttons = guiOptions.buttons, defs = guiOptions.definitions, allButtons = toolbar.childNodes, inIframe = this.inIframe(), button;
        // create buttons
        buttons.forEach(function (btnName) {
            button = _self.addButton(toolbar, defs, btnName, lang);
            if (inIframe && btnName === 'fullScreen') {
                button.buttonWrapper.className +=
                    ' ' + PREFIX + 'disabled-btn';
            }
            _self.eventsToUnbind.push(addEvent(button.buttonWrapper, 'click', function () {
                _self.eraseActiveButtons(allButtons, button.buttonWrapper);
            }));
            if (isArray(defs[btnName].items)) {
                // create submenu buttons
                addSubmenu.call(_self, button, defs[btnName]);
            }
        });
    },
    /**
     * Create submenu (list of buttons) for the option. In example main button
     * is Line, in submenu will be buttons with types of lines.
     * @private
     * @param {Highcharts.Dictionary<Highcharts.HTMLDOMElement>}
     * button which has submenu
     * @param {Highcharts.StockToolsGuiDefinitionsButtonsOptions}
     * list of all buttons
     */
    addSubmenu: function (parentBtn, button) {
        var _self = this, submenuArrow = parentBtn.submenuArrow, buttonWrapper = parentBtn.buttonWrapper, buttonWidth = getStyle(buttonWrapper, 'width'), wrapper = this.wrapper, menuWrapper = this.listWrapper, allButtons = this.toolbar.childNodes, topMargin = 0, submenuWrapper;
        // create submenu container
        this.submenu = submenuWrapper = createElement(UL, {
            className: PREFIX + 'submenu-wrapper'
        }, null, buttonWrapper);
        // create submenu buttons and select the first one
        this.addSubmenuItems(buttonWrapper, button);
        // show / hide submenu
        _self.eventsToUnbind.push(addEvent(submenuArrow, 'click', function (e) {
            e.stopPropagation();
            // Erase active class on all other buttons
            _self.eraseActiveButtons(allButtons, buttonWrapper);
            // hide menu
            if (buttonWrapper.className.indexOf(PREFIX + 'current') >= 0) {
                menuWrapper.style.width =
                    menuWrapper.startWidth + 'px';
                buttonWrapper.classList.remove(PREFIX + 'current');
                submenuWrapper.style.display = 'none';
            }
            else {
                // show menu
                // to calculate height of element
                submenuWrapper.style.display = 'block';
                topMargin = submenuWrapper.offsetHeight -
                    buttonWrapper.offsetHeight - 3;
                // calculate position of submenu in the box
                // if submenu is inside, reset top margin
                if (
                // cut on the bottom
                !(submenuWrapper.offsetHeight +
                    buttonWrapper.offsetTop >
                    wrapper.offsetHeight &&
                    // cut on the top
                    buttonWrapper.offsetTop > topMargin)) {
                    topMargin = 0;
                }
                // apply calculated styles
                css(submenuWrapper, {
                    top: -topMargin + 'px',
                    left: buttonWidth + 3 + 'px'
                });
                buttonWrapper.className += ' ' + PREFIX + 'current';
                menuWrapper.startWidth = wrapper.offsetWidth;
                menuWrapper.style.width = menuWrapper.startWidth +
                    getStyle(menuWrapper, 'padding-left') +
                    submenuWrapper.offsetWidth + 3 + 'px';
            }
        }));
    },
    /**
     * Create buttons in submenu
     * @private
     * @param {Highcharts.HTMLDOMElement}
     * button where submenu is placed
     * @param {Highcharts.StockToolsGuiDefinitionsButtonsOptions}
     * list of all buttons options
     *
     */
    addSubmenuItems: function (buttonWrapper, button) {
        var _self = this, submenuWrapper = this.submenu, lang = this.lang, menuWrapper = this.listWrapper, items = button.items, firstSubmenuItem, submenuBtn;
        // add items to submenu
        items.forEach(function (btnName) {
            // add buttons to submenu
            submenuBtn = _self.addButton(submenuWrapper, button, btnName, lang);
            _self.eventsToUnbind.push(addEvent(submenuBtn.mainButton, 'click', function () {
                _self.switchSymbol(this, buttonWrapper, true);
                menuWrapper.style.width =
                    menuWrapper.startWidth + 'px';
                submenuWrapper.style.display = 'none';
            }));
        });
        // select first submenu item
        firstSubmenuItem = submenuWrapper
            .querySelectorAll('li > .' + PREFIX + 'menu-item-btn')[0];
        // replace current symbol, in main button, with submenu's button style
        _self.switchSymbol(firstSubmenuItem, false);
    },
    /*
     * Erase active class on all other buttons.
     *
     * @param {Array} - Array of HTML buttons
     * @param {HTMLDOMElement} - Current HTML button
     *
     */
    eraseActiveButtons: function (buttons, currentButton, submenuItems) {
        [].forEach.call(buttons, function (btn) {
            if (btn !== currentButton) {
                btn.classList.remove(PREFIX + 'current');
                btn.classList.remove(PREFIX + 'active');
                submenuItems =
                    btn.querySelectorAll('.' + PREFIX + 'submenu-wrapper');
                // hide submenu
                if (submenuItems.length > 0) {
                    submenuItems[0].style.display = 'none';
                }
            }
        });
    },
    /**
     * Create single button. Consist of HTML elements `li`, `span`, and (if
     * exists) submenu container.
     * @private
     * @param {HTMLDOMElement} - HTML reference, where button should be added
     * @param {Object} - all options, by btnName refer to particular button
     * @param {String} - name of functionality mapped for specific class
     * @param {Object} - All titles, by btnName refer to particular button
     * @return {Object} - references to all created HTML elements
     */
    addButton: function (target, options, btnName, lang) {
        var btnOptions = options[btnName], items = btnOptions.items, classMapping = H.Toolbar.prototype.classMapping, userClassName = btnOptions.className || '', mainButton, submenuArrow, buttonWrapper;
        // main button wrapper
        buttonWrapper = createElement(LI, {
            className: pick(classMapping[btnName], '') + ' ' + userClassName,
            title: lang[btnName] || btnName
        }, null, target);
        // single button
        mainButton = createElement(SPAN, {
            className: PREFIX + 'menu-item-btn'
        }, null, buttonWrapper);
        // submenu
        if (items && items.length) {
            // arrow is a hook to show / hide submenu
            submenuArrow = createElement(SPAN, {
                className: PREFIX + 'submenu-item-arrow ' +
                    PREFIX + 'arrow-right'
            }, null, buttonWrapper);
            submenuArrow.style['background-image'] = 'url(' +
                this.iconsURL + 'arrow-bottom.svg)';
        }
        else {
            mainButton.style['background-image'] = 'url(' +
                this.iconsURL + btnOptions.symbol + ')';
        }
        return {
            buttonWrapper: buttonWrapper,
            mainButton: mainButton,
            submenuArrow: submenuArrow
        };
    },
    /*
     * Create navigation's HTML elements: container and arrows.
     *
     */
    addNavigation: function () {
        var stockToolbar = this, wrapper = stockToolbar.wrapper;
        // arrow wrapper
        stockToolbar.arrowWrapper = createElement(DIV, {
            className: PREFIX + 'arrow-wrapper'
        });
        stockToolbar.arrowUp = createElement(DIV, {
            className: PREFIX + 'arrow-up'
        }, null, stockToolbar.arrowWrapper);
        stockToolbar.arrowUp.style['background-image'] =
            'url(' + this.iconsURL + 'arrow-right.svg)';
        stockToolbar.arrowDown = createElement(DIV, {
            className: PREFIX + 'arrow-down'
        }, null, stockToolbar.arrowWrapper);
        stockToolbar.arrowDown.style['background-image'] =
            'url(' + this.iconsURL + 'arrow-right.svg)';
        wrapper.insertBefore(stockToolbar.arrowWrapper, wrapper.childNodes[0]);
        // attach scroll events
        stockToolbar.scrollButtons();
    },
    /*
     * Add events to navigation (two arrows) which allows user to scroll
     * top/down GUI buttons, if container's height is not enough.
     *
     */
    scrollButtons: function () {
        var targetY = 0, _self = this, wrapper = _self.wrapper, toolbar = _self.toolbar, step = 0.1 * wrapper.offsetHeight; // 0.1 = 10%
        _self.eventsToUnbind.push(addEvent(_self.arrowUp, 'click', function () {
            if (targetY > 0) {
                targetY -= step;
                toolbar.style['margin-top'] = -targetY + 'px';
            }
        }));
        _self.eventsToUnbind.push(addEvent(_self.arrowDown, 'click', function () {
            if (wrapper.offsetHeight + targetY <=
                toolbar.offsetHeight + step) {
                targetY += step;
                toolbar.style['margin-top'] = -targetY + 'px';
            }
        }));
    },
    /*
     * Create stockTools HTML main elements.
     *
     */
    createHTML: function () {
        var stockToolbar = this, chart = stockToolbar.chart, guiOptions = stockToolbar.options, container = chart.container, navigation = chart.options.navigation, bindingsClassName = navigation && navigation.bindingsClassName, listWrapper, toolbar, wrapper;
        // create main container
        stockToolbar.wrapper = wrapper = createElement(DIV, {
            className: PREFIX + 'stocktools-wrapper ' +
                guiOptions.className + ' ' + bindingsClassName
        });
        container.parentNode.insertBefore(wrapper, container);
        // toolbar
        stockToolbar.toolbar = toolbar = createElement(UL, {
            className: PREFIX + 'stocktools-toolbar ' +
                guiOptions.toolbarClassName
        });
        // add container for list of buttons
        stockToolbar.listWrapper = listWrapper = createElement(DIV, {
            className: PREFIX + 'menu-wrapper'
        });
        wrapper.insertBefore(listWrapper, wrapper.childNodes[0]);
        listWrapper.insertBefore(toolbar, listWrapper.childNodes[0]);
        stockToolbar.showHideToolbar();
        // add navigation which allows user to scroll down / top GUI buttons
        stockToolbar.addNavigation();
    },
    /**
     * Function called in redraw verifies if the navigation should be visible.
     * @private
     */
    showHideNavigatorion: function () {
        // arrows
        // 50px space for arrows
        if (this.visible &&
            this.toolbar.offsetHeight > (this.wrapper.offsetHeight - 50)) {
            this.arrowWrapper.style.display = 'block';
        }
        else {
            // reset margin if whole toolbar is visible
            this.toolbar.style.marginTop = '0px';
            // hide arrows
            this.arrowWrapper.style.display = 'none';
        }
    },
    /**
     * Create button which shows or hides GUI toolbar.
     * @private
     */
    showHideToolbar: function () {
        var stockToolbar = this, chart = this.chart, wrapper = stockToolbar.wrapper, toolbar = this.listWrapper, submenu = this.submenu, visible = this.visible, showhideBtn;
        // Show hide toolbar
        this.showhideBtn = showhideBtn = createElement(DIV, {
            className: PREFIX + 'toggle-toolbar ' + PREFIX + 'arrow-left'
        }, null, wrapper);
        showhideBtn.style['background-image'] =
            'url(' + this.iconsURL + 'arrow-right.svg)';
        if (!visible) {
            // hide
            if (submenu) {
                submenu.style.display = 'none';
            }
            showhideBtn.style.left = '0px';
            stockToolbar.visible = visible = false;
            toolbar.classList.add(PREFIX + 'hide');
            showhideBtn.classList.toggle(PREFIX + 'arrow-right');
            wrapper.style.height = showhideBtn.offsetHeight + 'px';
        }
        else {
            wrapper.style.height = '100%';
            showhideBtn.style.top = getStyle(toolbar, 'padding-top') + 'px';
            showhideBtn.style.left = (wrapper.offsetWidth +
                getStyle(toolbar, 'padding-left')) + 'px';
        }
        // Toggle menu
        stockToolbar.eventsToUnbind.push(addEvent(showhideBtn, 'click', function () {
            chart.update({
                stockTools: {
                    gui: {
                        visible: !visible,
                        placed: true
                    }
                }
            });
        }));
    },
    /*
     * In main GUI button, replace icon and class with submenu button's
     * class / symbol.
     *
     * @param {HTMLDOMElement} - submenu button
     * @param {Boolean} - true or false
     *
     */
    switchSymbol: function (button, redraw) {
        var buttonWrapper = button.parentNode, buttonWrapperClass = buttonWrapper.classList.value, 
        // main button in first level og GUI
        mainNavButton = buttonWrapper.parentNode.parentNode;
        // set class
        mainNavButton.className = '';
        if (buttonWrapperClass) {
            mainNavButton.classList.add(buttonWrapperClass.trim());
        }
        // set icon
        mainNavButton
            .querySelectorAll('.' + PREFIX + 'menu-item-btn')[0]
            .style['background-image'] =
            button.style['background-image'];
        // set active class
        if (redraw) {
            this.selectButton(mainNavButton);
        }
    },
    /*
     * Set select state (active class) on button.
     *
     * @param {HTMLDOMElement} - button
     *
     */
    selectButton: function (button) {
        if (button.className.indexOf(activeClass) >= 0) {
            button.classList.remove(activeClass);
        }
        else {
            button.classList.add(activeClass);
        }
    },
    /*
     * Remove active class from all buttons except defined.
     *
     * @param {HTMLDOMElement} - button which should not be deactivated
     *
     */
    unselectAllButtons: function (button) {
        var activeButtons = button.parentNode
            .querySelectorAll('.' + activeClass);
        [].forEach.call(activeButtons, function (activeBtn) {
            if (activeBtn !== button) {
                activeBtn.classList.remove(activeClass);
            }
        });
    },
    /*
     * Verify if chart is in iframe.
     *
     * @return {Object} - elements translations.
     */
    inIframe: function () {
        try {
            return win.self !== win.top;
        }
        catch (e) {
            return true;
        }
    },
    /*
     * Update GUI with given options.
     *
     * @param {Object} - general options for Stock Tools
     */
    update: function (options) {
        merge(true, this.chart.options.stockTools, options);
        this.destroy();
        this.chart.setStockTools(options);
        // If Stock Tools are updated, then bindings should be updated too:
        if (this.chart.navigationBindings) {
            this.chart.navigationBindings.update();
        }
    },
    /**
     * Destroy all HTML GUI elements.
     * @private
     */
    destroy: function () {
        var stockToolsDiv = this.wrapper, parent = stockToolsDiv && stockToolsDiv.parentNode;
        this.eventsToUnbind.forEach(function (unbinder) {
            unbinder();
        });
        // Remove the empty element
        if (parent) {
            parent.removeChild(stockToolsDiv);
        }
        // redraw
        this.chart.isDirtyBox = true;
        this.chart.redraw();
    },
    /**
     * Redraw, GUI requires to verify if the navigation should be visible.
     * @private
     */
    redraw: function () {
        this.showHideNavigatorion();
    },
    getIconsURL: function () {
        return this.chart.options.navigation.iconsURL ||
            this.options.iconsURL ||
            'https://code.highcharts.com/8.0.4/gfx/stock-icons/';
    },
    /**
     * Mapping JSON fields to CSS classes.
     * @private
     */
    classMapping: {
        circle: PREFIX + 'circle-annotation',
        rectangle: PREFIX + 'rectangle-annotation',
        label: PREFIX + 'label-annotation',
        segment: PREFIX + 'segment',
        arrowSegment: PREFIX + 'arrow-segment',
        ray: PREFIX + 'ray',
        arrowRay: PREFIX + 'arrow-ray',
        line: PREFIX + 'infinity-line',
        arrowLine: PREFIX + 'arrow-infinity-line',
        verticalLine: PREFIX + 'vertical-line',
        horizontalLine: PREFIX + 'horizontal-line',
        crooked3: PREFIX + 'crooked3',
        crooked5: PREFIX + 'crooked5',
        elliott3: PREFIX + 'elliott3',
        elliott5: PREFIX + 'elliott5',
        pitchfork: PREFIX + 'pitchfork',
        fibonacci: PREFIX + 'fibonacci',
        parallelChannel: PREFIX + 'parallel-channel',
        measureX: PREFIX + 'measure-x',
        measureY: PREFIX + 'measure-y',
        measureXY: PREFIX + 'measure-xy',
        verticalCounter: PREFIX + 'vertical-counter',
        verticalLabel: PREFIX + 'vertical-label',
        verticalArrow: PREFIX + 'vertical-arrow',
        currentPriceIndicator: PREFIX + 'current-price-indicator',
        indicators: PREFIX + 'indicators',
        flagCirclepin: PREFIX + 'flag-circlepin',
        flagDiamondpin: PREFIX + 'flag-diamondpin',
        flagSquarepin: PREFIX + 'flag-squarepin',
        flagSimplepin: PREFIX + 'flag-simplepin',
        zoomX: PREFIX + 'zoom-x',
        zoomY: PREFIX + 'zoom-y',
        zoomXY: PREFIX + 'zoom-xy',
        typeLine: PREFIX + 'series-type-line',
        typeOHLC: PREFIX + 'series-type-ohlc',
        typeCandlestick: PREFIX + 'series-type-candlestick',
        fullScreen: PREFIX + 'full-screen',
        toggleAnnotations: PREFIX + 'toggle-annotations',
        saveChart: PREFIX + 'save-chart',
        separator: PREFIX + 'separator'
    }
};
// Comunication with bindings:
addEvent(H.NavigationBindings, 'selectButton', function (event) {
    var button = event.button, className = PREFIX + 'submenu-wrapper', gui = this.chart.stockTools;
    if (gui && gui.guiEnabled) {
        // Unslect other active buttons
        gui.unselectAllButtons(event.button);
        // If clicked on a submenu, select state for it's parent
        if (button.parentNode.className.indexOf(className) >= 0) {
            button = button.parentNode.parentNode;
        }
        // Set active class on the current button
        gui.selectButton(button);
    }
});
addEvent(H.NavigationBindings, 'deselectButton', function (event) {
    var button = event.button, className = PREFIX + 'submenu-wrapper', gui = this.chart.stockTools;
    if (gui && gui.guiEnabled) {
        // If deselecting a button from a submenu, select state for it's parent
        if (button.parentNode.className.indexOf(className) >= 0) {
            button = button.parentNode.parentNode;
        }
        gui.selectButton(button);
    }
});
