using FishNet.Documenting;
using System;
using UnityEngine;

namespace FishNet.Managing.Timing
{

    [APIExclude]
    public class MovingAverage
    {
        #region Public.
        /// <summary>
        /// Average from samples favoring the most recent sample.
        /// </summary>
        public float Average { get; private set; }
        #endregion

        /// <summary>
        /// Next index to write a sample to.
        /// </summary>
        private int _writeIndex;
        /// <summary>
        /// Collected samples.
        /// </summary>
        private float[] _samples;
        /// <summary>
        /// Number of samples written. Will be at most samples size.
        /// </summary>
        private int _writtenSamples;
        /// <summary>
        /// Samples accumulated over queue.
        /// </summary>
        private float _sampleAccumulator;

        public MovingAverage(int sampleSize)
        {
            if (sampleSize < 0)
                sampleSize = 0;
            else if (sampleSize < 2)
                NetworkManager.StaticLogWarning("Using a sampleSize of less than 2 will always return the most recent value as Average.");

            _samples = new float[sampleSize];
        }


        /// <summary>
        /// Computes a new windowed average each time a new sample arrives
        /// </summary>
        /// <param name="newSample"></param>
        public void ComputeAverage(float newSample)
        {
            if (_samples.Length <= 1)
            {
                Average = newSample;
                return;
            }

            _sampleAccumulator += newSample;
            _samples[_writeIndex] = newSample;

            //Increase writeIndex.
            _writeIndex++;
            _writtenSamples = Math.Max(_writtenSamples, _writeIndex);
            if (_writeIndex >= _samples.Length)
                _writeIndex = 0;

            Average = _sampleAccumulator / _writtenSamples;

            /* If samples are full then drop off
            * the oldest sample. This will always be
            * the one just after written. The entry isn't
            * actually removed from the array but will
            * be overwritten next sample. */
            if (_writtenSamples >= _samples.Length)
                _sampleAccumulator -= _samples[_writeIndex];

        }
    }


}