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

#include "Header.hh"
#include "AugmentedLorentzian.hh"

void testTitle() {
    std::cout << std::setw(20) << setiosflags(std::ios::right) << "title";
    std::cout << std::setw(23) << setiosflags(std::ios::right) << "x/HWHM";
    std::cout << std::setw(23) << setiosflags(std::ios::right) << "value/f(0.0)";
    std::cout << std::setw(23) << setiosflags(std::ios::right) << "1st. derivative/f(0.0)";
    std::cout << std::setw(23) << setiosflags(std::ios::right) << "2nd. derivative/f(0.0)";
    std::cout << endl;
}

void testLorentzian(string title, Double x, vector<Double> &p, Double hwhm) {
    AugmentedLorentzian f;

    vector<Double> g=f.gradient(x, p);

    std::cout << setiosflags(std::ios::left)       << std::setw(20) << title;
    std::cout << setiosflags(std::ios::scientific) << std::setw(23) << std::setprecision(15) << x/hwhm;
    std::cout << setiosflags(std::ios::scientific) << std::setw(23) << std::setprecision(15) << f.eval(x, p)/f.eval(0.0, p);
    std::cout << setiosflags(std::ios::scientific) << std::setw(23) << std::setprecision(15) << f.der1st(x, p)/f.eval(0.0, p);
    std::cout << setiosflags(std::ios::scientific) << 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 << setiosflags(std::ios::scientific) << std::setw(23) << std::setprecision(15) << g.at(i)/f.eval(0.0, p);
    }
    std::cout << endl;
}

Int4 main(Int4 argc, Char *argv[]) {

    Double CENTER=0.0;
    Double WIDTH =1.0; // hwhm of Lorentzian
    Double POWER =1.0; // power of denominator

    Double HWHM=sqrt(pow(2.0, 1.0/POWER) - 1.0)*WIDTH;
    Double INFLECTION_POINT  =1.0/sqrt(2.0*POWER + 1.0);

    vector<Double> p;
    p.push_back(1.0);    // height
    p.push_back(CENTER); // center, median
    p.push_back(WIDTH);  // width
    p.push_back(POWER);  // power of denominator

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


    return EXIT_SUCCESS;
}
