#include "machdefs.h"

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <typeinfo>

#include "histerr.h"
#include "hist2err.h"

#include "fitsblkrw.h"
#include "fitshandler.h"

namespace SOPHYA {

///////////////////////////////////////////////////////////////////////////
///////////////////////// Histo , HProf , HistoErr ////////////////////////
///////////////////////////////////////////////////////////////////////////

DECL_TEMP_SPEC  /* equivalent a template <> , pour SGI-CC en particulier */
int FitsHandler<HistoErr>::CheckReadability(FitsInOutFile& is)
{
  if (is.CurrentHDUType() == IMAGE_HDU ) return 0;
  string key = "SOPCLSNM";
  string clsnm = is.KeyValue(key);
  if(clsnm == "SOPHYA::HistoErr") return 2;
  return 0;
}

DECL_TEMP_SPEC  /* equivalent a template <> , pour SGI-CC en particulier */
int FitsHandler<HistoErr>::CheckHandling(AnyDataObj & o) 
{  
 if (typeid(o) == typeid(HistoErr)) return 2;
 HistoErr * po = dynamic_cast< HistoErr * >(& o); 
 if (po != NULL) return 2;
 return 0;
}

DECL_TEMP_SPEC  /* equivalent a template <> , pour SGI-CC en particulier */
void FitsHandler<HistoErr>::Write(FitsInOutFile& os)
{
  if(dobj==NULL)   
    throw NullPtrError("FitsHandler<HistoErr>::Write() NULL dobj pointer ");

  //--- Le type d'objet et son pointeur
  HistoErr* he = dynamic_cast< HistoErr *> (dobj);

  //--- Les noms de colonnes
  int tbltyp = os.GetDef_TableType();
  vector<string> colnames, tform, tunit;
  // les valeurs du bin
  if(tbltyp==ASCII_TBL) tform.push_back("D15.8"); else tform.push_back("D");
  colnames.push_back("val");
  tunit.push_back("");
  // Les erreurs
  if(tbltyp==ASCII_TBL) tform.push_back("D15.8"); else tform.push_back("D");
  colnames.push_back("e2");
  tunit.push_back("");
  // Le nombre d'entrees dans le bin
  if(tbltyp==ASCII_TBL) tform.push_back("D15.8"); else tform.push_back("D");
  colnames.push_back("nb");
  tunit.push_back("");

  //--- On cree la table  
  string extname = os.NextExtensionName();
  os.CreateTable(os.GetDef_TableType(),extname,colnames,tform, tunit);

  // Ecriture des donnees des colonnes
  int n = he->NBins();
  if(n>0) {
    FitsBlockRW<r_8>::WriteColumnData(os,1,1,1,&(he->data_(0)),n);
    FitsBlockRW<r_8>::WriteColumnData(os,2,1,1,&(he->err2_(0)),n);
    FitsBlockRW<r_8>::WriteColumnData(os,3,1,1,&(he->ndata_(0)),n);
  }

  // Ecriture des clefs fits
  MuTyV mtv;

  mtv = "SOPHYA::HistoErr";
  os.WriteKey("SOPCLSNM",mtv," SOPHYA class name");

  mtv = "HistoErr";
  os.WriteKey("CONTENT",mtv," name of SOPHYA object");

  mtv = he->NBins();
  os.WriteKey("NBIN",mtv," number of bins");

  mtv = he->XMin();
  os.WriteKey("XMIN",mtv," absc of beginning of 1srt bin");

  mtv = he->XMax();
  os.WriteKey("XMAX",mtv," absc of end of last bin");

  mtv = he->BinWidth();
  os.WriteKey("WBIN",mtv," bin width");
  
  mtv = he->mMean;
  os.WriteKey("NMEAN",mtv," number of Mean/Variance calls");

  return;
}


DECL_TEMP_SPEC  /* equivalent a template <> , pour SGI-CC en particulier */
void FitsHandler<HistoErr>::Read(FitsInOutFile& is)
{
 int hdutyp = is.CurrentHDUType();
 if( (hdutyp != BINARY_TBL ) && (hdutyp != ASCII_TBL) )
    throw FitsIOException("FitsHandler<HistoErr>::Read() Not a binary or ascii table HDU");

  //--- Nb de lignes et de colonnes 
  vector<string> colnames;
  vector<int> coltypes;
  vector<LONGLONG> repcnt, width;
  is.GetColInfo(colnames,coltypes,repcnt,width);
  long ncol = colnames.size();
  if(ncol<=0)
    throw FitsIOException("FitsHandler<HistoErr>::Read() bad number of table columns");
  long nbrows = is.GetNbRows();
  if(nbrows<=0)
    throw FitsIOException("FitsHandler<HistoErr>::Read() number of rows is zero, no reading");

  //--- Lecture entete FITS
  string key = "SOPCLSNM"; string clsnm = is.KeyValue(key);
  DVList dvl; is.GetHeaderRecords(dvl,true,false);

  int_4 nbin = dvl.GetI("NBIN",-1);
  if(nbin<=0 && nbin!=nbrows)
    throw FitsIOException("FitsHandler<HistoErr>::Read() number of bins is zero or bad, no reading");

  r_8 xmin = dvl.GetD("XMIN",-1.);
  r_8 xmax = dvl.GetD("XMAX",+1.);

  //--- Creation de l'objet si necessaire
  if(dobj == NULL) {
    if(clsnm == "SOPHYA::HistoErr") dobj = new HistoErr;
  }

  //--- Type de l'histo
  HistoErr* he = dynamic_cast< HistoErr *> (dobj);

  //--- Allocation pour histo
  if(he && (clsnm=="SOPHYA::HistoErr")) {
    if(ncol<3)
      throw FitsIOException("FitsHandler<HistoErr>::Read() wrong number of columns for HistoErr");
    he->CreateOrResize(xmin,xmax,nbin);
  } else {
    throw FitsIOException("FitsHandler<HistoErr>::Read() No assocaition classe/fits_header");
  }

  //--- remplissage des variables d'entete
  he->mMean = dvl.GetI("NMEAN",0);

  //--- remplissage de l'histo
  FitsBlockRW<r_8>::ReadColumnData(is,1,1,1,&(he->data_(0)),nbin);
  FitsBlockRW<r_8>::ReadColumnData(is,2,1,1,&(he->err2_(0)),nbin);
  FitsBlockRW<r_8>::ReadColumnData(is,3,1,1,&(he->ndata_(0)),nbin);

  return;
}


///////////////////////////////////////////////////////////////////////////
/////////////////////////////// Histo2DErr ////////////////////////////////
///////////////////////////////////////////////////////////////////////////

DECL_TEMP_SPEC  /* equivalent a template <> , pour SGI-CC en particulier */
int FitsHandler<Histo2DErr>::CheckReadability(FitsInOutFile& is)
{
  if (is.CurrentHDUType() == IMAGE_HDU ) return 0;
  string key = "SOPCLSNM"; 
  string clsnm = is.KeyValue(key);
  if( clsnm == "SOPHYA::Histo2DErr") return 2;
  return 0;
}

DECL_TEMP_SPEC  /* equivalent a template <> , pour SGI-CC en particulier */
int FitsHandler<Histo2DErr>::CheckHandling(AnyDataObj & o) 
{  
 if (typeid(o) == typeid(Histo2DErr)) return 2;
 Histo2DErr * po = dynamic_cast< Histo2DErr * >(& o); 
 if (po != NULL) return 2;
 return 0;
}

DECL_TEMP_SPEC  /* equivalent a template <> , pour SGI-CC en particulier */
void FitsHandler<Histo2DErr>::Write(FitsInOutFile& os)
{
  if(dobj==NULL)   
    throw NullPtrError("FitsHandler<Histo2DErr>::Write() NULL dobj pointer ");

  //--- Le type d'objet et son pointeur
  Histo2DErr* he2 = dynamic_cast< Histo2DErr *> (dobj);

  //--- Les noms de colonnes
  int tbltyp = os.GetDef_TableType();
  vector<string> colnames, tform, tunit;
  // les valeurs du bin
  if(tbltyp==ASCII_TBL) tform.push_back("D15.8"); else tform.push_back("D");
  colnames.push_back("val");
  tunit.push_back("");
  // Les erreurs
  if(tbltyp==ASCII_TBL) tform.push_back("D15.8"); else tform.push_back("D");
  colnames.push_back("e2");
  tunit.push_back("");
  // Les nombres d'entrees
  if(tbltyp==ASCII_TBL) tform.push_back("D15.8"); else tform.push_back("D");
  colnames.push_back("nb");
  tunit.push_back("");

  //--- On cree la table  
  string extname = os.NextExtensionName();
  os.CreateTable(os.GetDef_TableType(),extname,colnames,tform, tunit);

  // Ecriture des donnees des colonnes
  long n = he2->NBinX()*he2->NBinY();
  if(n>0) {
    FitsBlockRW<r_8>::WriteColumnData(os,1,1,1,&(he2->data_(0,0)),n);
    FitsBlockRW<r_8>::WriteColumnData(os,2,1,1,&(he2->err2_(0,0)),n);
    FitsBlockRW<r_8>::WriteColumnData(os,3,1,1,&(he2->ndata_(0,0)),n);
  }

  // Ecriture des clefs fits
  MuTyV mtv;

  mtv = "SOPHYA::Histo2DErr";
  os.WriteKey("SOPCLSNM",mtv," SOPHYA class name");

  mtv = "Histo2DErr";
  os.WriteKey("CONTENT",mtv," name of SOPHYA object");

  mtv = he2->NBinX();
  os.WriteKey("NBINX",mtv," number of bins in X");
  mtv = he2->NBinY();
  os.WriteKey("NBINY",mtv," number of bins in Y");
  mtv = he2->NBinX()*he2->NBinY();
  os.WriteKey("NBINXY",mtv," (i,j): fits_row=i*NY+j 0<=i<NX 0<=j<NY");

  mtv = he2->XMin();
  os.WriteKey("XMIN",mtv," absc of beginning of 1srt bin in X");
  mtv = he2->XMax();
  os.WriteKey("XMAX",mtv," absc of end of last bin in X");
  mtv = he2->YMin();
  os.WriteKey("YMIN",mtv," absc of beginning of 1srt bin in Y");
  mtv = he2->YMax();
  os.WriteKey("YMAX",mtv," absc of end of last bin in Y");

  mtv = he2->WBinX();
  os.WriteKey("WBINX",mtv," bin width in X");
  mtv = he2->WBinY();
  os.WriteKey("WBINY",mtv," bin width in Y");
  
  mtv = he2->mMean;
  os.WriteKey("NMEAN",mtv," number of Mean/Variance calls");

  return;
}

DECL_TEMP_SPEC  /* equivalent a template <> , pour SGI-CC en particulier */
void FitsHandler<Histo2DErr>::Read(FitsInOutFile& is)
{
 int hdutyp = is.CurrentHDUType();
 if( (hdutyp != BINARY_TBL ) && (hdutyp != ASCII_TBL) )
    throw FitsIOException("FitsHandler<Histo2DErr>::Read() Not a binary or ascii table HDU");

  //--- Nb de lignes et de colonnes 
  vector<string> colnames; vector<int> coltypes; vector<LONGLONG> repcnt, width;
  is.GetColInfo(colnames,coltypes,repcnt,width);
  long ncol = colnames.size();
  if(ncol<=0)
    throw FitsIOException("FitsHandler<Histo2DErr>::Read() bad number of table columns");
  long nbrows = is.GetNbRows();
  if(nbrows<=0)
    throw FitsIOException("FitsHandler<Histo2DErr>::Read() number of rows is zero, no reading");

  //--- Lecture entete FITS
  DVList dvl; is.GetHeaderRecords(dvl,true,false);

  int_4 nbinx = dvl.GetI("NBINX",-1);
  int_4 nbiny = dvl.GetI("NBINY",-1);
  int_8 nbinxy = nbinx*nbiny;
  if(nbinx<=0 || nbiny<=0 || nbinxy!=nbrows)
    throw FitsIOException("FitsHandler<Histo2DErr>::Read() number of bins is zero or bad, no reading");

  r_8 xmin = dvl.GetD("XMIN",-1.);
  r_8 xmax = dvl.GetD("XMAX",1.);
  r_8 ymin = dvl.GetD("YMIN",-1.);
  r_8 ymax = dvl.GetD("YMAX",1.);

  //--- Creation de l'objet
  if(dobj == NULL) dobj = new Histo2DErr;
  dobj->CreateOrResize(xmin,xmax,nbinx,ymin,ymax,nbiny);

  //--- remplissage des variables d'entete
  dobj->mMean = dvl.GetI("NMEAN",0);

  //--- remplissage de l'histo
  FitsBlockRW<r_8>::ReadColumnData(is,1,1,1,&(dobj->data_(0,0)),nbinxy);
  FitsBlockRW<r_8>::ReadColumnData(is,2,1,1,&(dobj->err2_(0,0)),nbinxy);
  FitsBlockRW<r_8>::ReadColumnData(is,3,1,1,&(dobj->ndata_(0,0)),nbinxy);

  return;
}

} // FIN namespace SOPHYA 
