#ifndef ERROR_FUNCTION_H
#define ERROR_FUNCTION_H 1

#include <cmath>
#include "gsl/gsl_sf_erf.h"

#include "AdvFuncBase.hh"
#include "AdvGaussian.hh"

#define NumberOfParamForErrorFunction 3U

/** Error function.
 *
 * the function requires argument x and parameters h, c, w in order of evalueation.
 * the values of function, the first and the second  derived coeficients.
 * h is the height (or ampletude) of the functions.
 * c is the only zero point of the functions.
 * w is the width of ...
 * h, c and w can also be given as as an vector of Double type number.
 *
 * erf(x, h, c, w) = h erf((x-c)/w, 1, 0, 1) = h erf((x-c)/w)
 */
class AdvErrorFunction : public AdvFuncBase {

    private:
        /** rate of S.D. <=> HMHW */
        static const Double A; // = sqrt(log(2.0))
        /** normalisation factor */
        static const Double N; // = 2.0/sqrt(PI)

    private:
        /** gauss functions */
        AdvGaussian *gaussian;

    public:
        /** constructor */
        AdvErrorFunction();
        /** copy constructor */
        AdvErrorFunction(const AdvErrorFunction &obj);

        /** destructor */
        virtual ~AdvErrorFunction();

        /** 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 first order differential coefficient */
        Double der1st(const Double x, const Double h, const Double c, const Double w);
        /** evaluate the value of the second order differential coefficient */
        Double der2nd(const Double x, const Double h, const Double c, const Double w);

        /** evaluate the value of the differential coefficient for h */
        Double derH(const Double x, const Double h, const Double c, const Double w);
        /** evaluate the value of the differential coefficient for c */
        Double derC(const Double x, const Double h, const Double c, const Double w);
        /** evaluate the value of the differential coefficient for w */
        Double derW(const Double x, const Double h, const Double c, const Double w);
#endif // HAVE_DIFFERENTIAL_MEMBER

#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 first order differential coefficient */
        Double der1st(const Double x, const Double *p);
        /** evaluate the value of the second order differential coefficient */
        Double der2nd(const Double x, const Double *p);
        /** evaluate the gradiend  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 vector<Double> &p);
#ifdef HAVE_DIFFERENTIAL_MEMBER
        /** evaluate the value of the first order differential coefficient */
        Double der1st(const Double x, const vector<Double> &p);
        /** evaluate the value of the second order differential coefficient */
        Double der2nd(const Double x, const vector<Double> &p);
        /** evaluate the gradiend  of the function for parameters */
        vector<Double> gradient(const Double x, const vector<Double> &p);
#endif // HAVE_DIFFERENTIAL_MEMBER
#endif // USE_VECTOR
};

#endif
