// Copyright (C) 1999-2015
// Smithsonian Astrophysical Observatory, Cambridge, MA, USA
// For conditions of distribution and use, see copyright notice in "copyright"

#ifndef __fitsimage_h__
#define __fitsimage_h__

#include "vector.h"
#include "vector3d.h"
#include "fitsdata.h"
#include "coord.h"
#include "file.h"
#include "wcs.h"
#include "head.h"

#include "smooth.h"

extern "C" {
  #include "ast.h"
}

class WCSx {
 public:
  double crpix[FTY_MAXAXES];
  double crval[FTY_MAXAXES];
  double cd[FTY_MAXAXES];

 public:
  WCSx();
};

class FitsImage {
 public:
  enum CompressType {GZIP, RICE, PLIO, HCOMPRESS};

 protected:
  Base* parent;            // pointer to parent

  char* objectKeyword_;         // object keyword
  char* rootBaseFileName;   // base root filename
  char* fullBaseFileName;   // base full filename
  char* rootFileName;       // root filename
  char* fullFileName;       // full filename
  char* rootFileName3d;     // root filename
  char* fullFileName3d;     // full filename
  char* iisFileName;        // alt file name for iis

  // native fits file
  FitsFile* fits_;
  FitsFile* post_;          // fits post processing
  FitsFile* hist_;          // fits bin
  FitsFile* hpx_;           // healpix

  // base
  FitsFile* base_;
  FitsData* basedata_;

  // block
  int manageBlock_;
  FitsFile* block_;
  FitsData* blockdata_;

  // analysis
  int manageAnalysis_;
  FitsFile* analysis_;
  FitsData* analysisdata_;

  // final
  FitsFile* image_;
  FitsData* data_;

  Vector histCursor;        // start point to bin about (physical coords)
  Vector actualHistCursor;  // actual bin center (physical coords)
  char* binSliceFilter;

  char buf[32];             // tmp storage for returning strings

  // Mosaic items
  int keyLTMV;
  int keyATMV;
  int keyDTMV;
  int keyDATASEC;

  double jyBeam_; // beam area for radio maps

  BBox datasec;             // DATASEC keyword
  
  FitsBound* mparams; // minmax bbox

  int iisMode_;              // flag to indicate if iis
  Vector iisz_;              // z1 and z2
  int iiszt_;                // 0-Uniary, 1-Linear, 2-Log

  FitsImage* nextMosaic_;   // next mosaic
  FitsImage* nextSlice_;    // next slice

  int address[FTY_MAXAXES];

  WorldCoor** wcs;          // wcs list
  AstFrameSet** ast; // ast frameset;
  FitsHead* wcsHeader; // alt wcs header

 protected:
  void reset();

  void process(const char*, int);
  void initCompress();
  void initNRRD();
  void initENVI();
  void initHist();
  int initHPX();
  Vector getHistCenter();

  char* root(const char*);
  char* strip(const char*);

  void smooth();
  void smooth(pthread_t*, t_smooth_arg*);

  void wcsShow(WorldCoor*);
  void astinit(int, FitsHead*);
  int checkAst(double, double);
  AstFrameSet* fits2ast(FitsHead*);  
  AstFrameSet* buildast(int);
  void wcs2ast(int, void*);
  void header2ast(int, void*);
  void putFitsCard(void* chan, const char* key, const char* value);
  void putFitsCard(void* chan, const char* key, int value);
  void putFitsCard(void* chan, const char* key, double value);

  char* ASTpix2wcs(Vector, Coord::CoordSystem, Coord::SkyFrame, Coord::SkyFormat, char*, int);
  Vector ASTpix2wcs(Vector, Coord::CoordSystem, Coord::SkyFrame);
  Vector* ASTpix2wcs(Vector*, int, Coord::CoordSystem, Coord::SkyFrame);
  Vector ASTwcs2pix(Vector, Coord::CoordSystem, Coord::SkyFrame);
  Vector* ASTwcs2pix(Vector*, int, Coord::CoordSystem, Coord::SkyFrame);
  double ASTwcsdist(Vector, Vector, Coord::CoordSystem);

 public:
  WCSx** wcsx; // xth Axis WCS

  Matrix wcsToRef;          // iraf/wcs matrix
  Matrix irafToRef;

  Matrix amplifierToImage;
  Matrix amplifierToPhysical;
  Matrix amplifierToRef;
  Matrix canvasToRef;
  Matrix dataToImage;
  Matrix imageToData;
  Matrix dataToRef;
  Matrix dataToWidget;
  Matrix detectorToImage;
  Matrix detectorToPhysical;
  Matrix detectorToRef;
  Matrix imageToAmplifier;
  Matrix imageToDetector;
  Matrix imageToPhysical;
  Matrix imageToRef;
  Matrix imageToWidget;
  Matrix physicalToAmplifier;
  Matrix physicalToDetector;
  Matrix physicalToImage;
  Matrix physicalToRef;
  Matrix refToAmplifier;
  Matrix refToCanvas;
  Matrix refToData;
  Matrix refToDetector;
  Matrix refToImage;
  Matrix refToPhysical;
  Matrix widgetToData;
  Matrix widgetToImage;

  Matrix3d dataToImage3d;
  Matrix3d dataToRef3d;
  Matrix3d dataToWidget3d;
  Matrix3d imageToData3d;
  Matrix3d refToData3d;
  Matrix3d widgetToData3d;

  Matrix magnifierToData;
  Matrix dataToMagnifier;
  Matrix3d magnifierToData3d;
  Matrix3d dataToMagnifier3d;

  Matrix pannerToData;
  Matrix dataToPanner;
  Matrix3d pannerToData3d;
  Matrix3d dataToPanner3d;

  Matrix psToData;
  Matrix dataToPS;
  Matrix3d psToData3d;
  Matrix3d dataToPS3d;

  FitsBound iparams; // image bbox
  FitsBound dparams; // DATASEC bbox
  FitsBound cparams; // crop bbox

 public:
  FitsImage(Base*);
  virtual ~FitsImage();

  void load();
  void analysis(int);
  void analysis(int, pthread_t*, t_smooth_arg*);

  FitsImage* nextMosaic() {return nextMosaic_;}
  FitsImage* nextSlice() {return nextSlice_;}
  void setNextMosaic(FitsImage* n) {nextMosaic_ = n;}
  void setNextSlice(FitsImage* n) {nextSlice_ = n;}

  FitsFile* fitsFile() {return fits_;}
  FitsFile* baseFile() {return base_;}
  FitsFile* blockFile() {return block_;}
  FitsFile* analysisFile() {return analysis_;}
  FitsFile* imageFile() {return image_;}

  // we assume that 'data' is valid
  void* basedata() {return basedata_->raw();}
  void* blockdata() {return blockdata_->raw();}
  void* analysisdata() {return analysisdata_->raw();}
  void* imagedata() {return data_->raw();}

  // isValid() means "valid image found"
  int isValid() {return image_ ? 1 : 0;}
  int isPost() {return post_ ? 1 : 0;}
  int isHist() {return hist_ ? 1 : 0;}
  int isHPX() {return hpx_ ? 1 : 0;}

  int isImage() {return fits_ ? fits_->isImage() : 0;}
  int isTable() {return fits_ ? fits_->isTable() : 0;}
  int isAsciiTable() {return fits_ ? fits_->isAsciiTable() : 0;}
  int isBinTable() {return fits_ ? fits_->isBinTable() : 0;}

  void close() {if (fits_) fits_->done();}

  void match(const char* xxname1, const char* yyname1,
	     Coord::CoordSystem sys1, Coord::SkyFrame sky1,
	     const char* xxname2, const char* yyname2,
	     Coord::CoordSystem sys2, Coord::SkyFrame sky2,
	     double rad, Coord::CoordSystem sys, Coord::SkyDist dist,
	     const char* rrname);

  FitsHead* parseWCS(istream&);

  Matrix updateHistCenter();
  Matrix updateHistCursor();
  Matrix updateHist(const Vector&);
  Matrix nextHist(const Vector&);
  void calcHistSize();
  Vector getHistDim();
  Vector getHistColMinMax(const char*);
  Vector getHistColDim(const char*);
  Vector getHistCursor() {return actualHistCursor;}
  const char* getHistFilter();
  const char* getHistX();
  const char* getHistY();
  const char* getHistZ();
  char* getHistList();

  void block();
  Matrix updateBlock();

  void setBinCursor(const Vector&);

  void setBinX(const char* str) {if (fits_) fits_->setpBinX(str);}
  void setBinY(const char* str) {if (fits_) fits_->setpBinY(str);}
  void setBinZ(const char* str) {if (fits_) fits_->setpBinZ(str);}
  void setBinFilter(const char* fil) {if (fits_) fits_->setpFilter(fil);}
  void setBinSliceFilter(const char*);
  void setBinColMinMax(const char* str, const Vector& lim)
    {if (fits_) fits_->setColMinMax(str,lim);}

  int hasBinCol(const char*);

  const char* objectKeyword() {return objectKeyword_;}
  void setObjectKeyword(const char*);

  const char* getRootBaseFileName() {return rootBaseFileName;}
  const char* getFullBaseFileName() {return fullBaseFileName;}
  const char* getRootFileName() {return rootFileName;}
  const char* getFullFileName() {return fullFileName;}
  const char* getRootFileName3d() {return rootFileName3d;}
  const char* getFullFileName3d() {return fullFileName3d;}
  const char* iisGetFileName() {return iisFileName;}
  void iisSetFileName(const char*);
  void setFileName(const char*);
  void updateFileName();

  long naxis(int ii) {return image_->head()->naxis(ii);}

  long owidth() {return fits_->head()->naxis(0);}
  long oheight() {return fits_->head()->naxis(1);}
  Vector osize() {return Vector(owidth(),oheight());}
  Vector ocenter() {return Vector(owidth(),oheight())/2.;}

  long width() {return image_->head()->naxis(0);}
  long height() {return image_->head()->naxis(1);}
  long depth() {return naxis(2)>0 ? naxis(2) : 1;}
  Vector size() {return Vector(width(),height());}
  Vector center() {return Vector(width(),height())/2.;}

  Vector3d size3d() {return Vector3d(width(),height(),depth());}
  Vector3d osize3d() {return Vector3d(owidth(),oheight(),depth());}

  int nhdu();

  int bitpix() {return image_->head()->bitpix();}
  int ext() {return fits_->ext();}

  FitsBound* getDataParams(FrScale::ScanMode);   // return bbox in IMAGE
  void setCropParams(int);
  void setCropParams(int,int,int,int,int);
  void setCropParams(const Vector&, const Vector&, int);
  void setCrop3dParams();
  void setCrop3dParams(int,int);
  void setCrop3dParams(double, double);
  void setMinMaxParams();
  void setMinMaxParams(int,int,int,int);

  int hasLTMV() {return keyLTMV;}
  int hasATMV() {return keyATMV;}
  int hasDTMV() {return keyDTMV;}

  int isIIS() {return iisMode_;}
  Vector& iisz() {return iisz_;}

  char* pix2wcs(Vector in, Coord::CoordSystem sys, Coord::SkyFrame sky, Coord::SkyFormat format, char* lbuf, int len) 
  {return ASTpix2wcs(in, sys, sky, format, lbuf, len);}
  Vector pix2wcs(Vector in, Coord::CoordSystem sys, Coord::SkyFrame sky)
  {return ASTpix2wcs(in, sys, sky);}
  Vector wcs2pix(Vector in, Coord::CoordSystem sys, Coord::SkyFrame sky)
  {return ASTwcs2pix(in, sys, sky);}
  double wcsdist(Vector aa, Vector bb, Coord::CoordSystem sys)
  {return ASTwcsdist(aa, bb, sys);}

  double pix2wcsx(double, Coord::CoordSystem, int);
  double wcs2pixx(double, Coord::CoordSystem, int);

  void initWCS(FitsHead*, FitsHead*);
  void listWCS(ostream&, Coord::CoordSystem);
  void resetWCS();
  void replaceWCS(FitsHead*);
  void appendWCS(FitsHead*);
  void initWCS0(const Vector&);
  void resetWCS0();

  void processKeywords();
  int processKeywordsIRAF(FitsImage*);
  int processKeywordsWCS(FitsImage*, Coord::CoordSystem);

  WorldCoor* getWCS(Coord::CoordSystem sys) 
  {return (wcs && wcs[sys-Coord::WCS]) ? wcs[sys-Coord::WCS] : NULL;}
  const char* getWCSName(Coord::CoordSystem sys) 
  {return (wcs && wcs[sys-Coord::WCS]) ? wcs[sys-Coord::WCS]->wcsname : NULL;}
  Coord::Orientation getWCSOrientation(Coord::CoordSystem, Coord::SkyFrame);
  double getWCSRotation(Coord::CoordSystem, Coord::SkyFrame);
  Vector getWCScdelt(Coord::CoordSystem);
  Vector getWCScrpix(Coord::CoordSystem);
  Vector getWCScrval(Coord::CoordSystem);

  void setAstSkyFrame(AstFrameSet*, Coord::SkyFrame);
  void setAstFormat(AstFrameSet*, int, const char*);
  AstFrameSet* getAST(Coord::CoordSystem sys) 
    {return (ast && ast[sys-Coord::WCS]) ? ast[sys-Coord::WCS] : NULL;}

  int hasWCS(Coord::CoordSystem);
  int hasWCSx(Coord::CoordSystem, int);
  int hasWCSEqu(Coord::CoordSystem);
  int hasWCSCel(Coord::CoordSystem);

  void updateMatrices(Matrix&, Matrix&, Matrix&);
  void updateMatrices(Matrix3d&);

  void updatePannerMatrices(Matrix&);
  void updatePannerMatrices(Matrix3d&);

  void updateMagnifierMatrices(Matrix&);
  void updateMagnifierMatrices(Matrix3d&);

  void updatePS(Matrix);
  void updatePS(Matrix3d);

  Matrix& matrixFromData(Coord::InternalSystem);
  Matrix& matrixToData(Coord::InternalSystem);
  Matrix3d& matrixFromData3d(Coord::InternalSystem);
  Matrix3d& matrixToData3d(Coord::InternalSystem);

  Vector mapFromRef(const Vector&, Coord::CoordSystem, Coord::SkyFrame =Coord::FK5);
  void mapFromRef(const Vector&, Coord::CoordSystem, Coord::SkyFrame, Coord::SkyFormat, char*,int);
  Vector mapToRef(const Vector&, Coord::CoordSystem, Coord::SkyFrame =Coord::FK5);
  double mapFromRef3axis(double, Coord::CoordSystem, int);
  double mapToRef3axis(double, Coord::CoordSystem, int);
  double mapLenFromRef(double, Coord::CoordSystem, Coord::SkyDist =Coord::DEGREE);
  Vector mapLenFromRef(const Vector&, Coord::CoordSystem, Coord::SkyDist =Coord::DEGREE);
  double mapLenToRef(double, Coord::CoordSystem, Coord::SkyDist =Coord::DEGREE);
  Vector mapLenToRef(const Vector&, Coord::CoordSystem, Coord::SkyDist =Coord::DEGREE);
  Vector mapLenFromImage(const Vector&, Coord::CoordSystem, Coord::SkyDist =Coord::DEGREE);
  Vector mapLenToImage(const Vector&, Coord::CoordSystem, Coord::SkyDist =Coord::DEGREE);
  double mapDistFromRef(const Vector&, const Vector&, Coord::CoordSystem,
		       Coord::SkyDist =Coord::DEGREE);

  const char* getValue(const Vector& v);
  float getValueFloat(const Vector& v) {return data_->getValueFloat(v);}
  double getValueDouble(const Vector& v) {return data_->getValueDouble(v);}
  int getValueMask(const Vector& v) {return data_->getValueMask(v);}
  int getValueMask(double x, double y) {return data_->getValueMask(x,y);}

  float getValueFloat(long i) {return data_->getValueFloat(i);}
  double getValueDouble(long i) {return data_->getValueDouble(i);}
  int getValueMask(long i) {return data_->getValueMask(i);}

  void setClip(double l, double h) {data_->setClip(l,h);}

  const char* getMin() {return data_ ? data_->getMin() : NULL;}
  const char* getMax() {return data_ ? data_->getMax() : NULL;}

  double getMinDouble() {return data_ ? data_->getMinDouble() : 0;}
  double getMaxDouble() {return data_ ? data_->getMaxDouble() : 0;}

  const char* getLow() {return data_ ? data_->getLow() : NULL;}
  const char* getHigh() {return data_ ? data_->getHigh() : NULL;}
  double getLowDouble() {return data_ ? data_->getLowDouble() : 0;}
  double getHighDouble() {return data_ ? data_->getHighDouble() : 0;}

  void updateClip(FrScale*);

  int hasDATAMIN() {return data_ ? data_->hasDATAMIN() : 0;}
  int hasDATASEC() {return keyDATASEC;}
  int hasIRAFMIN() {return data_ ? data_->hasIRAFMIN() : 0;}

  void bin(double* b, int l, double mn, double mx, FrScale::ScanMode ds)
  {data_->bin(b,l,mn,mx,getDataParams(ds));}

  char* display(FitsHead*);
  char* displayHeader();
  char* displayPrimary();
  char* displayWCS();
  FitsHead* head() {return image_->head();}
  char* getKeyword(const char* key) {return fits_->getKeyword(key);}
  int findKeyword(const char*);

  int saveFitsPrimHeader(OutFitsStream& str)
  {return image_ ? image_->saveFitsPrimHeader(str) : 0;}

  int saveFitsXtHeader(OutFitsStream& str, int dd)
  {return image_ ? image_->saveFitsXtHeader(str, dd) : 0;}

  int saveFitsHeader(OutFitsStream& str, int dd)
  {return image_ ? image_->saveFitsHeader(str, dd) : 0;}

  int saveFits(OutFitsStream& str)
  {return image_ ? image_->saveFits(str) : 0;}

  int saveFitsPad(OutFitsStream& str, size_t cnt, char fil)
  {return image_ ? image_->saveFitsPad(str, cnt, fil) : 0;}

  int saveFitsTable(OutFitsStream& str)
  {return fits_ ? fits_->saveFitsTable(str) : 0;}

  int saveArray(OutFitsStream& str, FitsFile::ArchType endian)
  {return image_ ? image_->saveArray(str, endian) : 0;}

  int saveFitsIISHeader(OutFitsStream& str)
  {return image_ ? image_->saveFitsIISHeader(str) : 0;}

  int saveFitsIIS(OutFitsStream& str)
  {return image_ ? image_->saveFitsIIS(str,iisz_) : 0;}
};

// Fits

class FitsImageFitsAlloc : public FitsImage {
public:
  FitsImageFitsAlloc(Base*, const char*, const char*, 
		     FitsFile::FlushMode, int);
};

class FitsImageFitsAllocGZ : public FitsImage {
public:
  FitsImageFitsAllocGZ(Base*, const char*, const char*, 
		       FitsFile::FlushMode, int);
};

class FitsImageFitsChannel : public FitsImage {
public:
  FitsImageFitsChannel(Base*, Tcl_Interp*, const char*, const char*,
		       FitsFile::FlushMode, int);
};

class FitsImageFitsMMap : public FitsImage {
public:
  FitsImageFitsMMap(Base*, const char*, int);
};

class FitsImageFitsSMMap : public FitsImage {
public:
  FitsImageFitsSMMap(Base*, const char*, const char*, int);
};

class FitsImageFitsMMapIncr : public FitsImage {
public:
  FitsImageFitsMMapIncr(Base*, const char*, int);
};

class FitsImageFitsShare : public FitsImage {
public:
  FitsImageFitsShare(Base*, Base::ShmType, int, const char*, int);
};

class FitsImageFitsSShare : public FitsImage {
public:
  FitsImageFitsSShare(Base*, Base::ShmType, int, int, const char*, int);
};

class FitsImageFitsSocket : public FitsImage {
public:
  FitsImageFitsSocket(Base*, int, const char*, FitsFile::FlushMode, int);
};

class FitsImageFitsSocketGZ : public FitsImage {
public:
  FitsImageFitsSocketGZ(Base*, int, const char*, FitsFile::FlushMode, int);
};

class FitsImageFitsVar : public FitsImage {
public:
  FitsImageFitsVar(Base*, Tcl_Interp*, const char*, const char*, int);
};

class FitsImageFitsOrder : public FitsImage {
public:
  FitsImageFitsOrder(Base*, FitsImage*, FitsHead*, char*, size_t, int);
};

// Fits Next

class FitsImageFitsNextAlloc : public FitsImage {
public:
  FitsImageFitsNextAlloc(Base*, const char*, FitsFile*, int);
};

class FitsImageFitsNextAllocGZ : public FitsImage {
public:
  FitsImageFitsNextAllocGZ(Base*, const char*, FitsFile*, int);
};

class FitsImageFitsNextChannel : public FitsImage {
public:
  FitsImageFitsNextChannel(Base*, const char*, FitsFile*, int);
};

class FitsImageFitsNextMMap : public FitsImage {
public:
  FitsImageFitsNextMMap(Base*, const char*, FitsFile*, int);
};

class FitsImageFitsNextSMMap : public FitsImage {
public:
  FitsImageFitsNextSMMap(Base*, const char*, FitsFile*, int);
};

class FitsImageFitsNextMMapIncr : public FitsImage {
public:
  FitsImageFitsNextMMapIncr(Base*, const char*, FitsFile*, int);
};

class FitsImageFitsNextShare : public FitsImage {
public:
  FitsImageFitsNextShare(Base*, const char*, FitsFile*, int);
};

class FitsImageFitsNextSShare : public FitsImage {
public:
  FitsImageFitsNextSShare(Base*, const char*, FitsFile*, int);
};

class FitsImageFitsNextSocket : public FitsImage {
public:
  FitsImageFitsNextSocket(Base*, const char*, FitsFile*, int);
};

class FitsImageFitsNextSocketGZ : public FitsImage {
public:
  FitsImageFitsNextSocketGZ(Base*, const char*, FitsFile*, int);
};

class FitsImageFitsNextVar : public FitsImage {
public:
  FitsImageFitsNextVar(Base*, const char*, FitsFile*, int);
};

class FitsImageFitsNextHist : public FitsImage {
public:
  FitsImageFitsNextHist(Base*, FitsImage*, FitsFile*, int);
};

class FitsImageFitsNextPost : public FitsImage {
public:
  FitsImageFitsNextPost(Base*, FitsImage*, FitsFile*, int);
};

class FitsImageFitsNextOrder : public FitsImage {
public:
  FitsImageFitsNextOrder(Base*, FitsImage*, FitsFile*, int);
};

// Array

class FitsImageArrAlloc : public FitsImage {
public:
  FitsImageArrAlloc(Base*, const char*, const char*, 
		    FitsFile::FlushMode, int);
};

class FitsImageArrAllocGZ : public FitsImage {
public:
  FitsImageArrAllocGZ(Base*, const char*, const char*, 
		      FitsFile::FlushMode, int);
};

class FitsImageArrChannel : public FitsImage {
public:
  FitsImageArrChannel(Base*, Tcl_Interp*, const char*, const char*, 
		      FitsFile::FlushMode, int);
};

class FitsImageArrMMap : public FitsImage {
public:
  FitsImageArrMMap(Base*, const char*, int);
};

class FitsImageArrMMapIncr : public FitsImage {
public:
  FitsImageArrMMapIncr(Base*, const char*, int);
};

class FitsImageArrShare : public FitsImage {
public:
  FitsImageArrShare(Base*, Base::ShmType, int, const char*, int);
};

class FitsImageArrSocket : public FitsImage {
public:
  FitsImageArrSocket(Base*, int, const char*, FitsFile::FlushMode, int);
};

class FitsImageArrSocketGZ : public FitsImage {
public:
  FitsImageArrSocketGZ(Base*, int, const char*, FitsFile::FlushMode, int);
};

class FitsImageArrVar : public FitsImage {
public:
  FitsImageArrVar(Base*, Tcl_Interp*, const char*, const char*, int);
};

// ENVI

class FitsImageENVISMMap : public FitsImage {
public:
  FitsImageENVISMMap(Base*, const char*, const char*, int);
};

// NRRD

class FitsImageNRRDAlloc : public FitsImage {
public:
  FitsImageNRRDAlloc(Base*, const char*, const char*, 
		    FitsFile::FlushMode, int);
};

class FitsImageNRRDChannel : public FitsImage {
public:
  FitsImageNRRDChannel(Base*, Tcl_Interp*, const char*, const char*, 
		      FitsFile::FlushMode, int);
};

class FitsImageNRRDMMap : public FitsImage {
public:
  FitsImageNRRDMMap(Base*, const char*, int);
};

class FitsImageNRRDShare : public FitsImage {
public:
  FitsImageNRRDShare(Base*, Base::ShmType, int, const char*, int);
};

class FitsImageNRRDSocket : public FitsImage {
public:
  FitsImageNRRDSocket(Base*, int, const char*, FitsFile::FlushMode, int);
};

class FitsImageNRRDVar : public FitsImage {
public:
  FitsImageNRRDVar(Base*, Tcl_Interp*, const char*, const char*, int);
};

// Photo

class FitsImagePhoto : public FitsImage {
public:
  FitsImagePhoto(Base*, Tcl_Interp*, const char*, const char*, int);
};

class FitsImagePhotoCube : public FitsImage {
public:
  FitsImagePhotoCube(Base*, Tcl_Interp*, const char*, const char*, int);
};

class FitsImagePhotoCubeNext : public FitsImage {
public:
  FitsImagePhotoCubeNext(Base*, const char*, FitsFile*, int);
};

// Mosaic

class FitsImageMosaicAlloc : public FitsImage {
public:
  FitsImageMosaicAlloc(Base*, const char*, const char*, 
		       FitsFile::FlushMode, int);
};

class FitsImageMosaicAllocGZ : public FitsImage {
public:
  FitsImageMosaicAllocGZ(Base*, const char*, const char*, 
			 FitsFile::FlushMode, int);
};

class FitsImageMosaicChannel : public FitsImage {
public:
  FitsImageMosaicChannel(Base*, Tcl_Interp*, const char*, const char*,
			 FitsFile::FlushMode, int);
};

class FitsImageMosaicMMap : public FitsImage {
public:
  FitsImageMosaicMMap(Base*, const char*, int);
};

class FitsImageMosaicMMapIncr : public FitsImage {
public:
  FitsImageMosaicMMapIncr(Base*, const char*, int);
};

class FitsImageMosaicShare : public FitsImage {
public:
  FitsImageMosaicShare(Base*, Base::ShmType, int, const char*, int);
};

class FitsImageMosaicSocket : public FitsImage {
public:
  FitsImageMosaicSocket(Base*, int, const char*, FitsFile::FlushMode, int);
};

class FitsImageMosaicSocketGZ : public FitsImage {
public:
  FitsImageMosaicSocketGZ(Base*, int, const char*, FitsFile::FlushMode, int);
};

class FitsImageMosaicVar : public FitsImage {
public:
  FitsImageMosaicVar(Base*, Tcl_Interp*, const char*, const char*, int);
};

// Mosaic Next

class FitsImageMosaicNextAlloc : public FitsImage {
public:
  FitsImageMosaicNextAlloc(Base*, const char*, FitsFile*, 
			   FitsFile::FlushMode, int);
};

class FitsImageMosaicNextAllocGZ : public FitsImage {
public:
  FitsImageMosaicNextAllocGZ(Base*, const char*, FitsFile*, 
			     FitsFile::FlushMode, int);
};

class FitsImageMosaicNextChannel : public FitsImage {
public:
  FitsImageMosaicNextChannel(Base*, const char*, FitsFile*, 
			     FitsFile::FlushMode, int);
};

class FitsImageMosaicNextMMap : public FitsImage {
public:
  FitsImageMosaicNextMMap(Base*, const char*, FitsFile*, int);
};

class FitsImageMosaicNextMMapIncr : public FitsImage {
public:
  FitsImageMosaicNextMMapIncr(Base*, const char*, FitsFile*, int);
};

class FitsImageMosaicNextShare : public FitsImage {
public:
  FitsImageMosaicNextShare(Base*, const char*, FitsFile*, int);
};

class FitsImageMosaicNextSocket : public FitsImage {
public:
  FitsImageMosaicNextSocket(Base*, const char*, FitsFile*, 
			    FitsFile::FlushMode, int);
};

class FitsImageMosaicNextSocketGZ : public FitsImage {
public:
  FitsImageMosaicNextSocketGZ(Base*, const char*, FitsFile*, 
			      FitsFile::FlushMode, int);
};

class FitsImageMosaicNextVar : public FitsImage {
public:
  FitsImageMosaicNextVar(Base*, const char*, FitsFile*, int);
};

// IIS

class FitsImageIIS : public FitsImage {
public:
  FitsImageIIS(Base*, int, int);
  void iisErase();
  char* iisGet(int xx, int yy, int dx, int dy);
  void iisSet(const char* src, int xx, int yy, int dx, int dy);
  void iisWCS(const Matrix&, const Vector&, int);
};

#endif
