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

#include "amdmsFits.h"

amdmsCOMPL amdmsCreateImageCube(amdmsFITS *file, char *extName, int imageType, int nImages, int nReads)
{
  int       status = 0;
  long      naxes[3];

  amdmsDebug(__FILE__, __LINE__,
	    "amdmsCreateImageCube(%s, %s, %d, %d, %d)",
	    file->fileName, extName, imageType, nImages, nReads);
  if (file->currStateFile != amdmsFILE_CREATED_STATE) {
    /* amdmsVBF(amdmsVERBOSE_ERROR, (stderr, "ERROR: amdmsFITS::CreateImageCube(%s, ..), no open file!\n", extName)); */
    return amdmsFAILURE;
  }
  file->nImages = nImages;
  file->nReads = nReads;
  naxes[0] = file->nx;
  naxes[1] = file->ny;
  naxes[2] = nImages*nReads;
  if ((file->nx == 0) || (file->ny == 0) || (nImages == 0)) {
    /* dummy image */
    file->nAxis = 0;
    if (fits_create_img(file->fits, imageType, 0, naxes, &status)) {
      amdmsReportFitsError(file, status, __LINE__, NULL);
      return amdmsFAILURE;
    }
  } else if (naxes[2] == 1) {
    /* no cube, only one image! */
    file->nAxis = 2;
    if (fits_create_img(file->fits, imageType, 2, naxes, &status)) {
      amdmsReportFitsError(file, status, __LINE__, NULL);
      return amdmsFAILURE;
    }
  } else {
    /* cube, several images! */
    file->nAxis = 3;
    if (fits_create_img(file->fits, imageType, 3, naxes, &status)) {
      amdmsReportFitsError(file, status, __LINE__, NULL);
      return amdmsFAILURE;
    }
  }
  file->currStateHDU = amdmsCUBE_CREATED_STATE;
  if (file->hdrTable != NULL) {
    amdmsCopyHeader(file, file->hdrTable);
  }
  return amdmsUpdateKeywords(file);
}

amdmsCOMPL amdmsCreateEmptyImageCube(amdmsFITS *file)
{
  int       status = 0;
  long      naxes[3] = {0, 0, 0};

  /* amdmsVB(amdmsVERBOSE_DEBUG_CALL, ("amdmsFITS::CreateImageCube(%s, %d, %d, %d)\n", extName, imageType, nImages, nReads)); */
  if (file->currStateFile != amdmsFILE_CREATED_STATE) {
    /* amdmsVBF(amdmsVERBOSE_ERROR, (stderr, "ERROR: amdmsFITS::CreateImageCube(%s, ..), no open file!\n", extName)); */
    return amdmsFAILURE;
  }
  if (fits_create_img(file->fits, SHORT_IMG, 0, naxes, &status)) {
    amdmsReportFitsError(file, status, __LINE__, NULL);
    return amdmsFAILURE;
  }
  file->currStateHDU = amdmsCUBE_CREATED_STATE;
  if (file->hdrTable != NULL) {
    amdmsCopyHeader(file, file->hdrTable);
  }
  return amdmsUpdateKeywords(file);
}

amdmsCOMPL amdmsOpenImageCube(amdmsFITS *file, char *extName, int nReads)
{
  int       status = 0;
  long      axis[3];

  amdmsDebug(__FILE__, __LINE__,
	    "amdmsOpenImageCube(%s, %s, %d)", file->fileName, extName, nReads);
  if (file->currStateFile != amdmsFILE_OPENED_STATE) {
    amdmsError(__FILE__, __LINE__,
	      "amdmsOpenImageCube(%s, %s, %d), no open file!", file->fileName, extName, nReads);
    return amdmsFAILURE;
  }
  file->tableExt = extName;
  file->nReads = nReads;
  /* currently no named image header unit is supported!
  if (amdmsMoveToExtension(file, extName, IMAGE_HDU, amdmsFALSE) != amdmsSUCCESS) {
    return amdmsFAILURE;
  }
  */
  /* it is mandatory that the primary header unit exists */
  if (amdmsMoveToHDU(file, 1) != amdmsSUCCESS) {
    return amdmsFAILURE;
  }
  if (fits_get_img_param(file->fits, 3, &(file->bitpix), &(file->nAxis), axis, &status)) {
    amdmsReportFitsError(file, status, __LINE__, NULL);
    return amdmsFAILURE;
  }
  if (file->nAxis == 0) {
    amdmsError(__FILE__, __LINE__,
	      "amdmsOpenImageCube(%s, %s, %d), no images in extension!",
	      file->fileName, extName, nReads);
    return amdmsFAILURE;
  }
  switch (file->nAxis) {
  case 2:
    file->nx = axis[0];
    file->ny = axis[1];
    file->nImages = 1;
    file->nCols = 1;
    file->nRows = 1;
    amdmsSetRegion(file, 0, 0, 0, 0, file->nx, file->ny);
    break;
  case 3:
    file->nx = axis[0];
    file->ny = axis[1];
    file->nImages = axis[2];
    if (axis[2] == 1) {
      file->nAxis = 2;
    }
    file->nCols = 1;
    file->nRows = 1;
    amdmsSetRegion(file, 0, 0, 0, 0, file->nx, file->ny);
    break;
  default:
    amdmsError(__FILE__, __LINE__,
	      "amdmsOpenImageCube(%s, %s, %d), wrong dimension: %d!",
	      file->fileName, extName, nReads, file->nAxis);
    file->nCols = 0;
    file->nRows = 0;
    return 0;
  }
  file->currStateHDU = amdmsCUBE_OPENED_STATE;
  return amdmsSUCCESS;
}

amdmsCOMPL amdmsReadImage(amdmsFITS *file, amdmsDATA *data, int iImage, int iRead)
{
  int     status = 0;
  long    imgOffset = 1 + (iImage*file->nReads + iRead)*file->nPixels;

  amdmsDebug(__FILE__, __LINE__, "amdmsReadImage(%s, .., %d, %d)", file->fileName, iImage, iRead);
  amdmsDebug(__FILE__, __LINE__,
	    "  nx = %d, ny = %d, nImages = %d, nReads = %d => imgOffset = %d",
	    file->nx, file->ny, file->nImages, file->nReads, imgOffset);
  if (file->currStateHDU != amdmsCUBE_OPENED_STATE) {
    /* amdmsVBF(amdmsVERBOSE_ERROR, (stderr, "ERROR: amdmsFITS::ReadImage(, %d, %d), no open cube!\n", iImage, iRead)); */
    return amdmsFAILURE;
  }
  if (amdmsAllocateData(data, file->nx, file->ny) != amdmsSUCCESS) {
    return amdmsFAILURE;
  }
  data->index = iImage*file->nReads + iRead;
  if (fits_read_img(file->fits, TFLOAT, imgOffset, file->nPixels, NULL, data->data, NULL, &status)) {
    amdmsReportFitsError(file, status, __LINE__, NULL);
    return amdmsFAILURE;
  }
  return amdmsSUCCESS;
}

amdmsCOMPL amdmsWriteImage(amdmsFITS *file, amdmsDATA *data, int iImage, int iRead)
{
  int     status = 0;
  long    imgOffset = 1 + (iImage*file->nReads + iRead)*file->nPixels;

  amdmsDebug(__FILE__, __LINE__,
	    "amdmsWriteImage(%s, .., %d, %d), imgOffset = %ld",
	    file->fileName, iImage, iRead,
	    imgOffset);
  /* amdmsVB(amdmsVERBOSE_DEBUG_CALL, ("amdmsFITS::WriteImage(, %d, %d)\n", iImage, iRead)); */
  if (file->currStateHDU != amdmsCUBE_CREATED_STATE) {
    /* amdmsVBF(amdmsVERBOSE_ERROR, (stderr, "ERROR: amdmsFITS::WriteImage(, %d, %d), no open cube!\n", iImage, iRead)); */
    return amdmsFAILURE;
  }
  if (fits_write_img(file->fits, TFLOAT, imgOffset, (long)(file->nPixels), data->data, &status)) {
    amdmsReportFitsError(file, status, __LINE__, NULL);
    return amdmsFAILURE;
  }
  return amdmsSUCCESS;
}

