#ifndef QRK_MOVING_AVERAGE_H
#define QRK_MOVING_AVERAGE_H

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

  \author Satofumi KAMIMURA

  $Id: MovingAverage.h 1414 2009-10-14 23:14:02Z 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 */
