#include "machdefs.h"

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

#include "generaldata.h"

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

namespace SOPHYA {

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

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

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

  //--- Le type d'objet et son pointeur
  GeneralFitData* gd = dynamic_cast< GeneralFitData *> (dobj);
  long nvar = gd->mNVar;
  if(nvar<=0)
    throw NullPtrError("FitsHandler<GeneralFitData>::Write() no variables ");

  //--- Les noms de colonnes
  int tbltyp = os.GetDef_TableType();
  vector<string> colnames, tform, tunit;
  // La variable Y et son Erreur
  if(tbltyp==ASCII_TBL) tform.push_back("D15.8"); else tform.push_back("D");
  colnames.push_back("y");
  tunit.push_back("");
  if(tbltyp==ASCII_TBL) tform.push_back("D15.8"); else tform.push_back("D");
  colnames.push_back("ey");
  tunit.push_back("");
  // Le flag de validite
  if(tbltyp==ASCII_TBL) tform.push_back("I9"); else tform.push_back("J");
  colnames.push_back("ok");
  tunit.push_back("");
  // Les variables X
  for(int i=0;i<nvar;i++) {
    char str[16]; sprintf(str,"x%d",i);
    if(tbltyp==ASCII_TBL) tform.push_back("D15.8"); else tform.push_back("D");
    colnames.push_back(str);
    tunit.push_back("");
  }
  // Les erreurs sur les variables X
  if(gd->HasXErrors()) {
    for(int i=0;i<nvar;i++) {
      char str[16]; sprintf(str,"ex%d",i);
      if(tbltyp==ASCII_TBL) tform.push_back("D15.8"); else tform.push_back("D");
      colnames.push_back(str);
      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 = gd->mNDataAlloc;
  if(n>0) {
    // Y
    FitsBlockRW<r_8>::WriteColumnData(os,1,1,1,gd->mF,n);
    // EY
    FitsBlockRW<r_8>::WriteColumnData(os,2,1,1,gd->mErr,n);
    // Le flag de validite
    int_4 *ival = new int_4[n];
    for(int_4 i=0;i<n;i++) ival[i] =  gd->mOK[i];
    FitsBlockRW<int_4>::WriteColumnData(os,3,1,1,ival,n);
    delete [] ival;
    // les variables X
    r_8 *val = new r_8[n];
    for(int k=0;k<nvar;k++) {
      for(int_4 i=0;i<n;i++) val[i] = gd->mXP[nvar*i+k];
      FitsBlockRW<r_8>::WriteColumnData(os,4+k,1,1,val,n);
    }
    // les erreurs sur les variables X
    if(gd->HasXErrors()) {
      for(int k=0;k<nvar;k++) {
        for(int_4 i=0;i<n;i++) val[i] = gd->mErrXP[nvar*i+k];
        FitsBlockRW<r_8>::WriteColumnData(os,4+nvar+k,1,1,val,n);
      }
    }
    delete [] val;
  }

  //--- Ecriture des clefs fits
  MuTyV mtv;

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

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

  mtv = gd->mNVar;
  os.WriteKey("NVAR",mtv," number of variables X");

  mtv = gd->mNDataAlloc;
  os.WriteKey("NALLOC",mtv," number of allocated data");
  mtv = gd->mNData;
  os.WriteKey("NDATA",mtv," number of filled data");
  mtv = gd->mNDataGood;
  os.WriteKey("NGOOD",mtv," number of good filled data");

  mtv = (int_4)((gd->HasXErrors())? 1: 0);
  os.WriteKey("HASXERR",mtv," erreurs sur X?");

  return;
}

DECL_TEMP_SPEC  /* equivalent a template <> , pour SGI-CC en particulier */
void FitsHandler<GeneralFitData>::Read(FitsInOutFile& is)
{
 int hdutyp = is.CurrentHDUType();
 if( (hdutyp != BINARY_TBL ) && (hdutyp != ASCII_TBL) )
    throw FitsIOException("FitsHandler<GeneralFitData>::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<GeneralFitData>::Read() bad number of table columns");
  int_8 nbrows = is.GetNbRows();
  if(nbrows<=0)
    throw FitsIOException("FitsHandler<GeneralFitData>::Read() number of rows is zero, no reading");

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

  int_4 nvar = dvl.GetI("NVAR",-1);
  if(nvar<=0)
    throw FitsIOException("FitsHandler<GeneralFitData>::Read() number of variables is zero, no reading");

  int_4 ndatalloc = dvl.GetI("NALLOC",-1);
  if(ndatalloc<=0)
    throw FitsIOException("FitsHandler<GeneralFitData>::Read() number of allocated data is zero, no reading");
  int_4 ndata = dvl.GetI("NDATA",-1);
  int_8 ndatagood = dvl.GetI("NGOOD",-1);

  int_4 dum = dvl.GetI("HASXERR",0);
  uint_2 ok_ex = (dum==0) ? 0: 1;

  int mynvar = 3 + nvar + ((ok_ex>0)? nvar: 0);
  if(ncol!=mynvar)
    throw FitsIOException("FitsHandler<GeneralFitData>::Read() inconsistent header/mvar, no reading");

  //--- Creation de l'objet
  if(dobj == NULL) dobj = new GeneralFitData;
  dobj->Alloc(nvar,ndatalloc,ok_ex);

  //--- remplissage des variables privees restantes
  dobj->mNData = ndata;
  dobj->mNDataGood = ndatagood;

  //--- remplissage de la structure de donnees
  if(ndata>0) {
    // Y
    FitsBlockRW<r_8>::ReadColumnData(is,1,1,1,dobj->mF,ndata);
    // EY
    FitsBlockRW<r_8>::ReadColumnData(is,2,1,1,dobj->mErr,ndata);
    // Le flag de validite
    int_4 *ival = new int_4[ndata];
    FitsBlockRW<int_4>::ReadColumnData(is,3,1,1,ival,ndata);
    for(int_4 i=0;i<ndata;i++) dobj->mOK[i] = (uint_2)ival[i];
    delete [] ival;
    // les variables X
    r_8 *val = new r_8[ndata];
    for(int k=0;k<nvar;k++) {
      FitsBlockRW<r_8>::ReadColumnData(is,4+k,1,1,val,ndata);
      for(int_4 i=0;i<ndata;i++) dobj->mXP[nvar*i+k] = val[i];
    }
    // les erreurs sur les variables X
    if(dobj->HasXErrors()) {
      for(int k=0;k<nvar;k++) {
        FitsBlockRW<r_8>::ReadColumnData(is,4+nvar+k,1,1,val,ndata);
        for(int_4 i=0;i<ndata;i++) dobj->mErrXP[nvar*i+k] = val[i];
      }
    }
    delete [] val;
  }

  return;
}

} // FIN namespace SOPHYA 
