/**
 * @license  Highcharts JS v6.2.0 (2018-10-17)
 *
 * Indicator series type for Highstock
 *
 * (c) 2010-2017 Pawel Fus, Sebastian Bochan
 *
 * License: www.highcharts.com/license
 */
'use strict';
(function (factory) {
	if (typeof module === 'object' && module.exports) {
		module.exports = factory;
	} else if (typeof define === 'function' && define.amd) {
		define(function () {
			return factory;
		});
	} else {
		factory(Highcharts);
	}
}(function (Highcharts) {
	(function (H) {

		var pick = H.pick,
		    each = H.each,
		    error = H.error,
		    Series = H.Series,
		    isArray = H.isArray,
		    addEvent = H.addEvent,
		    seriesType = H.seriesType;

		/**
		 * The SMA series type.
		 *
		 * @constructor seriesTypes.sma
		 * @augments seriesTypes.line
		 */
		seriesType('sma', 'line',
		    /**
		     * Simple moving average indicator (SMA). This series requires `linkedTo`
		     * option to be set.
		     *
		     * @extends plotOptions.line
		     * @product highstock
		     * @sample {highstock} stock/indicators/sma Simple moving average indicator
		     * @since 6.0.0
		     * @excluding
		     *             allAreas,colorAxis,compare,compareBase,joinBy,keys,stacking,
		     *             showInNavigator,navigatorOptions,pointInterval,
		     *             pointIntervalUnit,pointPlacement,pointRange,pointStart,joinBy
		     * @optionparent plotOptions.sma
		     */
		    {
		        /**
		         * The name of the series as shown in the legend, tooltip etc. If not
		         * set, it will be based on a technical indicator type and default
		         * params.
		         *
		         * @type {String}
		         * @since 6.0.0
		         * @product highstock
		         */
		        name: undefined,
		        tooltip: {
		            /**
		             * Number of decimals in indicator series.
		             *
		             * @type {Number}
		             * @since 6.0.0
		             * @product highstock
		             */
		            valueDecimals: 4
		        },
		        /**
		         * The main series ID that indicator will be based on. Required for this
		         * indicator.
		         *
		         * @type {String}
		         * @since 6.0.0
		         * @product highstock
		         */
		        linkedTo: undefined,
		        params: {
		            /**
		             * The point index which indicator calculations will base. For
		             * example using OHLC data, index=2 means the indicator will be
		             * calculated using Low values.
		             *
		             * @type {Number}
		             * @since 6.0.0
		             * @product highstock
		             */
		            index: 0,
		            /**
		             * The base period for indicator calculations. This is the number of
		             * data points which are taken into account for the indicator
		             * calculations.
		             *
		             * @type {Number}
		             * @since 6.0.0
		             * @product highstock
		             */
		            period: 14
		        }
		    }, /** @lends Highcharts.Series.prototype */ {
		        bindTo: {
		            series: true,
		            eventName: 'updatedData'
		        },
		        useCommonDataGrouping: true,
		        nameComponents: ['period'],
		        nameSuffixes: [], // e.g. Zig Zag uses extra '%'' in the legend name
		        calculateOn: 'init',
		        init: function (chart, options) {
		            var indicator = this;

		            Series.prototype.init.call(
		                indicator,
		                chart,
		                options
		            );

		            // Make sure we find series which is a base for an indicator
		            chart.linkSeries();

		            indicator.dataEventsToUnbind = [];

		            function recalculateValues() {
		                var oldDataLength = (indicator.xData || []).length,
		                    processedData = indicator.getValues(
		                        indicator.linkedParent,
		                        indicator.options.params
		                    ) || {
		                        values: [],
		                        xData: [],
		                        yData: []
		                    };

		                // If number of points is the same, we need to update points to
		                // reflect changes in all, x and y's, values. However, do it
		                // only for non-grouped data - grouping does it for us (#8572)
		                if (
		                    oldDataLength &&
		                    oldDataLength === processedData.xData.length &&
		                    !indicator.cropped && // #8968
		                    !indicator.hasGroupedData &&
		                    indicator.visible &&
		                    indicator.points
		                ) {
		                    indicator.updateData(processedData.values);
		                } else {
		                    indicator.xData = processedData.xData;
		                    indicator.yData = processedData.yData;
		                    indicator.options.data = processedData.values;
		                }

		                // Removal of processedXData property is required because on
		                // first translate processedXData array is empty
		                if (indicator.bindTo.series === false) {
		                    delete indicator.processedXData;

		                    indicator.isDirty = true;
		                    indicator.redraw();
		                }
		                indicator.isDirtyData = false;
		            }

		            if (!indicator.linkedParent) {
		                return error(
		                    'Series ' +
		                    indicator.options.linkedTo +
		                    ' not found! Check `linkedTo`.'
		                );
		            }

		            indicator.dataEventsToUnbind.push(
		                addEvent(
		                    indicator.bindTo.series ?
		                        indicator.linkedParent : indicator.linkedParent.xAxis,
		                    indicator.bindTo.eventName,
		                    recalculateValues
		                )
		            );

		            if (indicator.calculateOn === 'init') {
		                recalculateValues();
		            } else {
		                var unbinder = addEvent(
		                    indicator.chart,
		                    indicator.calculateOn,
		                    function () {
		                        recalculateValues();
		                        // Call this just once, on init
		                        unbinder();
		                    }
		                );
		            }

		            return indicator;
		        },
		        getName: function () {
		            var name = this.name,
		                params = [];

		            if (!name) {

		                each(
		                    this.nameComponents,
		                    function (component, index) {
		                        params.push(
		                            this.options.params[component] +
		                            pick(this.nameSuffixes[index], '')
		                        );
		                    },
		                    this
		                );

		                name = (this.nameBase || this.type.toUpperCase()) +
		                    (this.nameComponents ? ' (' + params.join(', ') + ')' : '');
		            }

		            return name;
		        },
		        getValues: function (series, params) {
		            var period = params.period,
		                xVal = series.xData,
		                yVal = series.yData,
		                yValLen = yVal.length,
		                range = 0,
		                sum = 0,
		                SMA = [],
		                xData = [],
		                yData = [],
		                index = -1,
		                i,
		                SMAPoint;

		            if (xVal.length < period) {
		                return false;
		            }

		            // Switch index for OHLC / Candlestick / Arearange
		            if (isArray(yVal[0])) {
		                index = params.index ? params.index : 0;
		            }

		            // Accumulate first N-points
		            while (range < period - 1) {
		                sum += index < 0 ? yVal[range] : yVal[range][index];
		                range++;
		            }

		            // Calculate value one-by-one for each period in visible data
		            for (i = range; i < yValLen; i++) {
		                sum += index < 0 ? yVal[i] : yVal[i][index];

		                SMAPoint = [xVal[i], sum / period];
		                SMA.push(SMAPoint);
		                xData.push(SMAPoint[0]);
		                yData.push(SMAPoint[1]);

		                sum -= index < 0 ? yVal[i - range] : yVal[i - range][index];
		            }

		            return {
		                values: SMA,
		                xData: xData,
		                yData: yData
		            };
		        },
		        destroy: function () {
		            each(this.dataEventsToUnbind, function (unbinder) {
		                unbinder();
		            });
		            Series.prototype.destroy.call(this);
		        }
		    });

		/**
		 * A `SMA` series. If the [type](#series.sma.type) option is not
		 * specified, it is inherited from [chart.type](#chart.type).
		 *
		 * @type {Object}
		 * @since 6.0.0
		 * @extends series,plotOptions.sma
		 * @excluding data,dataParser,dataURL
		 * @product highstock
		 * @apioption series.sma
		 */


		/**
		 * An array of data points for the series. For the `SMA` series type,
		 * points are calculated dynamically.
		 *
		 * @type {Array<Object|Array>}
		 * @since 6.0.0
		 * @extends series.line.data
		 * @product highstock
		 * @apioption series.sma.data
		 */

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


	}());
}));
