#include "AdvPseudoVoigt2Conv.hh"

#include <cmath>
#include <numeric>
#include <cfloat>
/** default constructor */
AdvPseudoVoigt2Conv::AdvPseudoVoigt2Conv() : AdvFuncBase(*(new string("pseudo_voigt_2Conv")), *(new string("pv2c")), NumberOfParamForPseudoVoigt2Conv) {
    this->gaussian   = *(new AdvGaussian()  );
    this->lorentzian = *(new AdvLorentzian());
}

/** copy constructor */
AdvPseudoVoigt2Conv::AdvPseudoVoigt2Conv(const AdvPseudoVoigt2Conv &obj) {
    this->gaussian   = *(new AdvGaussian(obj.gaussian)   );
    this->lorentzian = *(new AdvLorentzian(obj.lorentzian));
}

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

/**
 *  evaluate the value of the function
 *
 *  \param[in] x argument
 *  \param[in] h the height of the function
 *  \param[in] c the center of the function
 *  \param[in] s the HWHM of the gaussian   part, sigma
 *  \param[in] g the HWHM of the lorentzian part, gamma
 *  \param[in] m the linear cobination cefficient for gaussian and lorentzian
 */

Double AdvPseudoVoigt2Conv::PseudoVoigt2Func(const Double x, const Double h, const Double c, const Double s, const Double g, const Double m) {
    return m*(this->gaussian.eval(x, h, c, s)) + (1.0-m)*(this->lorentzian.eval(x, h, c, g));
}


Double AdvPseudoVoigt2Conv::PseudoVoigt2ConvFunc(const Double x, const Double h, const Double c, const Double s, const Double g, const Double m) {

    if(ResY.size()==0) ReadResolutionFile();
    Double normFactor = 0.0;
    Double conv_result = 0.0;
    for (int i=0;i<ResX.size()-1;i++)
        {
        Double f_res = ResY.at(i);
        Double f_det = PseudoVoigt2Func(x-(ResX.at(i)+ResX.at(i+1))*0.5, h,c,s,g,m);
        conv_result += f_det*f_res;
        normFactor += ResY.at(i);
        }
     return conv_result/normFactor;
}

#ifdef HAVE_DIFFERENTIAL_MEMBER
/**
 *  evaluate the value of the 1st diffrentiation coefficient at x
 *
 *  \param[in] x argument
 *  \param[in] h the height of the function
 *  \param[in] c the center of the function
 *  \param[in] s the HWHM of the gaussian   part, sigma
 *  \param[in] g the HWHM of the lorentzian part, gamma
 *  \param[in] m the linear cobination cefficient for gaussian and lorentzian
 */
//Double AdvPseudoVoigt2Conv::der1st(const Double x, const Double h, const Double c, const Double s, const Double g, const Double m) {
//    std::cout << "Convolution::der1st is not implemented" << endl;
//    return DBL_MAX;
//}

/**
 *  evaluate the value of the 2nd diffrentiation coefficient at x
 *
 *  \param[in] x argument
 *  \param[in] h the height of the function
 *  \param[in] c the center of the function
 *  \param[in] s the HWHM of the gaussian   part, sigma
 *  \param[in] g the HWHM of the lorentzian part, gamma
 *  \param[in] m the linear cobination cefficient for gaussian and lorentzian
 */
//Double AdvPseudoVoigt2Conv::der2nd(const Double x, const Double h, const Double c, const Double s, const Double g, const Double m) {
//    std::cout << "Convolution::der2nd is not implemented" << endl;
//    return DBL_MAX;
//}
#endif // HAVE_DIFFERENTIAL_MEMBER

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

#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 AdvPseudoVoigt2Conv::der1st(const Double x, const Double *p) {
    std::cout << "Convolution::der2nd is not implemented" << endl;
    return DBL_MAX;
}

/**
 *  evaluate the value of the 2nd. differential coefficient
 *
 *  @param[in] x  argument of the function
 *  @param[in] p  parameters of the function
 */
Double AdvPseudoVoigt2Conv::der2nd(const Double x, const Double *p) {
    std::cout << "Convolution::der2nd is not implemented" << endl;
    return DBL_MAX;
}

/**
 *  evaluate the gradient of the coefficient for parameters
 *
 *  @param[in] x  argument of the function
 *  @param[in] p  parameters of the function
 */
Double *AdvPseudoVoigt2Conv::gradient(const Double x, const Double *p) {
//    std::cout << "Convolution::gradient is not implemented" << endl;
    return NULL;
}

#endif // HAVE_DIFFERENTIAL_MEMBER
#endif // USE_POINTER

#ifdef USE_VECTOR
Double AdvPseudoVoigt2Conv::eval(const Double x, const vector<Double> &p) {
    return PseudoVoigt2ConvFunc(x, p[0], p[1], p[2], p[3], p[4]);
}

#ifdef HAVE_DIFFERENTIAL_MEMBER
Double AdvPseudoVoigt2Conv::der1st(const Double x, const vector<Double> &p) {
    std::cout << "Convolution::der1st is not implemented" << endl;
    return DBL_MAX;
}

Double AdvPseudoVoigt2Conv::der2nd(const Double x, const vector<Double> &p) {
    std::cout << "Convolution::der2nd is not implemented" << endl;
    return DBL_MAX;
}

vector<Double> AdvPseudoVoigt2Conv::gradient(const Double x, const vector<Double> &p) {
//    std::cout << "Convolution::gradient is not implemented" << endl;
    vector<Double> v;
    v.clear();
    return v;
}
#endif // HAVE_DIFFERENTIAL_MEMBER
#endif // USE_VECTOR

#include "AdvLorentzian.hh"
