#include "Ntuple.h"
#include "cfortran.h"
#include "hbook.h"
#include <cstring>
#include <iostream>

#define MAXTAGS 512


// Read only ctor
Ntuple::Ntuple(const char* filename, int ntid, int lun /*=1*/, const char* rzpath /*=INPUT*/)
    : fReadOnly(true)
      ,fLun(lun)
      ,fID(ntid)
      ,fOffset(99999900)
      ,fNentries(0)
      ,fNvar(0)
      ,fRow(0)
      ,fRZPath(rzpath)
{
    int lrec=1024, istat=0;
    hropen_(&lun,(char*)fRZPath.c_str(),(char*)filename," ",&lrec,&istat,
            fRZPath.size(),strlen(filename),1);
    if (istat) {
        cerr << "Error in Ntuple ctor: can't open " 
             << filename << ", got stat=" << istat << endl;
        exit(istat);
    }

    string name = "C++ ntuple class";
    int nnnn = 999999;
    hrin_(&fID,&nnnn,&fOffset);
    int idpoff = fID+fOffset;
    hnoent_(&idpoff,&fNentries);
    hgnpar_(&idpoff,(char*)name.c_str(),name.size());

    int nvar = MAXTAGS;
    char chtagbuffer[MAXTAGS*80];
    memset(chtagbuffer,' ',MAXTAGS*80*sizeof(char));
    chtagbuffer[MAXTAGS*80-1]='\0';

    float rlow[MAXTAGS];
    float rhigh[MAXTAGS];
    int id = fID+fOffset;
    hgiven_(&id,(char*)fRZPath.c_str(),&nvar,chtagbuffer,rlow,rhigh,fRZPath.size(),80);

    char* chtag[MAXTAGS];
    for (int i=0; i<MAXTAGS; ++i) {
        chtag[i] = chtagbuffer+80*i;
        *strchr(chtag[i],' ') = '\0';
    }

    for (int i=0; i<nvar; ++i) {
        for (int j=0; chtag[i][j]; chtag[i][j]=tolower(chtag[i][j]), ++j);
        string s = chtag[i];
        fIndexMap[s] = i;
        fNames.push_back(s);
    }

    fRow = new float[nvar];

    fNvar = nvar;
}

// Write only ctor
Ntuple::Ntuple(const char* filename, int ntid, const char* title, 
               vector<string>& tags, int lun, const char* rzpath, int nwbuff)
    : fReadOnly(false)
      ,fLun(lun)
      ,fID(ntid)
      ,fOffset(99999900)
      ,fNentries(0)
      ,fNvar(0)
      ,fRow(0)
      ,fRZPath(rzpath)
{
    fNvar = tags.size();
    assert(fNvar <= MAXTAGS);

    int istat=0, ten24 = 1024;
    hropen_(&lun,(char*)fRZPath.c_str(),(char*)filename,"N",&ten24,&istat,
            fRZPath.size(),strlen(filename),1);
    if (istat) {
        cerr << "Failed to open file: \"" << filename << "\" for writing\n";
        abort();
    }


    char chtagbuffer[MAXTAGS*8];
    for (int j=0; j<8*MAXTAGS; ++j) chtagbuffer[j] = ' ';

    for (int i=0; i<fNvar; ++i) {
        int k = tags[i].size();
        if (!(k<8)) k=8;
        for (int j=0; j<k; ++j) chtagbuffer[8*i+j] = tags[i][j];

        fIndexMap[tags[i]] = i;
        fNames.push_back(tags[i]);
    }

    hbookn_(&ntid,(char*)title,&fNvar,(char*)fRZPath.c_str(),&nwbuff,chtagbuffer,
            strlen(title),fRZPath.size(),8);
}


Ntuple::~Ntuple()
{
    if (fReadOnly) {
        int idpoff = fID+fOffset;
        hdelet_(&idpoff);
        hrendc_((char*)fRZPath.c_str(),fRZPath.size());

        if (fRow) delete[] fRow;
    }
    else {
        int icycle=0, zero=0;
        hrout_(&zero,&icycle," ",1);
        hrend_((char*)fRZPath.c_str(),fRZPath.size());
    }
}

void Ntuple::Hlimit(int nwords)
{
    hlimit_(&nwords);
}

void Ntuple::FillRow(float* row)
{
    hfn_(&fID,row);
}

float* Ntuple::operator[](int index) 
{
    static int last_index = -1;
    if (index == last_index) return fRow;

    assert (index >= 0 && index <= fNentries-1);

    memset(fRow,0,sizeof(float)*fNvar);
    int ierror = 0;

    int idpoff=fID+fOffset, indexp1 = index+1;
    hgnf_(&idpoff,&indexp1,fRow,&ierror);

    assert (ierror == 0);

    last_index = index;
    return fRow;
}

float Ntuple::operator()(int row_index, int col_index)
{
    float* row = (*this)[row_index];

    return row[col_index];
}

float Ntuple::operator()(int row_index, const char* name)
{
    int col_index = fIndexMap[name];
    return (*this)(row_index,col_index);
}

