#include "Xsec.h"
#include "DBInt.h"
#include "InterSplineFunc.h"
#include "InterCompoundFunc.h"
#include <iostream>
#include <fstream>
#include <sstream>

#define ERROR cerr << "Xsec:" << __LINE__ << ": "

Xsec::Xsec()
    : desc_table("xsecdescr"), data_table("xsec")
{
}

Xsec::~Xsec()
{
}


void Xsec::Clear()
{
    fEnergy.erase(fEnergy.begin(),fEnergy.end());
    fXsec.erase(fXsec.begin(),fXsec.end());
}

bool Xsec::LoadDataFile(int id, const char* desc, const char* filename)
{
    ifstream fstr(filename);
    if (!fstr) {
        ERROR << "Can't open \"" << filename << "\"\n";
        return false;
    }

    this->Clear();

    fId = id;
    fDescription = desc;
    double energy;
    while (fstr >> energy) {
        double xs;
        fstr >> xs;
        fEnergy.push_back(energy);
        fXsec.push_back(xs);
    }
    return true;
}


bool Xsec::LoadDataDB(int id, const char* db_host, 
                      const char* db_user, const char* db_pass)
{
    DBInt dbi;
    if (! dbi.Init("nuosc",db_host,db_user,db_pass)) {
        ERROR << "Can't connect to db \"nuosc\"\n";
        return false;
    }

    this->Clear();

    // Get data
    vector<vector<string> > data;
    if (! dbi.GetData(id,data_table,"energy,xsec","energy",data))
        return false;
    int siz = data.size();
    for (int i=0; i<siz; ++i) {
        fEnergy.push_back(atof(data[i][0].c_str()));
        fXsec.push_back(atof(data[i][1].c_str()));
    }

    // Get description
    vector<string> vs;
    dbi.GetNthData(id,0,desc_table,"descr","",vs);
    fDescription = vs[0];

    fId = id;
    return true;
}

void Xsec::GetData(int& id, string description,
                   vector<double>& evec, vector<double>& xvec)
{
    id = fId;
    description = fDescription;
    evec = fEnergy;
    xvec = fXsec;
}



    // Set cross section data
void Xsec::SetData(int id, const char* description,
             vector<double>& evec, vector<double>& xvec)
{
    fId = id;
    fDescription = description;
    fEnergy = evec;
    fXsec = xvec;
}

bool Xsec::StoreDataFile(const char* filename)
{
    if (!filename) filename = "/dev/stdout";
    string minus("-");
    if (minus == filename) filename = "/dev/stdout";
    ofstream fstr(filename);
    if (!fstr) {
        ERROR << "Can't open \"" << filename << "\" for writing\n";
        return false;
    }

    int siz = fEnergy.size();
    for (int i = 0; i < siz; ++i) {
        fstr << fEnergy[i] << " "
             << fXsec[i] << endl;
    }
    return true;
}

bool Xsec::StoreDataDB(const char* db_host, const char* db_user, 
                     const char* db_pass)
{
    DBInt dbi;
    if (! dbi.Init("nuosc",db_host,db_user,db_pass)) {
        ERROR << "Can't connect to " << db_user << "@" << db_host
              << ":nuosc\n";
        return false;
    }

    // The data
    stringstream ss;
    vector<string> data;
    int siz = fEnergy.size();
    for (int i=0; i<siz; ++i) {
        ss.str("");
        ss << fEnergy[i] << "," << fXsec[i];
        data.push_back(ss.str());
    }
    if (! dbi.SetData(fId,data_table,"energy,xsec",data)) return false;


    // The description
    data.erase(data.begin(), data.end());
    data.push_back(fDescription);
    if (! dbi.SetData(fId,desc_table,"descr",data)) return false;

    return true;
}

InterFunc* Xsec::CreateFunc()
{
    InterSplineFunc* isf = new InterSplineFunc(fEnergy,fXsec);
    isf->SetMin(0.0);
    return isf;
}

bool Xsec::GetAvailable(const char* db_host, 
                        const char* db_user, const char* db_pass,
                        vector<int>& id, vector<string>& desc)
{
    DBInt dbi;
    if (! dbi.Init("nuosc",db_host,db_user,db_pass)) {
        ERROR << "Can't connect to db \"nuosc\"\n";
        return false;
    }

    // Get data
    vector<vector<string> > data;
    if (! dbi.GetData(-1,"xsecdescr","id,descr","id",data))
        return false;
    int siz = data.size();
    for (int i=0; i<siz; ++i) {
        id.push_back(atoi(data[i][0].c_str()));
        desc.push_back(data[i][1].c_str());
    }

    return true;
}

InterFunc* xsec_creator(int channels[], double weights[])
{
    InterAddedFunc* xsec = new InterAddedFunc;    
    
    Xsec xsec_db;

    for (int i=0; channels[i]; ++i) {
        xsec_db.LoadDataDB(channels[i]);
        xsec->Add(xsec_db.CreateFunc(),weights[i]);
    }

    return xsec;
}

InterFunc* xsec_create_nue_cc()
{
    int channels[] = { 1, 3, 4, 17, 0 };
    double weights[] = {10, 8, 8, 8};
    return xsec_creator(channels,weights);
}

InterFunc* xsec_create_nue_nc()
{
    int channels[] = { 10, 11, 13, 14, 0 };
    double weights[] = { 10, 10, 8, 8 };
    return xsec_creator(channels,weights);
}

InterFunc* xsec_create_numu_cc()
{
    int channels[] = { 1, 2, 3, 4, 0 };
    double weights[] = { 10, 8, 8, 8};
    return xsec_creator(channels,weights);
}

InterFunc* xsec_create_numu_nc()
{
    int channels[] = { 10, 11, 13, 14, 0 };
    double weights[] = { 10, 10, 8, 8 };
    return xsec_creator(channels,weights);
}



