#include "Spect.h"
#include "DBInt.h"
#include "InterSplineFunc.h"

#include <string>
#include <iostream>
#include <fstream>
#include <sstream>

static const char* data_table = "flux";
static const char* desc_table = "fluxdescr";

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

Spect::Spect()
{
}

Spect::~Spect()
{
}


bool Spect::LoadDataFile(int id, int nutype, double baseline, double angle,
              const char* filename)
{
    ifstream fstr(filename);

    if (!fstr) {
        ERROR << "Can't open \"" << filename << "\"\n";
        return false;
    }
    fId = id;
    fNutype = nutype;
    fBaseline = baseline;
    fAngle = angle;
    double energy;
    while (fstr >> energy) {
        double flux;
        fstr >> flux;

        fEnergy.push_back(energy);
        fFlux.push_back(flux);
    }
    return true;
}


bool Spect::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;
    }

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

    // Get description
    vector<string> vs;
    if (! dbi.GetNthData(id,0,desc_table,"type,baseline,angle","",vs))
        return false;
    fNutype = atoi(vs[0].c_str());
    fBaseline = atof(vs[1].c_str());
    fAngle = atof(vs[1].c_str());
    fId = id;

    return true;
}



void Spect::SetData(int id, int nutype, double baseline, double angle,
             vector<double>& evec, 
             vector<double>& flux)
{
    fId = id;
    fNutype = nutype;
    fBaseline = baseline;
    fAngle = angle;
    fEnergy = evec;
    fFlux = flux;
}



void Spect::GetData(int& id, int& nutype, double& baseline, double& angle,
             vector<double>& evec, 
             vector<double>& flux)
{
    id = fId;
    nutype = fNutype;
    baseline = fBaseline;
    angle = fAngle;
    evec = fEnergy;
    flux = fFlux;
}

    
bool Spect::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] << " "
             << fFlux[i] << endl;
    }
    return true;
    
}


bool Spect::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] << "," 
           << fFlux[i];
        data.push_back(ss.str());
    }

    if (! dbi.SetData(fId,data_table,"energy,flux",data))
        return false;


    // The description
    data.erase(data.begin(), data.end());
    ss.str("");
    ss << fNutype << ","
       << fBaseline << ","
       << fAngle;
    data.push_back(ss.str());

    if (! dbi.SetData(fId,desc_table,"type,baseline,angle",data)) return false;
    return true;

}


InterFunc* Spect::CreateFunc()
{

    InterSplineFunc* isf =
        new InterSplineFunc(fEnergy,fFlux,InterSplineFunc::zero_runout);
    isf->SetMin(0.0);
    return isf;
}

// Get available ids and descriptions
bool Spect::GetAvailable(const char* db_host, 
                  const char* db_user, const char* db_pass,
                  vector<int>& id, 
                  vector<int>& nutype,
                  vector<double>& baseline,
                  vector<double>& angle)
{
    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,desc_table,"type,baseline,angle,id",
                      "type,baseline,angle",data))
        return false;

    int siz = data.size();
    for (int i=0; i<siz; ++i) {
        nutype.push_back(atoi(data[i][0].c_str()));
        baseline.push_back(atof(data[i][1].c_str()));
        angle.push_back(atof(data[i][2].c_str()));
        id.push_back(atoi(data[i][3].c_str()));
    }

    return true;

}

int Spect::GetId(int nutype, double baseline, double angle,
                 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;
    }

    stringstream ss;
    ss << "type = " << nutype
       << " and "
       << bracket_double("baseline",baseline)
       << " and "
       << bracket_double("angle",angle);

    int id = dbi.GetId(desc_table,ss.str());
    if (!id) {
        ERROR << "Failed to get id for table " << desc_table
              << ", nutype = " << nutype
              << ", baseine = " << baseline
              << ", angle = " << angle << endl;
    }
    return id;
}


