#include <iostream>
#include <istream>
#include <ostream>
#include <iomanip>
#include <cstdlib>
#include <cmath>

#include "Header.hh"
#include "ElementContainer.hh"
#include "Gaussian.hh"

void testTitle() {
    std::cout << setiosflags(std::ios::left)  << std::setw(20) << "title";
    std::cout << setiosflags(std::ios::right) << std::setw(23) << "x/hwhm";
    std::cout << setiosflags(std::ios::right) << std::setw(23) << "value/f(0.0)";
#ifdef HAVE_DIFFERENTIATION_MEMBER
    std::cout << setiosflags(std::ios::right) << std::setw(23) << "1st. derivative/f(0.0)";
    std::cout << setiosflags(std::ios::right) << std::setw(23) << "2nd. derivative/f(0.0)";
    std::cout << setiosflags(std::ios::right) << std::setw(23) << "(df/dh)/f(0.0)";
    std::cout << endl;
#endif
}

void testGaussian(string title, Double hwhm, Double x, vector<Double> &p) {

    Gaussian f;
    vector<Double> g;

    g=f.gradient(x, p);

    std::cout << resetiosflags(std::ios::left)       << std::setw(20)                          << title;
    std::cout << resetiosflags(std::ios::showpoint) << std::setw(23) << std::setprecision(5)  << x/hwhm;
    std::cout << resetiosflags(std::ios::showpoint) << std::setw(23) << std::setprecision(15) << f.eval(x, p)/f.eval(0.0, p);
#ifdef HAVE_DIFFERENTIATION_MEMBER
    std::cout << resetiosflags(std::ios::showpoint) << std::setw(23) << std::setprecision(15) << f.der1st(x, p)/f.eval(0.0, p);
    std::cout << resetiosflags(std::ios::showpoint) << std::setw(23) << std::setprecision(15) << f.der2nd(x, p)/f.eval(0.0, p);
    for (UInt4 i=0; i<f.getNumberOfParam(); ++i) {
        std::cout << resetiosflags(std::ios::showpoint) << std::setw(23) << std::setprecision(15) << g.at(i)/f.eval(0.0, p);
    }
#endif
    std::cout << endl;
}


int main(int argc, char *argv[]) {

    Double CENTER=0.0;
    Double HWHM=1.0;

    Double INFLECTION_POINT  =HWHM/sqrt(2.0*log(2.0));

    vector<Double> p;
    p.push_back(1.0);    // height
    p.push_back(CENTER); // center, median
    p.push_back(HWHM);   // HWHM

    testTitle();
    testGaussian(string("hwhm"),               HWHM, -HWHM,               p);
    testGaussian(string("inflection point"),   HWHM, -INFLECTION_POINT,   p);
    testGaussian(string("center"),             HWHM,  CENTER,             p);
    testGaussian(string("inflection point"),   HWHM,  INFLECTION_POINT,   p);
    testGaussian(string("hwhm"),               HWHM,  HWHM,               p);

    return EXIT_SUCCESS;
}
