/** @file  psFits.h
 *
 *  @brief Contains Fits I/O routines
 *
 *  @ingroup FileIO
 *
 *  @author Robert DeSonia, MHPCC
 *
 *  @version $Revision: 1.21 $ $Name: not supported by cvs2svn $
 *  @date $Date: 2005-09-15 21:22:21 $
 *
 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
 */

#ifndef PS_FITS_H
#define PS_FITS_H

#include<fitsio.h>

#include "psType.h"
#include "psArray.h"
#include "psVector.h"
#include "psMetadata.h"
#include "psImage.h"

/// @addtogroup FileIO
/// @{

/** FITS HDU type.
 *
 *  Enumeration for FITS HDU type.
 *
 */
typedef enum {
    PS_FITS_TYPE_NONE = -1,            ///< Unknown HDU type
    PS_FITS_TYPE_IMAGE = IMAGE_HDU,    ///< Image HDU type
    PS_FITS_TYPE_BINARY_TABLE = BINARY_TBL, ///< Binary table HDU type
    PS_FITS_TYPE_ASCII_TABLE = ASCII_TBL,   ///< ASCII table HDU type
    PS_FITS_TYPE_ANY = ANY_HDU         ///< Any HDU type
} psFitsType;

/** FITS file object.
 *
 *  This object should be considered opaque to the user; no item in this
 *  struct should be accessed directly.
 *
 */
typedef struct
{
    fitsfile* fd;                      ///< the CFITSIO fits files handle.
    const char* filename;              ///< the filename of the fits file
    bool writable;                     ///< Is the file writable?
}
psFits;

/** Opens a FITS file and allocates the associated psFits object.
 *
 *  @return psFits*    new psFits object for the FITS files specified or
 *                     NULL if the open of the FITS file failed
 */
psFits* psFitsAlloc(
    const char* name                   ///< the FITS file name
);

/** Checks the type of a particular pointer.
 *
 *  Uses the appropriate deallocation function in psMemBlock to check the ptr datatype.
 *
 *  @return bool:       True if the pointer matches a psFits structure, false otherwise.
 */
bool psMemCheckFits(
    psPtr ptr                          ///< the pointer whose type to check
);


/** Moves the FITS HDU to the specified extension name.
 *
 *  @return psFitsType    The HDU type, or PS_FITS_TYPE_NONE if move failed.
 */
bool psFitsMoveExtName(
    const psFits* fits,                ///< the psFits object to move
    const char* extname                ///< the extension name
);

/** Moves the FITS HDU to the specified extension number
 *
 *  @return psFitsType    The HDU type, or PS_FITS_TYPE_NONE if move failed.
 */
bool psFitsMoveExtNum(
    const psFits* fits,                ///< the psFits object to move
    int extnum,                        ///< the extension number to move to (zero is primary HDU)
    bool relative                      ///< if true, extnum is a relative number to the current position
);

/** Get the current extension number, where 0 is the primary HDU.
 *
 *  @return int        Current HDU number of the psFits file or < 0 if an error
 *                     occurred.
 */
int psFitsGetExtNum(
    const psFits* fits                 ///< the psFits object
);

/** Get the current extension name.
 *
 *  @return int        Current HDU name of the psFits file or NULL if an
 *                     error occurred.
 */
psString psFitsGetExtName(
    const psFits* fits                 ///< the psFits object
);

/** Set the current extension's name
 *
 *  @return bool       TRUE if the extension was successfully set, otherwise FALSE.
 */
bool psFitsSetExtName(
    psFits* fits,                      ///< the psFits object
    const char* name                   ///< the extension name
);

/** Get the total number of HDUs in the FITS file.
 *
 *  @return int        The total number of HDUs in the FITS file or < 0 if an
 *                     error occurred.
 */
int psFitsGetSize(
    const psFits* fits                 ///< the psFits object
);

/** Get the extension type of the current HDU.
 *
 *  @return psFitsType The type of the current HDU.  If PS_FITS_TYPE_UNKNOWN,
 *                     the type could not be determined.
 */
psFitsType psFitsGetExtType(
    const psFits* fits                 ///< the psFits object
);

/** Reads the header of the current HDU.
 *
 *  @return psMetadata*   the header data
 */
psMetadata* psFitsReadHeader(
    psMetadata* out,
    ///< The psMetadata to add the header data.  If null, a new psMetadata is created.

    const psFits* fits                 ///< the psFits object
);

/** Reads the header of all HDUs.  The current HDU is not changed.
 *
 *  @return psMetadata*      the header data set as a number of metadata entries
 */
psMetadata* psFitsReadHeaderSet(
    psMetadata* out,
    ///< The psMetadata to add the header data via psMetadata items.  If null, a
    ///< new psMetadata is created.  The keys of the psMetadata are the extension names
    ///< of the cooresponding HDUs.

    const psFits* fits                       ///< the psFits object
);

/** Writes the values of the metadata to the current HDU header.
 *
 *  @return bool        if TRUE, the write was successful, otherwise FALSE.
 */
bool psFitsWriteHeader(
    const psMetadata* output,          ///< the psMetadata data in which to write
    psFits* fits                       ///< the psFits object
);

/** Reads an image, given the desired region and z-plane.
 *
 *  @return psImage*     the read image or NULL if there was an error.
 */
psImage* psFitsReadImage(
    psImage* out,                      ///< a psImage to recycle.
    const psFits* fits,                ///< the psFits object
    psRegion region,                   ///< the region in the FITS image to read
    int z                              ///< the z-plane in the FITS image cube to read
);

/** Writes an image, given the desired region and z-plane.
 *
 *  @return bool        TRUE is the write was successful, otherwise FALSE.
 */
bool psFitsWriteImage(
    psFits* fits,                      ///< the psFits object
    psMetadata* header,                ///< header items for the new HDU.  Can be NULL.
    const psImage* input,              ///< the image to output
    int depth                          ///< the number of z-planes of the FITS image data cube
);

/** Updates the FITS file image, given the desired region and z-plane.
 *
 *  @return bool        TRUE is the write was successful, otherwise FALSE.
 */
bool psFitsUpdateImage(
    psFits* fits,                      ///< the psFits object
    const psImage* input,              ///< the image to output
    psRegion region,                   ///< the region in the FITS image to write
    int z                              ///< the z-planes of the FITS image data cube to write
);

/** Reads a table row.  The current HDU type must be either
 *  PS_FITS_TYPE_BINARY_TABLE or PS_FITS_TYPE_ASCII_TABLE.
 *
 *  @return psMetadata*    The table row's data.  The keys are the column names.
 */
psMetadata* psFitsReadTableRow(
    const psFits* fits,                ///< the psFits object
    int row                            ///< row number to read
);

/** Reads a table column.  The current HDU type must be either
 *  PS_FITS_TYPE_BINARY_TABLE or PS_FITS_TYPE_ASCII_TABLE.
 *
 *  @return psArray*    Array of data items for the specified column or NULL
 *                      if an error occurred.
 */
psArray* psFitsReadTableColumn(
    const psFits* fits,                ///< the psFits object
    const char* colname                ///< the column name
);

/** Reads a table column of numbers.  The current HDU type must be either
 *  PS_FITS_TYPE_BINARY_TABLE or PS_FITS_TYPE_ASCII_TABLE.
 *
 *  @return psVector*    Vector of data for the specified column or NULL
 *                       if an error occurred.
 */
psVector* psFitsReadTableColumnNum(
    const psFits* fits,                ///< the psFits object
    const char* colname                ///< the column name
);


/** Reads a whole FITS table.  The current HDU type must be either
 *  PS_FITS_TYPE_BINARY_TABLE or PS_FITS_TYPE_ASCII_TABLE.
 *
 *  @return psArray*     Array of psMetadata items, which contains the output
 *                       data items of each row.
 *
 *  @see psFitsReadTableRow
 */
psArray* psFitsReadTable(
    psFits* fits                       ///< the psFits object
);

/** Writes a whole FITS table.  The current HDU type must be either
 *  PS_FITS_TYPE_BINARY_TABLE or PS_FITS_TYPE_ASCII_TABLE.
 *
 *  @return bool        TRUE if the write was successful, otherwise FALSE
 *
 *  @see psFitsReadTableRow
 */
bool psFitsWriteTable(
    psFits* fits,                      ///< the psFits object
    const psMetadata* header,          ///< header items for the new HDU.  Can be NULL.
    const psArray* table
    ///< Array of psMetadata items, which contains the output data items of each row.
);

/** Updates a FITS table.  The current HDU type must be either
 *  PS_FITS_TYPE_BINARY_TABLE or PS_FITS_TYPE_ASCII_TABLE.
 *
 *  @return bool        TRUE if the write was successful, otherwise FALSE
 *
 *  @see psFitsWriteTable
 */
bool psFitsUpdateTable(
    psFits* fits,                ///< the psFits object
    const psMetadata* data,
    ///< Array of psMetadata items, which contains the output data items of each row.
    int row                            ///< the row number to update.
);

/// @}

#endif // #ifndef PS_FITS_H
