#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <math.h>

#include "amdmsFits.h"

#define amdmsIMAGING_DETECTOR_EXT             "IMAGING_DETECTOR"
#define amdmsIMAGING_DATA_EXT                 "IMAGING_DATA"
#define amdmsAMBER_WAVE_EXT                   "AMBER_WAVEDATA"
#define amdmsPIXEL_STAT_EXT                   "PIXEL_STAT"
#define amdmsPIXEL_BIAS_EXT                   "PIXEL_BIAS"
#define amdmsBAD_PIXEL_EXT                    "BAD_PIXEL"
#define amdmsFLATFIELD_EXT                    "FLATFIELD"
#define amdmsFLATFIELD_FIT_EXT                "FLATFIELD_FIT"
#define amdmsCONVERSION_FACTOR_EXT            "CONVERSION_FACTOR"
#define amdmsREADOUT_NOISE_EXT                "READOUT_NOISE"
#define amdmsPHOTON_NOISE_EXT                 "PHOTON_NOISE"
#define amdmsNONLINEARITY_EXT                 "NONLINEARITY"
#define amdmsNONLINEARITY_FIT_EXT             "NONLINEARITY_FIT"
#define amdmsPTC_EXT                          "PTC"
#define amdmsFFT_EXT                          "FFT"
#define amdmsFUZZY_EXT                        "FUZZY"
#define amdmsPARTICLE_EVENT_EXT               "PARTICLE_EVENT"
#define amdmsELECTRONIC_BIAS_EXT              "ELECTRONIC_EVENT"
#define amdmsDARK_CURRENT_EXT                 "DARK_CURRENT"
#define amdmsHISTOGRAM_EXT                    "HISTOGRAM"

amdmsCOMPL amdmsCreateSimpleData(amdmsFITS *file, amdmsFITS_FLAGS flags, int nx, int ny, int nImages, int nReads)
{
  file->nTel = 1;
  file->nRows = 0;
  file->nCols = 0;
  file->nx = 0;
  file->ny = 0;
  file->nImages = 0;
  amdmsSetRegion(file, 0, 0, 0, 0, nx, ny);
  return amdmsCreateData(file, flags, nImages, nReads);
}

amdmsCOMPL amdmsCreateData(amdmsFITS *file, amdmsFITS_FLAGS flags, int nImages, int nReads)
{
  int     idxType;
  int     dataType;
  char   *extName;

  amdmsDebug(__FILE__, __LINE__, "amdmsCreateData(%s, (%d, %d, %d), %d, %d)",
	    file->fileName, flags.content, flags.format, flags.type, nImages, nReads);
  switch (flags.content) {
  case amdmsIMAGING_DATA_CONTENT:          idxType = TDOUBLE; break;
  case amdmsPIXEL_STAT_CONTENT:            idxType = TINT;    break;
  case amdmsPIXEL_BIAS_CONTENT:            idxType = TINT;    break;
  case amdmsBAD_PIXEL_CONTENT:             idxType = TINT;    break;
  case amdmsFLATFIELD_CONTENT:             idxType = TINT;    break;
  case amdmsFLATFIELD_FIT_CONTENT:         idxType = TINT;    break;
  case amdmsCONVERSION_FACTOR_CONTENT:     idxType = TINT;    break;
  case amdmsFFT_CONTENT:                   idxType = TDOUBLE; break;
  case amdmsREADOUT_NOISE_CONTENT:         idxType = TINT;    break;
  case amdmsPHOTON_NOISE_CONTENT:          idxType = TINT;    break;
  case amdmsNONLINEARITY_CONTENT:          idxType = TINT;    break;
  case amdmsNONLINEARITY_FIT_CONTENT:      idxType = TINT;    break;
  case amdmsPTC_CONTENT:                   idxType = TINT;    break;
  case amdmsFUZZY_CONTENT:                 idxType = TINT;    break;
  case amdmsPARTICLE_EVENT_CONTENT:        idxType = TINT;    break;
  case amdmsELECTRONIC_BIAS_CONTENT:       idxType = TINT;    break;
  case amdmsDARK_CURRENT_CONTENT:          idxType = TINT;    break;
  case amdmsHISTOGRAM_CONTENT:             idxType = TINT;    break;
  default:
    return amdmsFAILURE;
  }
  switch (flags.format) {
  case amdmsTABLE_FORMAT:
    switch (flags.type) {
    case amdmsBYTE_TYPE:   dataType = TBYTE;   break;
    case amdmsSHORT_TYPE:  dataType = TSHORT;  break;
    case amdmsINT_TYPE:    dataType = TINT;    break;
    case amdmsLONG_TYPE:   dataType = TLONG;   break;
    case amdmsFLOAT_TYPE:  dataType = TFLOAT;  break;
    case amdmsDOUBLE_TYPE: dataType = TDOUBLE; break;
    default:
      return amdmsFAILURE;
    }
    break;
  case amdmsCUBE_FORMAT:
    switch (flags.type) {
    case amdmsBYTE_TYPE:   dataType = BYTE_IMG;   break;
    case amdmsSHORT_TYPE:  dataType = SHORT_IMG;  break;
    case amdmsINT_TYPE:    dataType = LONG_IMG;   break;
    case amdmsLONG_TYPE:   dataType = LONG_IMG;   break;
    case amdmsFLOAT_TYPE:  dataType = FLOAT_IMG;  break;
    case amdmsDOUBLE_TYPE: dataType = DOUBLE_IMG; break;
    default:
      return amdmsFAILURE;
    }
    break;
  default:
    return amdmsFAILURE;
  }
  switch (flags.content) {
  case amdmsIMAGING_DATA_CONTENT:          extName = amdmsIMAGING_DATA_EXT;          break;
  case amdmsPIXEL_STAT_CONTENT:            extName = amdmsPIXEL_STAT_EXT;            break;
  case amdmsPIXEL_BIAS_CONTENT:            extName = amdmsPIXEL_BIAS_EXT;            break;
  case amdmsBAD_PIXEL_CONTENT:             extName = amdmsBAD_PIXEL_EXT;             break;
  case amdmsFLATFIELD_CONTENT:             extName = amdmsFLATFIELD_EXT;             break;
  case amdmsFLATFIELD_FIT_CONTENT:         extName = amdmsFLATFIELD_FIT_EXT;         break;
  case amdmsCONVERSION_FACTOR_CONTENT:     extName = amdmsCONVERSION_FACTOR_EXT;     break;
  case amdmsFFT_CONTENT:                   extName = amdmsFFT_EXT;                   break;
  case amdmsREADOUT_NOISE_CONTENT:         extName = amdmsREADOUT_NOISE_EXT;         break;
  case amdmsPHOTON_NOISE_CONTENT:          extName = amdmsPHOTON_NOISE_EXT;          break;
  case amdmsNONLINEARITY_CONTENT:          extName = amdmsNONLINEARITY_EXT;          break;
  case amdmsNONLINEARITY_FIT_CONTENT:      extName = amdmsNONLINEARITY_FIT_EXT;      break;
  case amdmsPTC_CONTENT:                   extName = amdmsPTC_EXT;                   break;
  case amdmsFUZZY_CONTENT:                 extName = amdmsFUZZY_EXT;                 break;
  case amdmsPARTICLE_EVENT_CONTENT:        extName = amdmsPARTICLE_EVENT_EXT;        break;
  case amdmsELECTRONIC_BIAS_CONTENT:       extName = amdmsELECTRONIC_BIAS_EXT;       break;
  case amdmsDARK_CURRENT_CONTENT:          extName = amdmsDARK_CURRENT_EXT;          break;
  case amdmsHISTOGRAM_CONTENT:             extName = amdmsHISTOGRAM_EXT;             break;
  default:
    return amdmsFAILURE;
  }
  switch (flags.format) {
  case amdmsTABLE_FORMAT:
    file->flags = flags;
    return amdmsCreateTable(file, extName, idxType, dataType, nReads);
  case amdmsCUBE_FORMAT:
    file->flags = flags;
    return amdmsCreateImageCube(file, extName, dataType, nImages, nReads);
  default:
    return amdmsFAILURE;
  }
}

amdmsCOMPL amdmsOpenData(amdmsFITS *file, amdmsFITS_FLAGS flags, int nReads)
{
  char   *extName;

  amdmsDebug(__FILE__, __LINE__, "amdmsOpenData(%s, (%d, %d, %d), %d)",
	    file->fileName, flags.content, flags.format, flags.type, nReads);
  switch (flags.content) {
  case amdmsIMAGING_DATA_CONTENT:          extName = amdmsIMAGING_DATA_EXT;          break;
  case amdmsPIXEL_STAT_CONTENT:            extName = amdmsPIXEL_STAT_EXT;            break;
  case amdmsPIXEL_BIAS_CONTENT:            extName = amdmsPIXEL_BIAS_EXT;            break;
  case amdmsBAD_PIXEL_CONTENT:             extName = amdmsBAD_PIXEL_EXT;             break;
  case amdmsFLATFIELD_CONTENT:             extName = amdmsFLATFIELD_EXT;             break;
  case amdmsFLATFIELD_FIT_CONTENT:         extName = amdmsFLATFIELD_FIT_EXT;         break;
  case amdmsCONVERSION_FACTOR_CONTENT:     extName = amdmsCONVERSION_FACTOR_EXT;     break;
  case amdmsFFT_CONTENT:                   extName = amdmsFFT_EXT;                   break;
  case amdmsREADOUT_NOISE_CONTENT:         extName = amdmsREADOUT_NOISE_EXT;         break;
  case amdmsPHOTON_NOISE_CONTENT:          extName = amdmsPHOTON_NOISE_EXT;          break;
  case amdmsNONLINEARITY_CONTENT:          extName = amdmsNONLINEARITY_EXT;          break;
  case amdmsNONLINEARITY_FIT_CONTENT:      extName = amdmsNONLINEARITY_FIT_EXT;      break;
  case amdmsPTC_CONTENT:                   extName = amdmsPTC_EXT;                   break;
  case amdmsFUZZY_CONTENT:                 extName = amdmsFUZZY_EXT;                 break;
  case amdmsPARTICLE_EVENT_CONTENT:        extName = amdmsPARTICLE_EVENT_EXT;        break;
  case amdmsELECTRONIC_BIAS_CONTENT:       extName = amdmsELECTRONIC_BIAS_EXT;       break;
  case amdmsDARK_CURRENT_CONTENT:          extName = amdmsDARK_CURRENT_EXT;          break;
  case amdmsHISTOGRAM_CONTENT:             extName = amdmsHISTOGRAM_EXT;             break;
  default:
    return amdmsFAILURE;
  }
  switch (flags.format) {
  case amdmsTABLE_FORMAT:
    file->flags = flags;
    return amdmsOpenTable(file, extName, nReads);
  case amdmsCUBE_FORMAT:
    file->flags = flags;
    return amdmsOpenImageCube(file, extName, nReads);
  default:
    return amdmsFAILURE;
  }
}

amdmsCOMPL amdmsReadData(amdmsFITS *file, amdmsDATA *data, int iImage, int iRead)
{
  switch (file->currStateHDU) {
  case amdmsTABLE_OPENED_STATE:
    return amdmsReadRow(file, data, iImage, iRead);
  case amdmsCUBE_OPENED_STATE:
    return amdmsReadImage(file, data, iImage, iRead);
  default:
    /* amdmsVBF(amdmsVERBOSE_ERROR, (stderr, "ERROR: amdmsFITS::ReadData(..), no table or cube opened!\n")); */
    return amdmsFAILURE;
  }
}

amdmsCOMPL amdmsWriteData(amdmsFITS *file, amdmsDATA *data, int iImage, int iRead)
{
  switch (file->currStateHDU) {
  case amdmsTABLE_CREATED_STATE:
    return amdmsWriteRow(file, data, iImage, iRead);
  case amdmsCUBE_CREATED_STATE:
    return amdmsWriteImage(file, data, iImage, iRead);
  default:
    /* amdmsVBF(amdmsVERBOSE_ERROR, (stderr, "ERROR: amdmsFITS::WriteData(..), no table or cube created!\n")); */
    return amdmsFAILURE;
  }
}

amdmsCOMPL amdmsReadImagingDetectorFromTable(amdmsFITS *file)
{
  int                    iRow;
  int                    iCol;
  long                   iReg;
  int                    iTel;
  long                   nRs;
  int                    status = 0;
  amdmsCOMPL             retVal = amdmsSUCCESS;
  amdmsIMAGING_DETECTOR *det;
  char                  *str;

  amdmsDebug(__FILE__, __LINE__,
	    "amdmsReadImagingDetectorFromTable(%s), try to read the IMAGING_DETECTOR",
	    file->fileName);
  /* it is optional that the extension with the subwindow setup exists */
  if (amdmsMoveToExtension(file, amdmsIMAGING_DETECTOR_EXT, BINARY_TBL, amdmsFALSE) != amdmsSUCCESS) {
    amdmsDebug(__FILE__, __LINE__,
	      "amdmsReadImagingDetectorFromTable(%s), IMAGING_DETECTOR binary table not found!",
	      file->fileName);
    return amdmsSUCCESS;
  }
  /* read IMAGING_DETECTOR binary table */
  /* read keywords from current HDU */
  det = &(file->detector);
  det->nDetectFlag = amdmsReadKeywordInt(file, "NDETECT", &(det->nDetect), NULL);
  det->nRegionFlag = amdmsReadKeywordInt(file, "NREGION", &(det->nRegion), NULL);
  det->maxCoefFlag = amdmsReadKeywordInt(file, "MAX_COEF", &(det->maxCoef), NULL);
  det->numDimFlag = amdmsReadKeywordInt(file, "NUM_DIM", &(det->numDim), NULL);
  det->maxTelFlag = amdmsReadKeywordInt(file, "MAXTEL", &(det->maxTel), NULL);
  /* request column indices */
  det->regionFlag = amdmsGetColumnIndex(file, "REGION", &(det->regionColNr));
  det->detectorFlag = amdmsGetColumnIndex(file, "DETECTOR", &(det->detectorColNr));
  det->portsFlag = amdmsGetColumnIndex(file, "PORTS", &(det->portsColNr));
  det->correlationFlag = amdmsGetColumnIndex(file, "CORRELATION", &(det->correlationColNr));
  det->regNameFlag = amdmsGetColumnIndex(file, "REGNAME", &(det->regNameColNr));
  det->cornerFlag = amdmsGetColumnIndex(file, "CORNER", &(det->cornerColNr));
  det->gainFlag = amdmsGetColumnIndex(file, "GAIN", &(det->gainColNr));
  det->nAxisFlag = amdmsGetColumnIndex(file, "NAXIS", &(det->nAxisColNr));
  if (!det->nAxisFlag) {
    det->nAxisFlag = amdmsGetColumnIndex(file, "NAXES", &(det->nAxisColNr));
  }
  det->CRValFlag = amdmsGetColumnIndex(file, "CRVAL", &(det->CRValColNr));
  det->CRPixFlag = amdmsGetColumnIndex(file, "CRPIX", &(det->CRPixColNr));
  det->cTypeFlag = amdmsGetColumnIndex(file, "CTYPE", &(det->cTypeColNr));
  det->CDFlag = amdmsGetColumnIndex(file, "CD", &(det->CDColNr));
  det->DMPFlag = amdmsGetColumnIndex(file, "DMP", &(det->DMPColNr));
  det->DMCFlag = amdmsGetColumnIndex(file, "DMC", &(det->DMCColNr));
  /* request number of regions */
  if (fits_get_num_rows(file->fits, &nRs, &status ) != 0) {
    amdmsReportFitsError(file, status, __LINE__, NULL);
    return amdmsFAILURE;
  }
  if (file->nCols*file->nRows != nRs) {
    switch (nRs) {
    case 1: file->nCols = 1; file->nRows = 1; break;
    case 3: file->nCols = 1; file->nRows = 1; break;
    case 4: file->nCols = 4; file->nRows = 1; break;
    case 5: file->nCols = 5; file->nRows = 1; break;
    case 8: file->nCols = 4; file->nRows = 2; break;
    case 10: file->nCols = 5; file->nRows = 2; break;
    case 12: file->nCols = 4; file->nRows = 3; break;
    case 15: file->nCols = 5; file->nRows = 3; break;
    default:
      file->nCols = 0;
      file->nRows = 0;
    }
  }
  amdmsDebug(__FILE__, __LINE__,
	   "amdmsReadImagingDetectorFromTable(%s), reading IMAGING_DETECTOR binary table",
	   file->fileName);
  for (iRow = 0; iRow < file->nRows; iRow++) {
    for (iCol = 0; iCol < file->nCols; iCol++) {
      iReg = (long)(iRow*file->nCols + iCol);
      amdmsDebug(__FILE__, __LINE__,
		 "  iRow = %d, rCol = %d, iReg = %2d", iRow, iCol, iReg + 1);
      if (det->regionFlag && (retVal == amdmsSUCCESS)) {
	retVal = amdmsReadElements(file,
				  TINT, det->regionColNr, iReg + 1, 1L,
				  &(det->region[iReg]));
	if (retVal == amdmsSUCCESS) {
	  amdmsDebug(__FILE__, __LINE__, "    region = %d", det->region[iReg]);
	}
      }
      if (det->detectorFlag && (retVal == amdmsSUCCESS)) {
	retVal = amdmsReadElements(file,
				  TINT, det->detectorColNr, iReg + 1, 1L,
				  &(det->detector[iReg]));
	if (retVal == amdmsSUCCESS) {
	  amdmsDebug(__FILE__, __LINE__,
		     "    detector = %d", det->detector[iReg]);
	}
      }
      if (det->portsFlag && (retVal == amdmsSUCCESS)) {
	retVal = amdmsReadElements(file,
				  TINT, det->portsColNr, iReg + 1, (long)(det->maxTel),
				  &(det->ports[iReg]));
	if (retVal == amdmsSUCCESS) {
	  for (iTel = 0; iTel < det->maxTel; iTel++) {
	    amdmsDebug(__FILE__, __LINE__,
		       "    ports[%d] = %d", iTel, det->ports[iReg][iTel]);
	  }
	}
      }
      if (det->correlationFlag && (retVal == amdmsSUCCESS)) {
	retVal = amdmsReadElements(file,
				  TINT, det->correlationColNr, iReg + 1, 1L,
				  &(det->correlation[iReg]));
	if (retVal == amdmsSUCCESS) {
	  amdmsDebug(__FILE__, __LINE__,
		     "    correlation = %d", det->correlation[iReg]);
	}
      }
      if (det->regNameFlag && (retVal == amdmsSUCCESS)) {
	str = det->regName[iReg];
	retVal = amdmsReadElements(file,
				  TSTRING, det->regNameColNr, iReg + 1, 1L,
				  &str);
	if (retVal == amdmsSUCCESS) {
	  if ((det->regName[iReg][0] == '\0') || (det->regName[iReg][0] == ' ')) {
	    sprintf(det->regName[iReg], "DATA%ld", iReg + 1);
	  }
	  amdmsDebug(__FILE__, __LINE__,
		     "    regName = <%s>", det->regName[iReg]);
	}
      }
      if (det->cornerFlag && (retVal == amdmsSUCCESS)) {
	retVal = amdmsReadElements(file,
				  TINT, det->cornerColNr, iReg + 1, 2L,
				  &(det->corner[iReg]));
	if (retVal == amdmsSUCCESS) {
	  amdmsDebug(__FILE__, __LINE__,
		     "    corner = %d, %d",
		     det->corner[iReg][0], det->corner[iReg][1]);
	}
      }
      if (det->gainFlag && (retVal == amdmsSUCCESS)) {
	retVal = amdmsReadElements(file,
				  TDOUBLE, det->gainColNr, iReg + 1, 1L,
				  &(det->gain[iReg]));
	if (retVal == amdmsSUCCESS) {
	  amdmsDebug(__FILE__, __LINE__, "    gain = %f", det->gain[iReg]);
	}
      }
      if (det->nAxisFlag && (retVal == amdmsSUCCESS)) {
	retVal = amdmsReadElements(file,
				  TINT, det->nAxisColNr, iReg + 1, 2L,
				  &(det->nAxis[iReg]));
	if (retVal == amdmsSUCCESS) {
	  amdmsDebug(__FILE__, __LINE__,
		     "    nAxis = %d, %d", det->nAxis[iReg][0], det->nAxis[iReg][1]);
	}
      }
      if (det->CRValFlag && (retVal == amdmsSUCCESS)) {
	retVal = amdmsReadElements(file,
				  TDOUBLE, det->CRValColNr, iReg + 1, 2L,
				  &(det->CRVal[iReg]));
	if (retVal == amdmsSUCCESS) {
	  amdmsDebug(__FILE__, __LINE__,
		     "    CRVal = %f, %f", det->CRVal[iReg][0], det->CRVal[iReg][1]);
	}
      }
      if (det->CRPixFlag && (retVal == amdmsSUCCESS)) {
	retVal = amdmsReadElements(file,
				  TDOUBLE, det->CRPixColNr, iReg + 1, 2L,
				  &(det->CRPix[iReg]));
	if (retVal == amdmsSUCCESS) {
	  amdmsDebug(__FILE__, __LINE__,
		     "    CRPix = %f, %f", det->CRPix[iReg][0], det->CRPix[iReg][1]);
	}
      }
      if (det->cTypeFlag && (retVal == amdmsSUCCESS)) {
	str = det->cType[iReg];
	retVal = amdmsReadElements(file,
				  TSTRING, det->cTypeColNr, iReg + 1, 1L,
				  &str);
	if (retVal == amdmsSUCCESS) {
	  amdmsDebug(__FILE__, __LINE__, "    cType = %s", det->cType[iReg]);
	}
      }
      if (det->CDFlag && (retVal == amdmsSUCCESS)) {
	retVal = amdmsReadElements(file,
				  TDOUBLE, det->CDColNr, iReg + 1, 4L,
				  &(det->CD[iReg]));
	if (retVal == amdmsSUCCESS) {
	  amdmsDebug(__FILE__, __LINE__,
		     "    CD = %f, %f, %f, %f\n",
		     det->CD[iReg][0], det->CD[iReg][1], det->CD[iReg][2], det->CD[iReg][3]);
	}
      }
      if (det->DMPFlag && (retVal == amdmsSUCCESS)) {
	retVal = amdmsReadElements(file,
				  TINT, det->DMPColNr,
				  iReg + 1, (long)(det->numDim*det->numDim*det->maxCoef),
				  &(det->DMP[iReg]));
      }
      if (det->DMCFlag && (retVal == amdmsSUCCESS)) {
	retVal = amdmsReadElements(file,
				  TDOUBLE, det->DMCColNr,
				  iReg + 1, (long)(det->numDim*det->maxCoef),
				  &(det->DMC[iReg]));
      }
      if (retVal != amdmsSUCCESS) {
	return 0;
      }
      if (det->cornerFlag && det->nAxisFlag) {
	amdmsSetRegion(file, iCol, iRow,
		      det->corner[iReg][0], det->corner[iReg][1],
		      det->nAxis[iReg][0], det->nAxis[iReg][1]);
      }
    }
  }
  return amdmsSUCCESS;
}

amdmsCOMPL amdmsReadImagingDetectorFromHeader(amdmsFITS *file)
{
  int                    iRow;
  int                    iCol;
  int                    iReg;
  int                    i;
  amdmsBOOL               ok = amdmsTRUE;
  int                    nRow;
  int                    nTel;
  int                    colLeft0;
  int                    colLeft1;
  int                    colLeft2;
  int                    colLeft3;
  int                    colLeft4;
  int                    colWidth0;
  int                    colWidth1;
  int                    colWidth2;
  int                    colWidth3;
  int                    colWidth4;
  int                    rowTop0;
  int                    rowTop1;
  int                    rowTop2;
  int                    rowHeight0;
  int                    rowHeight1;
  int                    rowHeight2;
  long                   ports1[5] = {0, 1, 0, 1, 0};
  long                   ports2[5] = {0, 0, 2, 2, 0};
  long                   ports3[5] = {0, 0, 0, 3, 3};
  long                   corrs[5]  = {0, 1, 1, 2, 1};
  amdmsIMAGING_DETECTOR  *det;

  /* it is mandatory that the primary header unit exists */
  if (amdmsMoveToHDU(file, 1) != amdmsSUCCESS) {
    return amdmsFAILURE;
  }
  /* read all neccessary keywords from the primary header unit */
  ok = ok && amdmsReadKeywordInt(file, "HIERARCH ESO DET NROW", &nRow, NULL);
  ok = ok && amdmsReadKeywordInt(file, "HIERARCH ESO DET NTEL", &nTel, NULL);
  ok = ok && amdmsReadKeywordInt(file, "HIERARCH ESO DET WIN AMSC0", &colLeft0, NULL);
  ok = ok && amdmsReadKeywordInt(file, "HIERARCH ESO DET WIN AMSC1", &colLeft1, NULL);
  ok = ok && amdmsReadKeywordInt(file, "HIERARCH ESO DET WIN AMSC2", &colLeft2, NULL);
  ok = ok && amdmsReadKeywordInt(file, "HIERARCH ESO DET WIN AMSC3", &colLeft3, NULL);
  ok = ok && amdmsReadKeywordInt(file, "HIERARCH ESO DET WIN AMSC4", &colLeft4, NULL);
  ok = ok && amdmsReadKeywordInt(file, "HIERARCH ESO DET WIN AMNC0", &colWidth0, NULL);
  ok = ok && amdmsReadKeywordInt(file, "HIERARCH ESO DET WIN AMNC1", &colWidth1, NULL);
  ok = ok && amdmsReadKeywordInt(file, "HIERARCH ESO DET WIN AMNC2", &colWidth2, NULL);
  ok = ok && amdmsReadKeywordInt(file, "HIERARCH ESO DET WIN AMNC3", &colWidth3, NULL);
  ok = ok && amdmsReadKeywordInt(file, "HIERARCH ESO DET WIN AMNC4", &colWidth4, NULL);
  ok = ok && amdmsReadKeywordInt(file, "HIERARCH ESO DET WIN AMSR0", &rowTop0, NULL);
  ok = ok && amdmsReadKeywordInt(file, "HIERARCH ESO DET WIN AMSR1", &rowTop1, NULL);
  ok = ok && amdmsReadKeywordInt(file, "HIERARCH ESO DET WIN AMSR2", &rowTop2, NULL);
  ok = ok && amdmsReadKeywordInt(file, "HIERARCH ESO DET WIN AMNR0", &rowHeight0, NULL);
  ok = ok && amdmsReadKeywordInt(file, "HIERARCH ESO DET WIN AMNR1", &rowHeight1, NULL);
  ok = ok && amdmsReadKeywordInt(file, "HIERARCH ESO DET WIN AMNR2", &rowHeight2, NULL);
  if (!ok) {
    /* we need all keywords! */
    return amdmsFAILURE;
  }
  det = &(file->detector);
  /* initialize default values */
  det->nDetectFlag = amdmsTRUE;
  det->nDetect = 1; /* we have only one detector for AMBER */
  det->nRegionFlag = amdmsTRUE;
  file->nTel = nTel;
  file->nCols = 0;
  file->nRows = nRow;
  switch (nTel) {
  case 1:
    file->nCols = 1;
    amdmsSetCol(file, 0, colLeft0, colWidth0);
    break;
  case 2:
    file->nCols = 4;
    amdmsSetCol(file, 0, colLeft0, colWidth0);
    amdmsSetCol(file, 1, colLeft1, colWidth1);
    amdmsSetCol(file, 2, colLeft2, colWidth2);
    amdmsSetCol(file, 3, colLeft3, colWidth3);
    break;
  case 3:
    file->nCols = 5;
    amdmsSetCol(file, 0, colLeft0, colWidth0);
    amdmsSetCol(file, 1, colLeft1, colWidth1);
    amdmsSetCol(file, 2, colLeft2, colWidth2);
    amdmsSetCol(file, 3, colLeft3, colWidth3);
    amdmsSetCol(file, 4, colLeft4, colWidth4);
    break;
  default:
    file->nCols = 0;
  }
  if (nRow >= 1) {
    amdmsSetRow(file, 0, rowTop0, rowHeight0);
  }
  if (nRow >= 2) {
    amdmsSetRow(file, 1, rowTop1, rowHeight1);
  }
  if (nRow >= 3) {
    amdmsSetRow(file, 2, rowTop2, rowHeight2);
  }
  det->nRegion = file->nCols*file->nRows;
  det->maxCoefFlag = amdmsTRUE;
  det->maxCoef = 0;
  det->numDimFlag = amdmsTRUE;
  det->numDim = 2;
  det->maxTelFlag = amdmsTRUE;
  det->maxTel = 3;
  det->regionFlag = amdmsTRUE;
  det->detectorFlag = amdmsTRUE;
  det->portsFlag = amdmsTRUE;
  det->correlationFlag = amdmsTRUE;
  det->cornerFlag = amdmsTRUE;
  det->gainFlag = amdmsTRUE;
  det->nAxisFlag = amdmsTRUE;
  det->CRValFlag = amdmsTRUE;
  det->CRPixFlag = amdmsTRUE;
  det->cTypeFlag = amdmsTRUE;
  det->CDFlag = amdmsFALSE;
  det->DMPFlag = amdmsFALSE;
  det->DMCFlag = amdmsFALSE;
  for (iRow = 0; iRow < file->nRows; iRow++) {
    for (iCol = 0; iCol < file->nCols; iCol++) {
      iReg = iRow*file->nCols + iCol;
      det->region[iReg] = iReg + 1;
      det->detector[iReg] = 1;
      if (nTel == 1) {
	det->ports[iReg][0] = 1;
	det->ports[iReg][1] = 1;
	det->ports[iReg][2] = 1;
	det->correlation[iReg] = 1;
      } else {
	det->ports[iReg][0] = ports1[iCol];
	det->ports[iReg][1] = ports2[iCol];
	det->ports[iReg][2] = ports3[iCol];
	det->correlation[iReg] = corrs[iCol];
      }
      sprintf(det->regName[iReg], "%s%d", file->regionColName, iReg + 1);
      det->corner[iReg][0] = (short)(file->regions[iCol][iRow].x);
      det->corner[iReg][1] = (short)(file->regions[iCol][iRow].y);
      det->gain[iReg] = 4.2;
      det->nAxis[iReg][0] = (short)(file->regions[iCol][iRow].width);
      det->nAxis[iReg][1] = (short)(file->regions[iCol][iRow].height);
      det->CRVal[iReg][0] = 1.0;
      det->CRVal[iReg][1] = 1.0;
      det->CRPix[iReg][0] = 1.0;
      det->CRPix[iReg][1] = 1.0;
      strcpy(det->cType[iReg], "PIXEL");
      for (i = 0; i < 4; i++) {
	det->CD[iReg][i] = 0.0;
      }
      for (i = 0; i < 256; i++) {
	det->DMP[iReg][i] = 0.0;
	det->DMC[iReg][i] = 0.0;
      }
    }
  }
  return amdmsSUCCESS;
}

amdmsCOMPL amdmsCreateImagingDetectorTable(amdmsFITS *file)
{
  int   status = 0;
  int   iCol;
  int   iRow;
  long  iReg;
  long  ports1[5] = {0, 1, 0, 1, 0};
  long  ports2[5] = {0, 0, 2, 2, 0};
  long  ports3[5] = {0, 0, 0, 3, 3};
  long  corrs[5]  = {0, 1, 1, 2, 1};
  char  regName[32];
  amdmsIMAGING_DETECTOR  *det;

  if (file->currStateFile != amdmsFILE_CREATED_STATE) {
    /* amdmsVBF(amdmsVERBOSE_ERROR, (stderr, "ERROR: amdmsFITS::createRegionTable(), no open file!\n")); */
    return amdmsFAILURE;
  }
  det = &(file->detector);
  file->tableExt = amdmsIMAGING_DETECTOR_EXT;
  file->outNCols = 0;
  if (amdmsAddColumn(file, TSHORT,   1, "REGION",      -1, NULL) != amdmsSUCCESS) {
    return amdmsFAILURE;
  }
  if (amdmsAddColumn(file, TSHORT,   1, "DETECTOR",    -1, NULL) != amdmsSUCCESS) {
    return amdmsFAILURE;
  }
  if (amdmsAddColumn(file, TSHORT,   3, "PORTS",       -1, NULL) != amdmsSUCCESS) {
    return amdmsFAILURE;
  }
  if (amdmsAddColumn(file, TSHORT,   3, "CORRELATION", -1, NULL) != amdmsSUCCESS) {
    return amdmsFAILURE;
  }
  if (amdmsAddColumn(file, TSTRING, 16, "REGNAME",     -1, NULL) != amdmsSUCCESS) {
    return amdmsFAILURE;
  }
  if (amdmsAddColumn(file, TSHORT,   2, "CORNER",      -1, NULL) != amdmsSUCCESS) {
    return amdmsFAILURE;
  }
  if (amdmsAddColumn(file, TFLOAT,   1, "GAIN",        -1, "e-/ADU") != amdmsSUCCESS) {
    return amdmsFAILURE;
  }
  if (amdmsAddColumn(file, TSHORT,   2, "NAXES",       -1, NULL) != amdmsSUCCESS) {
    return amdmsFAILURE;
  }
  if (amdmsAddColumn(file, TDOUBLE,  2, "CRVAL",       -1, NULL) != amdmsSUCCESS) {
    return amdmsFAILURE;
  }
  if (amdmsAddColumn(file, TDOUBLE,  2, "CRVPIX",      -1, NULL) != amdmsSUCCESS) {
    return amdmsFAILURE;
  }
  if (amdmsAddColumn(file, TSTRING,  8, "CTYPE",       -1, NULL) != amdmsSUCCESS) {
    return amdmsFAILURE;
  }
  if (amdmsMoveToLastHDU(file) != amdmsSUCCESS) {
    return amdmsFAILURE;
  }
  if (fits_create_tbl(file->fits, BINARY_TBL, 0L, file->outNCols, file->outColType, file->outColForm, file->outColUnit, file->tableExt, &status) != 0 ) {
    amdmsReportFitsError(file, status, __LINE__, file->tableExt);
    return amdmsFAILURE;
  }
  if (amdmsMoveToLastHDU(file) != amdmsSUCCESS) {
    return amdmsFAILURE;
  }
  file->currStateHDU = amdmsTABLE_CREATED_STATE;
  amdmsUpdateKeywordLong(file, "REVISION",             1L, NULL);
  amdmsUpdateKeywordString(file, "ORIGIN",               "ESO-PARANAL", NULL);
  amdmsUpdateKeywordString(file, "INSTRUME",             "AMBER", NULL);
  /* amdmsUpdateKeyword(file, "MJD-OBS",              ExpStartTimeMJD(), NULL); */
  /* amdmsUpdateKeyword(file, "DATE-OBS",             ExpStartTime(), NULL); */
  /* icmdGetUTC(utc, 4); */
  /* amdmsUpdateKeyword(file, "DATE",                 utc, NULL); */
  /* amdmsUpdateKeyword(file, "HIERARCH ESO DET DID", dicID, NULL); */
  /* amdmsUpdateKeyword(file, "HIERARCH ESO DET ID",  dcsVersion, NULL); */
  amdmsUpdateKeywordLong(file, "NDETECT",              1L, NULL);
  amdmsUpdateKeywordLong(file, "NREGION",              (long)(file->nCols*file->nRows), NULL);
  amdmsUpdateKeywordLong(file, "MAX_COEF",             0L, NULL);
  amdmsUpdateKeywordLong(file, "NUM_DIM",              2L, NULL);
  amdmsUpdateKeywordLong(file, "MAXTEL",               3L, NULL);
  amdmsUpdateKeywords(file);
  for (iRow = 0; iRow < file->nRows; iRow++) {
    for (iCol = 0; iCol < file->nCols; iCol++) {
      iReg = (long)(iRow*file->nCols + iCol + 1);
      amdmsWriteElementLong(file, 1, iReg, iReg, 0L);
      amdmsWriteElementLong(file, 2, iReg, 1L, 0L);
      amdmsWriteElementLong(file, 3, iReg, ports1[iCol], 0L);
      amdmsWriteElementLong(file, 3, iReg, ports2[iCol], 1L);
      amdmsWriteElementLong(file, 3, iReg, ports3[iCol], 2L);
      amdmsWriteElementLong(file, 4, iReg, corrs[iCol], 0L);
      sprintf(regName, "%s%ld", file->regionColName, iReg);
      amdmsWriteElementString(file, 5, iReg, regName, 0L);
      amdmsWriteElementLong(file, 6, iReg, (long)file->regions[iCol][iRow].x, 0L);
      amdmsWriteElementLong(file, 6, iReg, (long)file->regions[iCol][iRow].y, 1L);
      amdmsWriteElementDouble(file, 7, iReg, 1.0, 0L);
      amdmsWriteElementLong(file, 8, iReg, (long)file->regions[iCol][iRow].width, 0L);
      amdmsWriteElementLong(file, 8, iReg, (long)file->regions[iCol][iRow].height, 1L);
      amdmsWriteElementDouble(file, 9, iReg, 1.0, 0L);
      amdmsWriteElementDouble(file, 9, iReg, 1.0, 1L);
      amdmsWriteElementDouble(file, 10, iReg, 1.0, 0L);
      amdmsWriteElementDouble(file, 10, iReg, 1.0, 1L);
      amdmsWriteElementString(file, 11, iReg, "PIXEL", 0L);
    }
  }
  return amdmsSUCCESS;
}

