#ifndef FITSARRHAND_H
#define FITSARRHAND_H

#include "machdefs.h"
#include <string>
#include "tarray.h"
#include "tvector.h"

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

namespace SOPHYA {

/*! 
  \ingroup FitsIOServer
  \brief FITS I/O handler for array objects
*/

template <class T>
class FitsArrayHandler : public FitsHandlerInterface {
public :
  FitsArrayHandler() { dobj=NULL; ownobj=true; }
  FitsArrayHandler(TArray< T > & obj) { dobj = &obj; ownobj=false; }
  virtual   ~FitsArrayHandler() { if (ownobj && dobj) delete dobj; }
  virtual   AnyDataObj* DataObj() { return(dobj); }

  virtual   int         CheckHandling(AnyDataObj & o) 
  {  
    if ( (typeid(o) == typeid(TArray<T>)) ||
	 (typeid(o) == typeid(TMatrix<T>)) ||
	 (typeid(o) == typeid(TVector<T>)) )  return 2;
    TArray<T> * po = dynamic_cast< TArray<T> * >(& o); 
    if (po == NULL) return 0;
    else return 1;
  }

  virtual   void        SetDataObj(AnyDataObj & o) 
  {  
    TArray<T> * po = dynamic_cast< TArray<T> * >(& o); 
    if (po == NULL)  {
      string msg = "FitsHandler<T>::SetDataObj() Wrong object type: " ;
      msg += typeid(o).name(); 
      throw TypeMismatchExc(msg);    
    }
    if (ownobj && dobj) delete dobj;  dobj = po; ownobj = false; 
  }

  virtual int         CheckReadability(FitsInOutFile& is)
  {
    if (is.CurrentHDUType() != IMAGE_HDU)  return 0;
    T x = 0;
    long naxes[BASEARRAY_MAXNDIMS];
    int naxis=BASEARRAY_MAXNDIMS;
    int imgtyp = is.GetImageHDUInfo(naxis, naxes);
    if (naxis < 1) return 0;
    if (FitsTypes::ImageType(x) == imgtyp)  return 2;
    else return 1;
  }

  virtual FitsHandlerInterface* Clone() 
    { return new FitsArrayHandler< T >(); }

  inline operator T&() { return(*dobj); }

  //----- Ecriture
  virtual void     Write(FitsInOutFile& os)
    {
      if ( dobj == NULL) 
	throw NullPtrError("FitsArrayHandler<T>::Write() dobj=NULL ");
      long naxes[BASEARRAY_MAXNDIMS] = {0,0,0,0,0};
      for(int_4 id=0; id<dobj->NbDimensions(); id++) 
	naxes[id] = dobj->Size(id);
      T x = 0;
      os.CreateImageHDU(FitsTypes::ImageType(x), dobj->NbDimensions(), naxes);
      os.WriteHeaderRecords(dobj->Info());
      MuTyV mtv;
      mtv = "SOPHYA::TArray<T>";
      os.WriteKey("SOPCLSNM",mtv," Object class name "); 
      FitsBlockRW<T>::WriteImageData(os, dobj->Data(), dobj->Size());
    }

  //----- Lecture
  virtual void     Read(FitsInOutFile& is)
    {
      long naxes[BASEARRAY_MAXNDIMS];
      int naxis=BASEARRAY_MAXNDIMS;
      is.GetImageHDUInfo(naxis, naxes);
      if ( dobj == NULL) {
	if (naxis == 1) dobj = new TVector<T>;
	else if (naxis == 2) { 
	  if ( (naxes[0] == 1) || (naxes[1] == 1) )  
	    dobj = new TVector<T>;  
	  else dobj = new TMatrix<T>;
	}
	else dobj = new TArray<T>;
	ownobj = true;
      }
      sa_size_t sz[BASEARRAY_MAXNDIMS];
      if (naxis > BASEARRAY_MAXNDIMS) naxis = BASEARRAY_MAXNDIMS;
      for(int_4 id=0; id<naxis; id++) sz[id] = naxes[id];
      dobj->SetSize(naxis, sz, 1, false);
      FitsBlockRW<T>::ReadImageData(is, dobj->Data(), dobj->Size());
      is.GetHeaderRecords(dobj->Info());
    }

protected :
  TArray<T>  * dobj;
  bool ownobj;       // True si dobj obtenu par new
};


template <class T>
inline FitsInOutFile& operator << (FitsInOutFile& os, TArray<T> const & obj)
{ FitsArrayHandler<T> fio(const_cast< TArray<T> &>(obj));  fio.Write(os);  return os; }

template <class T>
inline FitsInOutFile& operator >> (FitsInOutFile& is, TArray<T> & obj)
{ FitsArrayHandler<T> fio(obj); fio.Read(is); is.MoveToNextHDU(); return(is); }


} // Fin du namespace

#endif

