/**
 * @license Highcharts JS v6.1.1 (2018-06-27)
 * Drag-panes module
 *
 * (c) 2010-2017 Highsoft AS
 * Author: Kacper Madej
 *
 * License: www.highcharts.com/license
 */
'use strict';
(function (factory) {
	if (typeof module === 'object' && module.exports) {
		module.exports = factory;
	} else {
		factory(Highcharts);
	}
}(function (Highcharts) {
	(function (H) {
		/**
		 * Plugin for resizing axes / panes in a chart.
		 *
		 * (c) 2010-2017 Highsoft AS
		 * Author: Kacper Madej
		 *
		 * License: www.highcharts.com/license
		 */


		var hasTouch = H.hasTouch,
		    merge = H.merge,
		    wrap = H.wrap,
		    each = H.each,
		    isNumber = H.isNumber,
		    addEvent = H.addEvent,
		    relativeLength = H.relativeLength,
		    objectEach = H.objectEach,
		    Axis = H.Axis,
		    Pointer = H.Pointer,

		    /**
		     * Default options for AxisResizer.
		     */
		    resizerOptions = {
		        /**
		         * Minimal size of a resizable axis. Could be set as a percent
		         * of plot area or pixel size.
		         *
		         * This feature requires the `drag-panes.js` module.
		         *
		         * @type      {Number|String}
		         * @product   highstock
		         * @sample    {highstock} stock/yaxis/resize-min-max-length
		         *            minLength and maxLength
		         * @apioption yAxis.minLength
		         */
		        minLength: '10%',

		        /**
		         * Maximal size of a resizable axis. Could be set as a percent
		         * of plot area or pixel size.
		         *
		         * This feature requires the `drag-panes.js` module.
		         *
		         * @type      {String|Number}
		         * @product   highstock
		         * @sample    {highstock} stock/yaxis/resize-min-max-length
		         *            minLength and maxLength
		         * @apioption yAxis.maxLength
		         */
		        maxLength: '100%',

		        /**
		         * Options for axis resizing. This feature requires the
		         * `drag-panes.js` -
		         * [classic](http://code.highcharts.com/stock/modules/drag-panes.js) or
		         * [styled](http://code.highcharts.com/stock/js/modules/drag-panes.js)
		         * mode - module.
		         *
		         * @product highstock
		         * @sample    {highstock} stock/demo/candlestick-and-volume
		         *          Axis resizing enabled
		         * @optionparent yAxis.resize
		         */
		        resize: {

		            /**
		             * Contains two arrays of axes that are controlled by control line
		             * of the axis.
		             *
		             * This feature requires the `drag-panes.js` module.
		             */
		            controlledAxis: {

		                /**
		                 * Array of axes that should move out of the way of resizing
		                 * being done for the current axis. If not set, the next axis
		                 * will be used.
		                 *
		                 * This feature requires the `drag-panes.js` module.
		                 *
		                 * @type    {Array<String|Number>}
		                 * @default []
		                 * @sample  {highstock} stock/yaxis/multiple-resizers
		                 *          Three panes with resizers
		                 * @sample  {highstock} stock/yaxis/resize-multiple-axes
		                 *          One resizer controlling multiple axes
		                 */
		                next: [],

		                /**
		                 * Array of axes that should move with the current axis
		                 * while resizing.
		                 *
		                 * This feature requires the `drag-panes.js` module.
		                 *
		                 * @type    {Array<String|Number>}
		                 * @sample  {highstock} stock/yaxis/multiple-resizers
		                 *          Three panes with resizers
		                 * @sample  {highstock} stock/yaxis/resize-multiple-axes
		                 *          One resizer controlling multiple axes
		                 */
		                prev: []
		            },

		            /**
		             * Enable or disable resize by drag for the axis.
		             *
		             * This feature requires the `drag-panes.js` module.
		             *
		             * @sample {highstock} stock/demo/candlestick-and-volume
		             *         Enabled resizer
		             */
		            enabled: false,

            

		            /**
		             * Horizontal offset of the control line.
		             *
		             * This feature requires the `drag-panes.js` module.
		             *
		             * @sample {highstock} stock/yaxis/styled-resizer Styled resizer
		             */
		            x: 0,

		            /**
		             * Vertical offset of the control line.
		             *
		             * This feature requires the `drag-panes.js` module.
		             *
		             * @sample {highstock} stock/yaxis/styled-resizer Styled resizer
		             */
		            y: 0
		        }
		    };
		merge(true, Axis.prototype.defaultYAxisOptions, resizerOptions);

		/**
		 * The AxisResizer class.
		 * @param {Object} axis - main axis for the AxisResizer.
		 * @class
		 */
		H.AxisResizer = function (axis) {
		    this.init(axis);
		};

		H.AxisResizer.prototype = {
		    /**
		     * Initiate the AxisResizer object.
		     * @param {Object} axis - main axis for the AxisResizer.
		     */
		    init: function (axis, update) {
		        this.axis = axis;
		        this.options = axis.options.resize;
		        this.render();

		        if (!update) {
		            // Add mouse events.
		            this.addMouseEvents();
		        }
		    },

		    /**
		     * Render the AxisResizer
		     */
		    render: function () {
		        var resizer = this,
		            axis = resizer.axis,
		            chart = axis.chart,
		            options = resizer.options,
		            x = options.x,
		            y = options.y,
		            // Normalize control line position according to the plot area
		            pos = Math.min(
		                Math.max(
		                    axis.top + axis.height + y,
		                    chart.plotTop
		                ),
		                chart.plotTop + chart.plotHeight
		            ),
		            attr = {},
		            lineWidth;

        

		        // Register current position for future reference.
		        resizer.lastPos = pos - y;

		        if (!resizer.controlLine) {
		            resizer.controlLine = chart.renderer.path()
		                .addClass('highcharts-axis-resizer');
		        }

		        // Add to axisGroup after axis update, because the group is recreated
        
		        // Do .add() before path is calculated because strokeWidth() needs it.
        
		        resizer.controlLine.add(axis.axisGroup);

        
		        lineWidth = resizer.controlLine.strokeWidth();
        
		        attr.d = chart.renderer.crispLine(
		            [
		                'M', axis.left + x, pos,
		                'L', axis.left + axis.width + x, pos
		            ],
		            lineWidth
		        );

		        resizer.controlLine.attr(attr);
		    },

		    /**
		     * Set up the mouse and touch events for the control line.
		     */
		    addMouseEvents: function () {
		        var resizer = this,
		            ctrlLineElem = resizer.controlLine.element,
		            container = resizer.axis.chart.container,
		            eventsToUnbind = [],
		            mouseMoveHandler,
		            mouseUpHandler,
		            mouseDownHandler;

		        /**
		         * Create mouse events' handlers.
		         * Make them as separate functions to enable wrapping them:
		         */
		        resizer.mouseMoveHandler = mouseMoveHandler = function (e) {
		            resizer.onMouseMove(e);
		        };
		        resizer.mouseUpHandler = mouseUpHandler = function (e) {
		            resizer.onMouseUp(e);
		        };
		        resizer.mouseDownHandler = mouseDownHandler = function (e) {
		            resizer.onMouseDown(e);
		        };

		        /**
		         * Add mouse move and mouseup events. These are bind to doc/container,
		         * because resizer.grabbed flag is stored in mousedown events.
		        */
		        eventsToUnbind.push(
		            addEvent(container, 'mousemove', mouseMoveHandler),
		            addEvent(container.ownerDocument, 'mouseup', mouseUpHandler),
		            addEvent(ctrlLineElem, 'mousedown', mouseDownHandler)
		        );

		        // Touch events.
		        if (hasTouch) {
		            eventsToUnbind.push(
		                addEvent(container, 'touchmove', mouseMoveHandler),
		                addEvent(container.ownerDocument, 'touchend', mouseUpHandler),
		                addEvent(ctrlLineElem, 'touchstart', mouseDownHandler)
		            );
		        }

		        resizer.eventsToUnbind = eventsToUnbind;
		    },

		    /**
		     * Mouse move event based on x/y mouse position.
		     * @param {Object} e  - mouse event.
		     */
		    onMouseMove: function (e) {
		        /*
		         * In iOS, a mousemove event with e.pageX === 0 is fired when holding
		         * the finger down in the center of the scrollbar. This should
		         * be ignored. Borrowed from Navigator.
		        */
		        if (!e.touches || e.touches[0].pageX !== 0) {
		            // Drag the control line
		            if (this.grabbed) {
		                this.hasDragged = true;
		                this.updateAxes(this.axis.chart.pointer.normalize(e).chartY -
		                    this.options.y);
		            }
		        }
		    },

		    /**
		     * Mouse up event based on x/y mouse position.
		     * @param {Object} e - mouse event.
		     */
		    onMouseUp: function (e) {
		        if (this.hasDragged) {
		            this.updateAxes(this.axis.chart.pointer.normalize(e).chartY -
		                this.options.y);
		        }

		        // Restore runPointActions.
		        this.grabbed = this.hasDragged = this.axis.chart.activeResizer = null;
		    },

		    /**
		     * Mousedown on a control line.
		     * Will store necessary information for drag&drop.
		     */
		    onMouseDown: function () {
		        // Clear all hover effects.
		        this.axis.chart.pointer.reset(false, 0);

		        // Disable runPointActions.
		        this.grabbed = this.axis.chart.activeResizer = true;
		    },

		    /**
		     * Update all connected axes after a change of control line position
		     */
		    updateAxes: function (chartY) {
		        var resizer = this,
		            chart = resizer.axis.chart,
		            axes = resizer.options.controlledAxis,
		            nextAxes = axes.next.length === 0 ?
		                [H.inArray(resizer.axis, chart.yAxis) + 1] : axes.next,
		            // Main axis is included in the prev array by default
		            prevAxes = [resizer.axis].concat(axes.prev),
		            axesConfigs = [], // prev and next configs
		            stopDrag = false,
		            plotTop = chart.plotTop,
		            plotHeight = chart.plotHeight,
		            plotBottom = plotTop + plotHeight,
		            yDelta,
		            normalize = function (val, min, max) {
		                return Math.round(Math.min(Math.max(val, min), max));
		            };

		        // Normalize chartY to plot area limits
		        chartY = Math.max(Math.min(chartY, plotBottom), plotTop);

		        yDelta = chartY - resizer.lastPos;

		        // Update on changes of at least 1 pixel in the desired direction
		        if (yDelta * yDelta < 1) {
		            return;
		        }

		        // First gather info how axes should behave
		        each([prevAxes, nextAxes], function (axesGroup, isNext) {
		            each(axesGroup, function (axisInfo, i) {
		                // Axes given as array index, axis object or axis id
		                var axis = isNumber(axisInfo) ?
		                        // If it's a number - it's an index
		                        chart.yAxis[axisInfo] :
		                        (
		                            // If it's first elem. in first group
		                            (!isNext && !i) ?
		                                // then it's an Axis object
		                                axisInfo :
		                                // else it should be an id
		                                chart.get(axisInfo)
		                        ),
		                    axisOptions = axis && axis.options,
		                    optionsToUpdate = {},
		                    hDelta = 0,
		                    height, top,
		                    minLength, maxLength;

		                // Skip if axis is not found
		                // or it is navigator's yAxis (#7732)
		                if (
		                    !axisOptions ||
		                    axisOptions.id === 'navigator-y-axis'
		                ) {
		                    return;
		                }

		                top = axis.top;

		                minLength = Math.round(
		                    relativeLength(
		                        axisOptions.minLength,
		                        plotHeight
		                    )
		                );
		                maxLength = Math.round(
		                    relativeLength(
		                        axisOptions.maxLength,
		                        plotHeight
		                    )
		                );

		                if (isNext) {
		                    // Try to change height first. yDelta could had changed
		                    yDelta = chartY - resizer.lastPos;

		                    // Normalize height to option limits
		                    height = normalize(axis.len - yDelta, minLength, maxLength);

		                    // Adjust top, so the axis looks like shrinked from top
		                    top = axis.top + yDelta;

		                    // Check for plot area limits
		                    if (top + height > plotBottom) {
		                        hDelta = plotBottom - height - top;
		                        chartY += hDelta;
		                        top += hDelta;
		                    }

		                    // Fit to plot - when overflowing on top
		                    if (top < plotTop) {
		                        top = plotTop;
		                        if (top + height > plotBottom) {
		                            height = plotHeight;
		                        }
		                    }

		                    // If next axis meets min length, stop dragging:
		                    if (height === minLength) {
		                        stopDrag = true;
		                    }

		                    axesConfigs.push({
		                        axis: axis,
		                        options: {
		                            top: Math.round(top),
		                            height: height
		                        }
		                    });
		                } else {
		                    // Normalize height to option limits
		                    height = normalize(chartY - top, minLength, maxLength);

		                    // If prev axis meets max length, stop dragging:
		                    if (height === maxLength) {
		                        stopDrag = true;
		                    }

		                    // Check axis size limits
		                    chartY = top + height;
		                    axesConfigs.push({
		                        axis: axis,
		                        options: {
		                            height: height
		                        }
		                    });
		                }

		                optionsToUpdate.height = height;
		            });
		        });

		        // If we hit the min/maxLength with dragging, don't do anything:
		        if (!stopDrag) {
		            // Now update axes:
		            each(axesConfigs, function (config) {
		                config.axis.update(config.options, false);
		            });

		            chart.redraw(false);
		        }
		    },

		    /**
		     * Destroy AxisResizer. Clear outside references, clear events,
		     * destroy elements, nullify properties.
		     */
		    destroy: function () {
		        var resizer = this,
		            axis = resizer.axis;

		        // Clear resizer in axis
		        delete axis.resizer;

		        // Clear control line events
		        if (this.eventsToUnbind) {
		            each(this.eventsToUnbind, function (unbind) {
		                unbind();
		            });
		        }

		        // Destroy AxisResizer elements
		        resizer.controlLine.destroy();

		        // Nullify properties
		        objectEach(resizer, function (val, key) {
		            resizer[key] = null;
		        });
		    }
		};

		// Keep resizer reference on axis update
		Axis.prototype.keepProps.push('resizer');

		// Add new AxisResizer, update or remove it
		addEvent(Axis, 'afterRender', function () {
		    var axis = this,
		        resizer = axis.resizer,
		        resizerOptions = axis.options.resize,
		        enabled;

		    if (resizerOptions) {
		        enabled = resizerOptions.enabled !== false;

		        if (resizer) {
		            // Resizer present and enabled
		            if (enabled) {
		                // Update options
		                resizer.init(axis, true);

		            // Resizer present, but disabled
		            } else {
		                // Destroy the resizer
		                resizer.destroy();
		            }
		        } else {
		            // Resizer not present and enabled
		            if (enabled) {
		                // Add new resizer
		                axis.resizer = new H.AxisResizer(axis);
		            }
		            // Resizer not present and disabled, so do nothing
		        }
		    }
		});

		// Clear resizer on axis remove.
		addEvent(Axis, 'destroy', function (e) {
		    if (!e.keepEvents && this.resizer) {
		        this.resizer.destroy();
		    }
		});

		// Prevent any hover effects while dragging a control line of AxisResizer.
		wrap(Pointer.prototype, 'runPointActions', function (proceed) {
		    if (!this.chart.activeResizer) {
		        proceed.apply(this, Array.prototype.slice.call(arguments, 1));
		    }
		});

		// Prevent default drag action detection while dragging a control line
		// of AxisResizer. (#7563)
		wrap(Pointer.prototype, 'drag', function (proceed) {
		    if (!this.chart.activeResizer) {
		        proceed.apply(this, Array.prototype.slice.call(arguments, 1));
		    }
		});

	}(Highcharts));
	return (function () {


	}());
}));
