#include "datatable.h"
#include "swppfdtable.h"
#include "pexceptions.h"
#include "fiosegdb.h"

namespace SOPHYA {


/*!
   \class ObjFileIO<BaseDataTable>
   \ingroup HiStats
   Persistence (serialisation) handler for class DataTable classes
*/
/* --Methode-- */ 
DECL_TEMP_SPEC  /* equivalent a template <> , pour SGI-CC en particulier */
void   ObjFileIO<BaseDataTable>::WriteSelf(POutPersist& s)  const
//	Serialisation en ecriture du DataTable sur stream PPF
{
  if (dobj == NULL)   
    throw NullPtrError("ObjFileIO<BaseDataTable>::WriteSelf() NULL dobj pointer ");
  //-------  On ecrit 3 uint_4 .... 
  //  [0]: Numero de version ;
  //  [1] : bit1 non nul -> has info  
  //  [2] : =1 DataTable , =2 SwPPFDataTable 
  //  [3] : reserve

  DataTable* dt = dynamic_cast< DataTable *> (dobj);
  SwPPFDataTable* swdt = dynamic_cast< SwPPFDataTable *> (dobj);
  if ( (dt == NULL) && (swdt == NULL) )
    throw IOExc("ObjFileIO<BaseDataTable>::WriteSelf() object not a DataTable or SwPPFDataTable");
  if ( swdt && (swdt->mSwOut != &s) )
    throw IOExc("ObjFileIO<SwPPFDataTable>::WriteSelf() (obj=SwPPFDataTable) OutputStream <> SwapStream");
  uint_4 itab[4];
  itab[0] = 1;  // Numero de version a 1
  itab[1] = itab[2] = itab[3] = 0;
  if (dobj->mInfo)  itab[1] = 1;
  if (dt != NULL) itab[2] = 1;
  else if (swdt != NULL) itab[2] = 2;
  s.Put(itab, 4);

  //-------- Ecriture de segment size, nb de colonnes, nb de lignes ...  
  // [0] : SegmentSize()        [1] : NVar()
  // [2] : NEntry()             [3] : NbSegments()
  // [4] : reserve utilisation future
  uint_8 ltab[5];
  ltab[0] = dobj->SegmentSize();
  ltab[1] = dobj->NVar();
  ltab[2] = dobj->NEntry();
  ltab[3] = dobj->NbSegments();
  ltab[4] = 0;
  s.Put(ltab, 5);

  //------ Ecriture du nom et type des colonnes
  for(sa_size_t k=0; k<dobj->NVar(); k++) { 
    uint_2 typ = dobj->mNames[k].type;
    s.Put(typ);
    s.Put(dobj->mNames[k].nom);
  }
  // ------- Ecriture des tableaux min,max et n_minmax
  for(uint_8 k=0; k<ltab[1]; k++) { 
    s.Put(dobj->mMin[k]);
    s.Put(dobj->mMax[k]);
    s.Put(dobj->mMinMaxNEnt[k]);
  }  
  //------- Ecriture du DVList Info() associe, si existant
  if (dobj->mInfo)  s << (*(dobj->mInfo));

  //------- Ecriture des blocs de donnees Sw/SegDataBlock<T>
  if (dt) {  // C'est un DataTable 
  //.... Ecriture des SegDataBlock<T>
    for (size_t kk=0; kk<dobj->mNames.size(); kk++) {
      sa_size_t sk = dobj->mNames[kk].ser;
      switch (dobj->mNames[kk].type) {
      case BaseDataTable::IntegerField :
	s << dt->mICols[sk]; 
	break;
      case BaseDataTable::LongField :
	s << dt->mLCols[sk]; 
	break;
      case BaseDataTable::FloatField :
	s << dt->mFCols[sk]; 
	break;
      case BaseDataTable::DoubleField :
      case BaseDataTable::DateTimeField :
	s << dt->mDCols[sk]; 
	break;
      case BaseDataTable::ComplexField :
	s << dt->mYCols[sk]; 
	break;
      case BaseDataTable::DoubleComplexField :
	s << dt->mZCols[sk]; 
	break;
      case BaseDataTable::StringField :
	s << dt->mSCols[sk]; 
	break;
      default:
	throw IOExc("ObjFileIO<BaseDataTable>::WriteSelf() (DataTable) unknown column type ");
	break;
      }
    }    
  }
  else if (swdt) {  // C'est un SwPPFDataTable
    //.... Ecriture des tables de positionnement de SwSegDataBlock<T> 
    for (size_t kk=0; kk<dobj->mNames.size(); kk++) {
      sa_size_t sk = dobj->mNames[kk].ser;
      switch (dobj->mNames[kk].type) {
      case BaseDataTable::IntegerField :
	s.PutPosTagTable(swdt->mICols[sk].GetSwapPosTagTable()); 
	break;
      case BaseDataTable::LongField :
	s.PutPosTagTable(swdt->mLCols[sk].GetSwapPosTagTable()); 
	break;
      case BaseDataTable::FloatField :
	s.PutPosTagTable(swdt->mFCols[sk].GetSwapPosTagTable()); 
	break;
      case BaseDataTable::DoubleField :
      case BaseDataTable::DateTimeField :
	s.PutPosTagTable(swdt->mDCols[sk].GetSwapPosTagTable()); 
	break;
      case BaseDataTable::ComplexField :
	s.PutPosTagTable(swdt->mYCols[sk].GetSwapPosTagTable()); 
	break;
      case BaseDataTable::DoubleComplexField :
	s.PutPosTagTable(swdt->mZCols[sk].GetSwapPosTagTable()); 
	break;
      case BaseDataTable::StringField :
	s.PutPosTagTable(swdt->mSCols[sk].GetSwapPosTagTable()); 
	break;
      default:
	throw IOExc("ObjFileIO<BaseDataTable>::WriteSelf() (SwPPFDataTable) unknown column type ");
	break;
      }
    }    
  }
  return;
  }
  
/* --Methode-- */
DECL_TEMP_SPEC  /* equivalent a template <> , pour SGI-CC en particulier */
void  ObjFileIO<BaseDataTable>::ReadSelf(PInPersist& s)
//	Serialisation en lecture du DataTable sur stream PPF
{
  // ------- On lit les 3 premiers uint_4
  //  [0]: Numero de version ;
  //  [1] : bit1 non nul -> has info  
  //  [2] : =1 DataTable , =2 SwPPFDataTable 
  //  [3] : reserve
  uint_4 itab[4] = {0,0,0,0};
  s.Get(itab, 4);
  bool hadinfo = false;
  if ((itab[1]&1) == 1)  hadinfo = true;
  if ((itab[2] != 1) && (itab[2] != 2))
    throw IOExc("ObjFileIO<BaseDataTable>::ReadSelf(): (itab[2]=type=1 or 2) supported only");    

  // -------- Lecture de segment size, nb de colonnes, nb de lignes ...  
  // [0] : SegmentSize()        [1] : NVar()
  // [2] : NEntry()             [3] : NbSegments()
  uint_8 ltab[5] = {0,0,0,0,0};
  s.Get(ltab, 5);
  if (dobj == NULL) {
    if (itab[2] == 1)  dobj = new DataTable(ltab[0]);
    else if (itab[2] == 2) dobj = new SwPPFDataTable(s, ltab[0]);
  }
  else {     
    dobj->Clear();  
    dobj->mSegSz = ltab[0]; 
    SwPPFDataTable* swdtc = dynamic_cast< SwPPFDataTable *> (dobj);
    // Copie brutale en utilisant l'operateur = 
    if (swdtc && (itab[2] == 2)) *swdtc = SwPPFDataTable(s, ltab[0]);
  }

  DataTable* dt = dynamic_cast< DataTable *> (dobj);
  SwPPFDataTable* swdt = dynamic_cast< SwPPFDataTable *> (dobj);
  if ( (dt == NULL) && (swdt == NULL) )
    throw IOExc("ObjFileIO<BaseDataTable>::ReadSelf() object not a DataTable or SwPPFDataTable");
  if ( (itab[2] == 1) && (dt == NULL) )
    throw IOExc("ObjFileIO<BaseDataTable>::ReadSelf() object not a DataTable and itab[2]=1");
  if ( (itab[2] == 2) && (swdt == NULL) )
    throw IOExc("ObjFileIO<BaseDataTable>::ReadSelf() object not a DataTable and itab[2]=1");

  // -------- Lecture nom/type colonnes et allocation des colonnes
  uint_2 typ; 
  string cnom;
  for(uint_8 k=0; k<ltab[1]; k++) { 
    s.Get(typ);
    s.Get(cnom);
    BaseDataTable::FieldType ft = (BaseDataTable::FieldType)typ;
    dobj->AddColumn(ft, cnom);
  }
  // ------- Lecture des tableaux min,max et n_minmax
  for(uint_8 k=0; k<ltab[1]; k++) { 
    s.Get(dobj->mMin[k]);
    s.Get(dobj->mMax[k]);
    s.Get(dobj->mMinMaxNEnt[k]);
  }  
  // ------- Lecture du DVList Info() associe, si necessaire
  if (hadinfo) {    // Lecture eventuelle du DVList Info
    if (dobj->mInfo == NULL)  dobj->mInfo = new DVList;
    s >> (*(dobj->mInfo));
  }
  // ------- Mise a jour des champs Nb d'entrees, nb segments ...
  dobj->mNEnt = ltab[2];
  dobj->mNSeg = ltab[3];
  // ------- Lecture des donnees Sw/SegDataBlock<T> ou Sw 
  if (itab[2] == 1) {   // On lit un DataTable
  // .... Lecture des SegDataBlock<T> 
    for (size_t kk=0; kk<dobj->mNames.size(); kk++) {
      sa_size_t sk = dobj->mNames[kk].ser;
      switch (dobj->mNames[kk].type) {
      case BaseDataTable::IntegerField :
	s >> dt->mICols[sk]; 
	break;
      case BaseDataTable::LongField :
	s >> dt->mLCols[sk]; 
	break;
      case BaseDataTable::FloatField :
	s >> dt->mFCols[sk]; 
	break;
      case BaseDataTable::DoubleField :
      case BaseDataTable::DateTimeField :
	s >> dt->mDCols[sk]; 
	break;
      case BaseDataTable::ComplexField :
	s >> dt->mYCols[sk]; 
	break;
      case BaseDataTable::DoubleComplexField :
	s >> dt->mZCols[sk]; 
	break;
      case BaseDataTable::StringField :
	s >> dt->mSCols[sk]; 
	break;
      default:
	throw IOExc("ObjFileIO<BaseDataTable>::ReadSelf() : unknown column type ");
	break;
      }
    }    
  }
  else if (itab[2] == 2) {  // C'est un SwPPFDataTable
    // .... Lecture des tag de positionnement des SwSegDataBlock<T> 
    vector<int_8> swpos;
    for (size_t kk=0; kk<dobj->mNames.size(); kk++) {
      sa_size_t sk = dobj->mNames[kk].ser;
      switch (dobj->mNames[kk].type) {
      case BaseDataTable::IntegerField :
	swpos.clear();
	s.GetPosTagTable(swpos);
	swdt->mICols[sk] = SwSegDataBlock<int_4>(swdt->mISwapper, swpos, swdt->SegmentSize());
	break;
      case BaseDataTable::LongField :
	swpos.clear();
	s.GetPosTagTable(swpos);
	swdt->mLCols[sk] = SwSegDataBlock<int_8>(swdt->mLSwapper, swpos, swdt->SegmentSize());
	break;
      case BaseDataTable::FloatField :
	swpos.clear();
	s.GetPosTagTable(swpos);
	swdt->mFCols[sk] = SwSegDataBlock<r_4>(swdt->mFSwapper, swpos, swdt->SegmentSize());
	break;
      case BaseDataTable::DoubleField :
      case BaseDataTable::DateTimeField :
	swpos.clear();
	s.GetPosTagTable(swpos);
	swdt->mDCols[sk] = SwSegDataBlock<r_8>(swdt->mDSwapper, swpos, swdt->SegmentSize());
	break;
      case BaseDataTable::ComplexField :
	swpos.clear();
	s.GetPosTagTable(swpos);
	swdt->mYCols[sk] = SwSegDataBlock< complex<r_4> >(swdt->mYSwapper, swpos, swdt->SegmentSize());
	break;
      case BaseDataTable::DoubleComplexField :
	swpos.clear();
	s.GetPosTagTable(swpos);
	swdt->mZCols[sk] = SwSegDataBlock< complex<r_8> >(swdt->mZSwapper, swpos, swdt->SegmentSize());
	break;
      case BaseDataTable::StringField :
	swpos.clear();
	s.GetPosTagTable(swpos);
	swdt->mSCols[sk] = SwSegDataBlock<string>(swdt->mSSwapper, swpos, swdt->SegmentSize());
	break;
      default:
	throw IOExc("ObjFileIO<SwPPFDataTable>::ReadSelf() : unknown column type ");
	break;
      }
    }    
  }
return;
}

#ifdef __CXX_PRAGMA_TEMPLATES__
#pragma define_template ObjFileIO<BaseDataTable>
#endif

#if defined(ANSI_TEMPLATES) || defined(GNU_TEMPLATES)
template class ObjFileIO<BaseDataTable>;
#endif

} // FIN namespace SOPHYA 
