/*    
   --- SOPHYA software - FitsIOServer module ---
   C. Magneville, 2001 
   (C) UPS+LAL IN2P3/CNRS     (C) DAPNIA-SPP/CEA 
*/
/* Interface Fits BINARY/ASCII Table Writer    cmv 26/09/2001 */
#ifndef FABTWRITER_H_SEEN
#define FABTWRITER_H_SEEN

#include "machdefs.h"
#include <iostream>
#include <string.h>
#include <string>

#include "anydataobj.h"
#include "tvector.h"
#include "FitsIO/fitsio.h"

#include <vector>

namespace SOPHYA {

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
//! Class for writing into a FITS file (DO NOT USE)
class FitsWriter : public AnyDataObj {
protected:
  FitsWriter(string fname,int lp=0);
  FitsWriter(const char* cfname,int lp=0);
  FitsWriter(string fname,bool update,int lp=0);
  FitsWriter(const char* cfname,bool update,int lp=0);
  virtual ~FitsWriter();

public:
  void Flush(void);

  //! Write a double value in Fits header.
  void WriteKey(const char *keyname,double val,const char* comment=NULL);
  //! Write a long value in Fits header.
  void WriteKey(const char *keyname,long val,const char* comment=NULL);
  //! Write a long long value in Fits header.
  void WriteKey(const char *keyname,LONGLONG val,const char* comment=NULL);
  //! Write a string value in Fits header.
  void WriteKey(const char *keyname,string val,const char* comment=NULL);
  //! Write a character string value in Fits header.
  inline void WriteKey(const char *keyname,const char* val,const char* comment=NULL)
                      {string dum=val; WriteKey(keyname,dum,comment);}
  //! Set debug level
  inline void SetDebug(int lp=0) {DbgLevel = (unsigned short) lp;}

  //! Return the number of overflows managed by cfitsio
  inline LONGLONG GetNOverFlow(void) {return NOverFlow;}

  //! Return the c-fitsio file pointer
  inline fitsfile * GetFitsPtr() { return FitsPtr; }
protected:
  struct KeyDouble   {string keyname; double   val; string comment;};
  struct KeyLong     {string keyname; long     val; string comment;};
  struct KeyLongLong {string keyname; LONGLONG val; string comment;};
  struct KeyString   {string keyname; string   val; string comment;};

  void cr_or_upd_fits(const char *cfname,bool update,int lp);

  void writekeys(void);
  void printerrorwrite(const char* type,int col,LONGLONG row,int sta);
  void printerror(int sta) const;

  string FitsFN,ExtName;
  bool Update;
  int HduType;
  unsigned short DbgLevel;
  fitsfile *FitsPtr;
  LONGLONG NOverFlow;

  vector<struct KeyDouble>   DoubleKey;
  vector<struct KeyLong>     LongKey;
  vector<struct KeyLongLong> LongLongKey;
  vector<struct KeyString>   StringKey;
};

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
//! Class for writing a FITS ASCII or BINARY table
class FitsABTWriter : public FitsWriter {
public:
  FitsABTWriter(string fname,int hdutype=BINARY_TBL,int lp=0);
  FitsABTWriter(const char* cfname,int hdutype=BINARY_TBL,int lp=0);
  FitsABTWriter(string fname,bool update,int hdutype=BINARY_TBL,int lp=0);
  FitsABTWriter(const char* cfname,bool update,int hdutype=BINARY_TBL,int lp=0);
  virtual ~FitsABTWriter();

  //! Set the FITS table extension name
  inline void SetExtName(string extname=string("")) {ExtName = extname;}
  //! Set the FITS table extension name
  inline void SetExtName(const char* extname="") {ExtName = extname;}

  //! Add a new column to the FITS table and return its number (see addcol).
  inline int AddCol(string label,string tform=string("")
                   ,string tunit=string(""),int datatype=TDOUBLE)
     {return addcol(label.c_str(),tform.c_str(),tunit.c_str(),datatype);}
  //! Add a new column to the FITS table and return its number (see addcol).
  inline int AddCol(const char* label,const char* tform=""
                   ,const char* tunit="",int datatype=TDOUBLE)
     {return addcol(label,tform,tunit,datatype);}

  void Write(int col,LONGLONG row,int_1 val);
  void Write(int col,LONGLONG row,uint_1 val);
  void Write(int col,LONGLONG row,int_2 val);
  void Write(int col,LONGLONG row,uint_2 val);
  void Write(int col,LONGLONG row,int_4 val);
  void Write(int col,LONGLONG row,uint_4 val);
  void Write(int col,LONGLONG row,int_8 val);
  void Write(int col,LONGLONG row,float val);
  void Write(int col,LONGLONG row,double val);
  LONGLONG Write(int col,LONGLONG row,TVector<uint_2>& val);
  LONGLONG Write(int col,LONGLONG row,TVector<int_4>& val);
  LONGLONG Write(int col,LONGLONG row,TVector<int_8>& val);
  LONGLONG Write(int col,LONGLONG row,TVector<float>& val);
  LONGLONG Write(int col,LONGLONG row,TVector<double>& val);

  //! Return the number of created columns
  inline int GetNbCol(void) {return (int) Label.size();}

  //! Print to os
  virtual void   Print(ostream& os,int lp=1) const;
  //! Print to stdout
  inline  void   Print(int lp=1) const {Print(cout,lp);}

protected:
  int addcol(const char* label,const char* tform,const char* tunit,int datatype);
  void createtbl(void);

  bool FirstTime;
  vector<string> Label;
  vector<string> TForm;
  vector<string> TUnit;
};

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
//! Class for writing a FITS Image
class FitsImg2DWriter : public FitsWriter {
public:
  FitsImg2DWriter(string fname,int bitpix=FLOAT_IMG,int lp=0);
  FitsImg2DWriter(const char* cfname,int bitpix=FLOAT_IMG,int lp=0);
  FitsImg2DWriter(string fname,bool update,int bitpix=FLOAT_IMG,int lp=0);
  FitsImg2DWriter(const char* cfname,bool update,int bitpix=FLOAT_IMG,int lp=0);
  virtual ~FitsImg2DWriter();

  void Write(TMatrix<uint_1>& data);
  void Write(TMatrix<uint_2>& data);
  void Write(TMatrix<int_4>& data);
  void Write(TMatrix<float>& data);
  void Write(TMatrix<double>& data);

  //! Print to os
  virtual void   Print(ostream& os) const;
  //! Print to stdout
  inline  void   Print(void) const {Print(cout);}

protected:
  void createimg(void);

  int BitPix;
  LONGLONG Naxis[2];
  bool FirstTime;
};

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
//! Class for writing a FITS Image
class FitsImg3DWriter : public FitsWriter {
public:
  FitsImg3DWriter(string fname,int bitpix=FLOAT_IMG,int lp=0);
  FitsImg3DWriter(const char* cfname,int bitpix=FLOAT_IMG,int lp=0);
  FitsImg3DWriter(string fname,bool update,int bitpix=FLOAT_IMG,int lp=0);
  FitsImg3DWriter(const char* cfname,bool update,int bitpix=FLOAT_IMG,int lp=0);
  virtual ~FitsImg3DWriter();

  void CreateImg(LONGLONG naxis1,LONGLONG naxis2,LONGLONG naxis3);

  void Write(TArray<uint_1>& data);
  void Write(TArray<uint_2>& data);
  void Write(TArray<int_4>& data);
  void Write(TArray<float>& data);
  void Write(TArray<double>& data);

  void Write(LONGLONG j,LONGLONG k,TVector<uint_1>& data);
  void Write(LONGLONG j,LONGLONG k,TVector<uint_2>& data);
  void Write(LONGLONG j,LONGLONG k,TVector<int_4>& data);
  void Write(LONGLONG j,LONGLONG k,TVector<float>& data);
  void Write(LONGLONG j,LONGLONG k,TVector<double>& data);

  //! Print to os
  virtual void   Print(ostream& os) const;
  //! Print to stdout
  inline  void   Print(void) const {Print(cout);}

protected:
  void createimg(void);

  int BitPix;
  LONGLONG Naxis[3];
  bool FirstTime;
};

} // namespace SOPHYA
#endif    /* FABTWRITER_H_SEEN */
