#ifndef amdmsFits_H
#define amdmsFits_H

#include "fitsio.h"
#include "amdms.h"


typedef enum {
  amdmsUNDEFINED_STATE,
  amdmsERROR_STATE,
  amdmsFILE_OPENED_STATE,
  amdmsFILE_CREATED_STATE,
  amdmsCUBE_OPENED_STATE,
  amdmsCUBE_CREATED_STATE,
  amdmsTABLE_OPENED_STATE,
  amdmsTABLE_CREATED_STATE
} amdmsFITS_STATE;


typedef struct _amdmsKEYWORD {
  struct _amdmsKEYWORD  *next;
  char                  name[80];
  char                  comment[80];
  int                   type;
  int                   decimals;
  long                  longValue;
  double                doubleValue;
  char                  stringValue[80];
} amdmsKEYWORD;

typedef struct {
  /* IMAGING_DETECTOR binary table */
  /* HDU keywords */
  /* number of detectors */
  amdmsBOOL              nDetectFlag;
  int                   nDetect;
  /* number of regions/subwindows */
  amdmsBOOL              nRegionFlag;
  int                   nRegion;
  /* number of coefficients for DMP and DMC (max 256) */
  amdmsBOOL              maxCoefFlag;
  int                   maxCoef;
  /* number of detector array dimensions (2) */
  amdmsBOOL              numDimFlag;
  int                   numDim;
  /* maximum numbers of telescopes (3) */
  amdmsBOOL              maxTelFlag;
  int                   maxTel;
  /* binary table contents */
  /* region/subwindow number */
  amdmsBOOL              regionFlag;
  int                   regionColNr;
  int                   region[amdmsMAX_REGIONS];
  /* detector number */
  amdmsBOOL              detectorFlag;
  int                   detectorColNr;
  int                   detector[amdmsMAX_REGIONS];
  /* port number */
  amdmsBOOL              portsFlag;
  int                   portsColNr;
  int                   ports[amdmsMAX_REGIONS][amdmsMAX_TELS];
  /* correlation */
  amdmsBOOL              correlationFlag;
  int                   correlationColNr;
  int                   correlation[amdmsMAX_REGIONS];
  /* region name (-> IMAGING DATA binary table column name) */
  amdmsBOOL              regNameFlag;
  int                   regNameColNr;
  char                  regName[amdmsMAX_REGIONS][amdmsMAX_COLNAME_LEN];
  /* coordinate of lower left corner (0,0 is lower left corner of detector) */
  amdmsBOOL              cornerFlag;
  int                   cornerColNr;
  int                   corner[amdmsMAX_REGIONS][2];
  /* gain value (conversion factor 4.2 e-/DU) */
  amdmsBOOL              gainFlag;
  int                   gainColNr;
  double                gain[amdmsMAX_REGIONS];
  /* region/subwindow size */
  amdmsBOOL              nAxisFlag;
  int                   nAxisColNr;
  int                   nAxis[amdmsMAX_REGIONS][2];
  /* ??? */
  amdmsBOOL              CRValFlag;
  int                   CRValColNr;
  double                CRVal[amdmsMAX_REGIONS][2];
  /* ??? */
  amdmsBOOL              CRPixFlag;
  int                   CRPixColNr;
  double                CRPix[amdmsMAX_REGIONS][2];
  /* ??? */
  amdmsBOOL              cTypeFlag;
  int                   cTypeColNr;
  char                  cType[amdmsMAX_REGIONS][amdmsMAX_COLNAME_LEN];
  /* ??? */
  amdmsBOOL              CDFlag;
  int                   CDColNr;
  double                CD[amdmsMAX_REGIONS][4];
  /* ??? */
  amdmsBOOL              DMPFlag;
  int                   DMPColNr;
  int                   DMP[amdmsMAX_REGIONS][256];
  /* ??? */
  amdmsBOOL              DMCFlag;
  int                   DMCColNr;
  double                DMC[amdmsMAX_REGIONS][256];
} amdmsIMAGING_DETECTOR;

typedef struct {
  /* IMAGING_DATA binary table */
  /* HDU keywords */
  /* number of instrument trains */
  amdmsBOOL              maxInsFlag;
  int                   maxIns;
  /* number of observation steps */
  amdmsBOOL              maxStepFlag;
  int                   maxStep;
  /* binary table contents */
  /* frame number */
  amdmsBOOL              frameFlag;
  int                   frameColNr;
  int                   frame;
  /* observation time */
  amdmsBOOL              timeFlag;
  int                   timeColNr;
  double                time;
  /* exposure time */
  amdmsBOOL              exptimeFlag;
  int                   exptimeColNr;
  float                 exptime;
  /* optical train */
  amdmsBOOL              optTrainFlag;
  int                   optTrainColNr;
  short                 optTrain[amdmsMAX_TELS];
  /* instrument train */
  amdmsBOOL              insTrainFlag;
  int                   insTrainColNr;
  short                 insTrain[amdmsMAX_TRAINS];
  /* ??? */
  amdmsBOOL              referenceFlag;
  int                   referenceColNr;
  short                 reference;
  /* ??? */
  amdmsBOOL              opdFlag;
  int                   opdColNr;
  double                opd[amdmsMAX_TELS];
  /* ??? */
  amdmsBOOL              localOpdFlag;
  int                   localOpdColNr;
  double                localOpd[amdmsMAX_TELS];
  /* ??? */
  amdmsBOOL              offsetFlag;
  int                   offsetColNr;
  float                 offset[2];
  /* ??? */
  amdmsBOOL              rotationFlag;
  int                   rotationColNr;
  float                 rotation;
  /* ??? */
  amdmsBOOL              steppingPhaseFlag;
  int                   steppingPhaseColNr;
  short                 steppingPhase;
  /* ??? */
  amdmsBOOL              targetFlag;
  int                   targetColNr[amdmsMAX_REGIONS];
  short                 target[amdmsMAX_REGIONS];
  /* ??? */
  amdmsBOOL              tarTypFlag;
  int                   tarTypColNr[amdmsMAX_REGIONS];
  char                  tarTyp[amdmsMAX_REGIONS][amdmsMAX_TARTYP_LEN];
  /* camera data for each subwindow */
  amdmsBOOL              dataFlag;
  int                   dataColNr[amdmsMAX_REGIONS];
  float                *data[amdmsMAX_REGIONS];
} amdmsIMAGING_DATA;

typedef struct _amdmsFITS {
  fitsfile             *fits;
  amdmsFITS_FLAGS        flags;
  amdmsBOOL              isNew;
  amdmsFITS_STATE        currStateFile;
  amdmsFITS_STATE        currStateHDU;
  /* information about images and cubes */
  int                   bitpix;
  int                   nAxis;
  /* number of telescopes (1 = calibration full frame) */
  int                   nTel;
  /* number of subwindow columns (1 = calibration frame) */
  int                   nCols;
  /* number of subwindow rows (1 = calibration frame) */
  int                   nRows;
  /* region definition */
  amdmsREGION            regions[amdmsMAX_COLS][amdmsMAX_ROWS];
  /* horizontal size of glued image */
  int                   nx;
  /* vertical size of glued image */
  int                   ny;
  /* number of images (input and output) */
  int                   nImages;
  /* number of reads per image (1) */
  int                   nReads;
  /* number of pixels per read (nx*ny) */
  int                   nPixels;
  /* exposure time (EXPTIME from primary HDU) */
  float                 exptime;
  char                 *fileName;
  char                 *tableExt;
  int                  *rowIndex;
  /* index column type (TDOUBLE of TINT) */
  int                   indexColType;
  /* name of the index/first column */
  char                 *indexColName;
  /* region/subwindow column data type (TFLOAT or TBYTE) */
  int                   regionColType;
  /* generic region/subwindow columd name (DATA) */
  char                 *regionColName;
  /* column type, form and unit for new binary tables */
  int                   outNCols;
  char                 *outColType[amdmsMAX_BTBL_COLS];
  char                 *outColForm[amdmsMAX_BTBL_COLS];
  char                 *outColUnit[amdmsMAX_BTBL_COLS];
  struct _amdmsFITS     *hdrTable;
  amdmsKEYWORD          *hdrKeys;
  amdmsIMAGING_DETECTOR  detector;
  amdmsIMAGING_DATA      data;
  amdmsBOOL              allocated;
} amdmsFITS;

#ifdef __cplusplus
extern "C" {
#endif

  amdmsCOMPL amdmsCreateFitsFile(amdmsFITS **file,
			       char *fileName);
  amdmsCOMPL amdmsOpenFitsFile(amdmsFITS **file,
			     char *fileName);
  amdmsCOMPL amdmsCloseFitsFile(amdmsFITS **file);
  amdmsCOMPL amdmsDeleteFitsFile(amdmsFITS **file);

  void amdmsSetRegion(amdmsFITS *file,
		     int col,
		     int row,
		     int x,
		     int y,
		     int width,
		     int height);
  void amdmsSetCol(amdmsFITS *file,
		  int col,
		  int x,
		  int width);
  void amdmsSetRow(amdmsFITS *file,
		  int row,
		  int y,
		  int height);
  void amdmsRecalcRegions(amdmsFITS *file);
  void amdmsSetRegions(amdmsFITS *dst,
		       amdmsFITS *src);

  amdmsCOMPL amdmsAdjustDataFilterSetup(amdmsDATA_FILTER_SETUP *setup,
				      amdmsFITS *file);

  amdmsCOMPL amdmsMoveToExtension(amdmsFITS *file,
				char* extName,
				int hduType,
				amdmsBOOL force);
  amdmsCOMPL amdmsMoveToHDU(amdmsFITS *file,
			  int hduNum);
  amdmsCOMPL amdmsMoveToLastHDU(amdmsFITS *file);
  amdmsCOMPL amdmsCopyHeader(amdmsFITS *dst,
			   amdmsFITS *src);
  amdmsCOMPL amdmsCopyExtension(amdmsFITS *dst,
			      amdmsFITS *src,
			      char *extName,
			      amdmsBOOL force);

  amdmsBOOL amdmsReadKeywordInt(amdmsFITS *file,
			      char *name,
			      int *value,
			      char *comment);
  amdmsBOOL amdmsReadKeywordLong(amdmsFITS *file,
			       char *name,
			       long *value,
			       char *comment);
  amdmsBOOL amdmsReadKeywordFloat(amdmsFITS *file,
				char *name,
				float *value,
				char *comment);
  amdmsBOOL amdmsReadKeywordDouble(amdmsFITS *file,
				 char *name,
				 double *value,
				 char *comment);
  amdmsBOOL amdmsReadKeywordString(amdmsFITS *file,
				 char *name,
				 char *value,
				 char *comment);
  amdmsCOMPL amdmsUpdateKeywordInt(amdmsFITS *file,
				 char *name,
				 int value,
				 char *comment);
  amdmsCOMPL amdmsUpdateKeywordLong(amdmsFITS *file,
				  char *name,
				  long value,
				  char *comment);
  amdmsCOMPL amdmsUpdateKeywordFloat(amdmsFITS *file,
				   char *name,
				   float value,
				   int decimals,
				   char *comment);
  amdmsCOMPL amdmsUpdateKeywordDouble(amdmsFITS *file,
				    char *name,
				    double value,
				    int decimals,
				    char *comment);
  amdmsCOMPL amdmsUpdateKeywordString(amdmsFITS *file,
				    char *name,
				    char *value,
				    char *comment);
  amdmsKEYWORD *amdmsAppendKeyword(amdmsFITS *file,
				 char *name,
				 int type,
				 char *comment);
  amdmsCOMPL amdmsUpdateKeywords(amdmsFITS *file);

  amdmsCOMPL amdmsCreateSimpleData(amdmsFITS *file,
				 amdmsFITS_FLAGS flags,
				 int nx,
				 int ny,
				 int nImages,
				 int nReads);
  amdmsCOMPL amdmsCreateData(amdmsFITS *file,
			   amdmsFITS_FLAGS flags,
			   int nImages,
			   int nReads);
  amdmsCOMPL amdmsOpenData(amdmsFITS *file,
			 amdmsFITS_FLAGS flags,
			 int nReads);
  amdmsCOMPL amdmsReadData(amdmsFITS *file,
			 amdmsDATA *data,
			 int iImage,
			 int iRead);
  amdmsCOMPL amdmsWriteData(amdmsFITS *file,
			  amdmsDATA *data,
			  int iImage,
			  int iRead);
  amdmsCOMPL amdmsReadImagingDetectorFromTable(amdmsFITS *file);
  amdmsCOMPL amdmsReadImagingDetectorFromHeader(amdmsFITS *file);
  amdmsCOMPL amdmsCreateImagingDetectorTable(amdmsFITS *file);

  amdmsCOMPL amdmsCreateTable(amdmsFITS *file,
			    char *extName,
			    int indexColType,
			    int regionColType,
			    int nReads);
  amdmsCOMPL amdmsOpenTable(amdmsFITS *file,
			  char *extName,
			  int nReads);
  amdmsCOMPL amdmsReadRow(amdmsFITS *file,
			amdmsDATA *data,
			int iImage,
			int iRead);
  amdmsCOMPL amdmsWriteRow(amdmsFITS *file,
			 amdmsDATA *data,
			 int iImage,
			 int iRead);
  amdmsCOMPL amdmsAddColumn(amdmsFITS *file,
			  int colType,
			  int nEls,
			  char *colName,
			  int colNameExt,
			  char *colUnit);
  amdmsBOOL amdmsGetColumnIndex(amdmsFITS *file,
			      char *name,
			      int *index);
  amdmsCOMPL amdmsReadElements(amdmsFITS *file,
			     int dataType,
			     int iCol,
			     long iRow,
			     long nEls,
			     void *values);
  amdmsCOMPL amdmsWriteElementLong(amdmsFITS *file,
				 int iCol,
				 long iRow,
				 long value,
				 long offset);
  /* amdmsCOMPL amdmsWriteElementFloat(amdmsFITS *file, int iCol, int iRow, float value, int offset); */
  amdmsCOMPL amdmsWriteElementDouble(amdmsFITS *file,
				   int iCol,
				   long iRow,
				   double value,
				   long offset);
  amdmsCOMPL amdmsWriteElementString(amdmsFITS *file,
				   int iCol,
				   long iRow,
				   char *value,
				   long offset);
  amdmsCOMPL amdmsWriteElements(amdmsFITS *file,
			      int dataType,
			      int iCol,
			      long iRow,
			      long nEls,
			      void *values);

  amdmsCOMPL amdmsCreateImageCube(amdmsFITS *file,
				char *extName,
				int imageType,
				int nImages,
				int nReads);
  amdmsCOMPL amdmsCreateEmptyImageCube(amdmsFITS *file);
  amdmsCOMPL amdmsOpenImageCube(amdmsFITS *file,
			      char *extName,
			      int nReads);
  amdmsCOMPL amdmsReadImage(amdmsFITS *file,
			  amdmsDATA *data,
			  int iImage,
			  int iRead);
  amdmsCOMPL amdmsWriteImage(amdmsFITS *file,
			   amdmsDATA *data,
			   int iImage,
			   int iRead);

  void amdmsReportFitsError(amdmsFITS *file,
			   int status,
			   int line,
			   char *info);

#ifdef __cplusplus
}
#endif

#endif /* !amdmsFits_H */
