#include "AdvPseudoVoigt1Conv.hh"
#include <cassert>
#include <iostream>
#include <ostream>
#include <cmath>
#include <numeric>
#include <cfloat>

/** default constructor */
AdvPseudoVoigt1Conv::AdvPseudoVoigt1Conv() : AdvFuncBase(*(new string("pseudo_voigt_1Conv")), *(new string("pv1c")), NumberOfParamForPseudoVoigt1Conv) {
    //std::cerr << "Degub: AdvPseudoVoigt1Conv::AdvPseudoVoigt1Conv(string, string, UInt4): enter" << endl;
    gaussian = *(new AdvGaussian());
    lorentzian = *(new AdvLorentzian());
    //std::cerr << "Degub: AdvPseudoVoigt1Conv::AdvPseudoVoigt1Conv(string, string, UInt4): exit" << endl;
}

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

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

Double AdvPseudoVoigt1Conv::PseudoVoigt1ConvFunc(const Double x,  const Double h, const Double c, const Double w, 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 = PseudoVoigt1Func(x-(ResX.at(i)+ResX.at(i+1))*0.5, h,c,w,m);
        conv_result += f_det*f_res;
        normFactor += ResY.at(i);
        }
     return conv_result/normFactor;
}


#ifdef USE_POINTER
/**
 *  evaluate the value of the function
 *
 *  @param[in] x  argument of the function
 *  @param[in] p  parameters of the function
 */
Double AdvPseudoVoigt1Conv::eval(const Double x, const Double *p) {
    return PseudoVoigt1ConvFunc(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 AdvPseudoVoigt1Conv::der1st(const Double x, const Double *p) {
    std::cout << "Convolution::der1st 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 AdvPseudoVoigt1Conv::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 *AdvPseudoVoigt1Conv::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 AdvPseudoVoigt1Conv::eval(const Double x, const vector<Double> &p) {
    return PseudoVoigt1ConvFunc(x, p[0], p[1], p[2], p[3]);
}

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

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

vector<Double> AdvPseudoVoigt1Conv::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

