#ifndef AdvMovingAverage_h
#define AdvMovingAverage_h

#include "Header.hh"
#include "ElementContainer.hh"
#include "AdvDomain.hh"
#include "AdvParamSet.hh"
#include "AdvMethod.hh"
#include "AdvMessage.hh"

//! moving average for one dimensional histogram.
/*! moving average
 *
 *
 *  @author TANIMORI Souichirou, AdvanceSoft Corp.
 *  @version 0.0
 *
 *  We usually define moving average in the following way:
 *  \f[ y_i(W, U) = \frac{1}{W} \sum_{k=-L}^{U} y_{i+k} * \f]
 *  where, U nad L are the upper and lower bound of the window. and W=U+L+1 is the width of window for average,
 *
 *  \f[
 *       y_i(W, U) =
 *       \begin{eqnarray}
 *           \left\{
 *           \begin{array}
 *               \frac{1}{U+1+i} \sum~{U}_{k=-i}     y_{i+k} (0   \le i \lt L  )\\
 *               \frac{1}{W}     \sum^{U}_{k=-L}     y_{i+k} (L   \le i \lt N-U)\\
 *               \frac{1}{N+L-i} \sum^{N-1-i}_{k=-L} y_{i+k} (N-U \le i \lt N  )\\
 *           \end{array}
 *       \end{eqnarray}
 *  \f]
 *
 *  \f[
 *      \frac{\Delta y_{i}(W, U)}{\Delta x_{i}} =
 *      \begin{eqnarray}
 *          \left\{
 *          \begin{array}
 *              \frac{y_{i+1}(W, U) - y_{i  }(W, U)}{x_{i+1} - x_{i}  } (i=0) \\
 *              \frac{y_{i+1}(W, U) - y_{i-1}(W, U)}{x_{i+1} - x_{i-1}} (1 \le i \le N-2)) \\
 *              \frac{y_{i  }(W, U) - y_{i-1}(W, U)}{x_{i  } - x_{i-1}} (i=N-1) \\
 *          \end{array}
 *      \end{eqnarray}
 *  \f]
 *
 *  \f[
 *
 *  \f]
 */
class AdvMovingAverage : virtual public AdvMethod, public AdvMessage {

 private:
    static const std::string className; //="AdvMovingAverage"

 public:
    static const std::string WINDOW_WIDTH;    //="window width"
    static const std::string WINDOW_UPPER;    //="window upper"
    static const std::string USE_STRICT_DEFINITION; //="allowe data lost"

    static const Bool DEFAULT_USE_STRICT_DEFINITION; // false;

 private:
    std::vector<Double> srcX, srcXm, srcY, srcE;
    std::vector<Double> *resultX,*resultY, *resultE; // removed *resultXm,

    /*!
     * range of srcBin
     */
    Int4 lower, upper;

    /*!
     *  window width for average
     */
    Int4 windowWidth;
    /*!
     * upper offset for the average window
     */
    Int4 windowUpper;

    /*!
     * lower offset for the average window
     */
    Int4 windowLower;

 private:

    /*!
     *  do moving average
     *
     *  @param[in] src double type std::vector as source
     */
    std::vector<Double> *do_moving_average(std::vector<Double> &src);

    /*!
     *  difference quotient
     *
     *  @param[in] srcXm data points
     *  @param[in] srcY  source value
     */
    std::vector<Double> *diff_quot(std::vector<Double> &x, std::vector<Double> &y);

 protected:

    /*!
     *  calcurate the likehood for the method
     */
    Double likehood();

 public:

    /*!
     *  constructor
     */
    AdvMovingAverage();

    /*!
     *  destructor
     */
    ~AdvMovingAverage();


    /*!
     *  set parameters to the default values
     */
    AdvParamSet setDefaultParam(ElementContainer &src) ;

    /*!
     *  check parameters
     */
    Bool checkParam(ElementContainer &src, AdvDomain &domain, AdvParamSet &param) ;

    /*!
     *  translate parameters in inner form
     */
    void toInnerForm( ElementContainer &src,  AdvDomain &domain,  AdvParamSet &param);

    /*!
     *  do nothing
     */
    void fit();

    /*!
     *  carry out moving average
     */
    void eval();

    /*!
     *  add the results to an element container
     */
    void toElementContainer(ElementContainer &src, ElementContainer &dest) const ;

    /*!
     *  get the description of parameters for the method
     */
    void getParamDescription() const ;

    AdvParamSet* getLatestConvergenceStat() const { return NULL; }

    /*!
     *  return a set of parameters for the method
     */
    AdvParamSet getFittedParam() const ;

    /*!
     *  \retval true,  if the function is differentiable.
     *  \retval false, otherwise
     */
    Bool differentiable() const { return false; };

    Bool isMultiThreaded() const { return false; };

    /*!
     *  get trend, i.e. inclease and decreas table
     */
    std::vector< std::vector<Double> > getTrend();

};


#endif // AdvMovingAverage_h

