#include "AdvPseudoVoigt1.hh"

#include <iostream>

/** default constructor */
AdvPseudoVoigt1::AdvPseudoVoigt1() : AdvFuncBase(*(new std::string("pseudo_voigt_1")), *(new std::string("pv1")), NumberOfParamForPseudoVoigt1) {
    //std::cerr << "Degub: AdvPseudoVoigt1::AdvPseudoVoigt1(std::string, std::string, UInt4): enter" << std::endl;
    gaussian = *(new AdvGaussian());
    lorentzian = *(new AdvLorentzian());
    //std::cerr << "Degub: AdvPseudoVoigt1::AdvPseudoVoigt1(std::string, std::string, UInt4): exit" << std::endl;
}

/** destructor */
AdvPseudoVoigt1::~AdvPseudoVoigt1() {
}

Double AdvPseudoVoigt1::eval(const Double x, const Double h, const Double c, const Double w, const Double m) {
    //std::cerr << "Degub: AdvPseudoVoigt1::eval(Double, Double, Double, Double, Double): enter" << std::endl;
    //std::cerr.flush();
    return m*gaussian.eval(x, h, c, w) + (1.0-m)*lorentzian.eval(x, h ,c, w);
}

Double AdvPseudoVoigt1::der1st(const Double x, const Double h, const Double c, const Double w, const Double m) {
    return m*gaussian.der1st(x, h, c, w) + (1.0-m)*lorentzian.der1st(x, h ,c, w);
}

Double AdvPseudoVoigt1::der2nd(const Double x, const Double h, const Double c, const Double w, const Double m) {
    return m*gaussian.der2nd(x, h, c, w) + (1.0-m)*lorentzian.der2nd(x, h ,c, w);
}

#ifdef USE_POINTER
/**
 *  evaluate the value of the function
 *
 *  @param[in] x  argument of the function
 *  @param[in] p  parameters of the function
 */
Double AdvPseudoVoigt1::eval(const Double x, const Double *p) {
    return eval(x, p[0], p[1], p[2], p[3]);
}

#ifdef HAVE_DIFFERENTIAL_MEMBER
/**
 *  evaluate the value of the 1st. differential coefficient
 *
 *  @param[in] x  argument of the function
 *  @param[in] p  parameters of the function
 */
Double AdvPseudoVoigt1::der1st(const Double x, const Double *p) {
    return der1st(x, p[0], p[1], p[2], p[3]);
}

/**
 *  evaluate the value of the 2nd. differential coefficient
 *
 *  @param[in] x  argument of the function
 *  @param[in] p  parameters of the function
 */
Double AdvPseudoVoigt1::der2nd(const Double x, const Double *p) {
    return der2nd(x, p[0], p[1], p[2], p[3]);
}

/**
 *  evaluate the gradient of the coefficient for parameters
 *
 *  @param[in] x  argument of the function
 *  @param[in] p  parameters of the function
 */
Double *AdvPseudoVoigt1::gradient(const Double x, const Double *p) {

    Double *tmp1=gaussian.gradient(x, p);
    Double *tmp2=lorentzian.gradient(x, p);
    Double *retval=new Double[NumberOfParamForPseudoVoigt1];
    retval[0]=p[3]*tmp1[0]+(1.0-p[3])*tmp2[0];
    retval[1]=p[3]*tmp1[1]+(1.0-p[3])*tmp2[1];
    retval[2]=p[3]*tmp1[2]+(1.0-p[3])*tmp2[2];
    retval[3]=gaussian.eval(x, p)-lorentzian.eval(x,p);

    delete[] tmp1;
    delete[] tmp2;

    return retval;
}
#endif // HAVE_DIFFERENTIAL_MEMBER
#endif // USE_POINTER

#ifdef USE_VECTOR
Double AdvPseudoVoigt1::eval(const Double x, const std::vector<Double> &p) {
    //std::cerr << "Degub: AdvPseudoVoigt1::eval(Double, std::vector<Double>&): enter" << std::endl;
    //std::cerr.flush();
    return eval(x, p[0], p[1], p[2], p[3]);
}

#ifdef HAVE_DIFFERENTIAL_MEMBER
Double AdvPseudoVoigt1::der1st(const Double x, const std::vector<Double> &p) {
    return der1st(x, p[0], p[1], p[2], p[3]);
}

Double AdvPseudoVoigt1::der2nd(const Double x, const std::vector<Double> &p) {
    return der2nd(x, p[0], p[1], p[2], p[3]);
}

std::vector<Double> AdvPseudoVoigt1::gradient(const Double x, const std::vector<Double> &p) {

    std::vector<Double> pp=*(new std::vector<Double>(3));
    pp[0]=p[1]; pp[1]=p[1]; pp[2]=p[2];
    std::vector<Double> tmp1=gaussian.gradient(x, pp);
    std::vector<Double> tmp2=lorentzian.gradient(x, pp);
    std::vector<Double> *retval=new std::vector<Double>();

    retval->push_back(p[3]*tmp1.at(0)+(1.0-p[3])*tmp2.at(0));
    retval->push_back(p[3]*tmp1.at(1)+(1.0-p[3])*tmp2.at(1));
    retval->push_back(p[3]*tmp1.at(2)+(1.0-p[3])*tmp2.at(2));
    retval->push_back(gaussian.eval(x, p)-lorentzian.eval(x,p));

    tmp1.clear();
    tmp2.clear();

    return *retval;
}
#endif // HAVE_DIFFERENTIAL_MEMBER
#endif // USE_VECTOR

