#ifndef QRK_MOVING_AVERAGE_H
#define QRK_MOVING_AVERAGE_H

/*!
  \file
  \brief 移動平均の計算

  \author Satofumi KAMIMURA

  $Id: MovingAverage.h 1811 2010-04-30 16:12:05Z satofumi $
*/

#include <deque>


namespace qrk
{

    /*!
      \brief 移動平均のテンプレート

      \attention 和が使用している型より大きな値になると、結果が保証されない
    */
    template <class T>
    class MovingAverage
    {
    public:
        /*!
          \brief コンストラクタ

          \param[in] size バッファのサイズ
        */
        MovingAverage(size_t size, T initial_value = 0)
            : buffer_size_(size), total_(0)
        {
            if (buffer_size_ == 0) {
                buffer_size_ = 1;
            }
            buffer_set(buffer_size_, initial_value);
        }


        /*!
          \brief 格納されている平均値の更新

          \param value [i] 更新する平均値
        */
        void setAverageValue(T value)
        {
            buffer_set(buffer_size_, value);
        }


        /*!
          \brief 平均値の取得

          \return 移動平均の値
        */
        T average(void)
        {
            return average_;
        }


        /*!
          \brief 値の追加

          \param[in] value 追加する値

          \return 移動平均の値
        */
        T push_back(T value)
        {
            total_ -= buffer_.front();
            buffer_.pop_front();
            total_ += value;
            buffer_.push_back(value);

            average_ = total_ / buffer_size_;

            return average_;
        }

    private:
        MovingAverage(const MovingAverage& rhs);
        MovingAverage& operator = (const MovingAverage& rhs);

        std::deque<T> buffer_;
        long buffer_size_;
        T average_;
        T total_;


        void buffer_set(size_t size, T value)
        {
            buffer_.assign(size, value);
            average_ = value;
            total_ = average_ * size;
        }
    };
}

#endif /* !QRK_MOVING_AVERAGE_H */
