#ifndef GAUSSIAN_H
#define GAUSSIAN_H 1

#include "AdvFuncBase.hh"

#define NumberOfParamForGaussian 3U

/**
 *  gaussian function
 *
 *  the function requires argument x and parmters h, c, w  in order to evaluate
 *  the values of the function, 1st and 2nd order derived coefficients.
 *  h is hte height of the function,
 *  c is the center of the function,
 *  w is the half width at half maximum.
 *  h, c and w can also be given as an array of Douyble type number.
 *
 *  the value of function is maximum at c, and half maximum at x = c+w and x = c-w.
 *  the standard deviation of the function equals to w/log(2.0).
 *  the normalization factor equals to sqrt( log(2.0)/PI )/w. (i.e. the integral of the function from -Inf. to Inf. equals to 1);
 *  the inflection points of the function are x= c+w*sqrt( 1.0/(2.0*log(2.0)) ) and  x = c-w*sqrt( 1.0/(2.0*log(2.0)) ).
 */
class AdvGaussian : public AdvFuncBase {

    private:
        /** constant log(2.0)=0.69.... for HWHM <==> S.D. */
        static const Double LOG2; // = log2;
        /** normalization constatnt,  sqrt(log2/PI); PI=abs(atan2(0.0, -1.0)); */
        static const Double NC;

#ifdef USE_SETTER_GETTER
    private:
        /** height at peak */
        Double h;
        /** center of the peak */
        Double c;
        /** half width at half maximum */
        Double w;
#endif
    //private:
    //    /** flag to normalize */
    //    Bool isNormalized;

    //public:
    //    Double standardDaviation(Double w) { return w/sqrt(2.0*LOG2); };

    public:
        /** default constructor */
        AdvGaussian() ;
        //AdvGaussian(Bool isNormalized);
        //AdvGaussian(Bool isNormalised=false);
        /** copy constructor */
        AdvGaussian(const AdvGaussian &obj);

        /** destructor */
        ~AdvGaussian() ;

        ///** assignment operator */
        //AdvGaussian operator = (const AdvGaussian &obj);

        ///** set normalization flag */
        //void setNormalized(Bool b);

        /** evaluate the value of the function */
        Double eval(const Double x, const Double h, const Double c, const Double w);
#ifdef HAVE_DIFFERENTIAL_MEMBER
        /** evaluate the value of the 1st. differential coefficient */
        Double der1st(const Double x, const Double h, const Double c, const Double w);
        /** evaluate the value of the 2nd. differential coefficient */
        Double der2nd(const Double x, const Double h, const Double c, const Double w);
        /** evaluate the value of differential coefficient for w*/
        Double derW(const Double x, const Double h, const Double c, const Double w);
#endif

#ifdef USE_POINTER
        /** evaluate the value of the function */
        Double eval(const Double x, const Double *p);
#ifdef HAVE_DIFFERENTIAL_MEMBER
        /** evaluate the value of the 1st. differential coefficient */
        Double der1st(const Double x, const Double *p);
        /** evaluate the value of the 2nd. differential coefficient */
        Double der2nd(const Double x, const Double *p);
        /** evaluate the gradient of the function for parameters */
        Double *gradient(const Double x, const Double *p);
#endif // HAVE_DIFFERENTIAL_MEMBER
#endif // USE_POINTER

#ifdef USE_VECTOR
        /** evaluate the value of the function */
        Double eval(const Double x, const std::vector<Double> &p);
#ifdef HAVE_DIFFERENTIAL_MEMBER
        /** evaluate the value of the 1st derivative function */
        Double der1st(const Double x, const std::vector<Double> &p);
        /** evaluate the value of the 2nd derivative function */
        Double der2nd(const Double x, const std::vector<Double> &p);
        /** evaluate the gradient of the function for parameters */
        std::vector<Double> gradient(const Double x, const std::vector<Double> &p);
#endif // HAVE_DIFFERENTIAL_MEMBER
#endif // USE_VECTOR
};

#ifdef USE_SETTER_GETTER
        void    setParam(const Double h, const Double c, const Double w);
        Double  eval(const Double x);
        Double  der1st(const Double x);
        Double  der2nd(const Double x);
#ifdef USE_POINTER
        void setParam(const Double *p) ;
        //Double *getParam();
        //Double *gradient(const Double x);
#endif // UISE_POINTER

#ifdef USE_VECTOR
        void setParam(const std::vector<Double> p);
        //std::vector<Double> getParam();
        //std::vector<Double> gradient(const Double x);
#endif // USE_VECTOR
#endif // USE_SETTER_GETTER

#endif // GAUSSIAN_H
