/** @file  pmAstrometry.h
*
*  @brief This file defines the basic types for astronomical coordinate
*  transformation
*
*  @ingroup AstroImage
*
*  @author GLG, MHPCC
*
*  @version $Revision: 1.6 $ $Name: not supported by cvs2svn $
*  @date $Date: 2006-01-26 21:10:50 $
*
*  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
*/

#ifndef PS_ASTROMETRY_H
#define PS_ASTROMETRY_H
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include "pslib.h"
#include "psDB.h"

/// @addtogroup AstroImage
/// @{

// XXX: Is this correct?  Must determine what p_pmHDU is.
// XXX: Create the p_pmHDU alloc/free.
typedef struct
{
    const char *extname;                // Extension name, if it corresponds to this level
    psArray *pixels;                    // The pixel data, if it corresponds to this level
    psMetadata *header;                 // The FITS header, if it corresponds to this level
}
p_pmHDU;

p_pmHDU *pmHDUAlloc();
void *pmHDUFree(p_pmHDU *hdu);

/** Focal plane data structure
 * 
 *  A focal plane consists of one or more chips (according to the number of
 *  pieces of contiguous silicon). It contains metadata containers for the
 *  concepts and analysis, a link to the parent, and pointers to the FITS header,
 *  if that corresponds to this level (the FPA may be the PHU, but will not ever
 *  contain pixels). For astrometry, it contains a transformation from the focal
 *  plane to the tangent plane and the fixed pattern residuals. It is expected
 *  that the transformation will consist of two 4D polynomials (i.e. a function
 *  of two coordinates in position, the magnitude of the object, and the color of
 *  the object) in order to correct for optical distortions and the effects of
 *  the atmosphere; hence we think that it is prudent to include a reverse
 *  transformation which will be derived from numerically inverting the forward
 *  transformation.
 *  
 */
typedef struct
{
    // Astrometric transformations
    psPlaneDistort* fromTangentPlane;   ///< Transformation from tangent plane to focal plane
    psPlaneDistort* toTangentPlane;     ///< Transformation from focal plane to tangent plane
    psProjection *projection;           ///< Projection from tangent plane to sky
    // Information
    psMetadata *concepts;               ///< Cache for PS concepts
    psMetadata *analysis;               ///< FPA-level analysis metadata
    const psMetadata *camera;           ///< Camera configuration
    psArray *chips;                     ///< The chips
    p_pmHDU *hdu;                       ///< FITS data
    psMetadata *phu;                    ///< Primary Header
}
pmFPA;

/** Chip data structure
 *  
 *  A chip consists of one or more cells (according to the number of amplifiers
 *  on the device). The chip contains metadata containers for the concepts and
 *  analysis, a link to the parent, and pointers to the pointers to the various
 *  FITS data, if that corresponds to this level. For astrometry, in addition to
 *  the rough positioning information, it contains a coordinate transform from
 *  the chip to the focal plane. It is expected that this transform will consist
 *  of two second-order 2D polynomials; hence we think that it is prudent to
 *  include a reverse transformation which will be derived from numerically
 *  inverting the forward transformation. A boolean indicates whether the chip is
 *  of interest, allowing it to be excluded from analysis.
 *  
 */
typedef struct
{
    // Offset specifying position on focal plane
    int col0;                           ///< Offset from the left of FPA.
    int row0;                           ///< Offset from the bottom of FPA.
    // Astrometric transformations
    psPlaneTransform* toFPA;            ///< Transformation from chip to FPA coordinates
    psPlaneTransform* fromFPA;          ///< Transformation from FPA to chip coordinates
    // Information
    psMetadata *concepts;               ///< Cache for PS concepts
    psMetadata *analysis;               ///< Chip-level analysis metadata
    psArray *cells;                     ///< The cells (referred to by name)
    pmFPA *parent;                      ///< Parent FPA
    bool valid;                         ///< Do we bother about reading and working with this chip?
    p_pmHDU *hdu;                       ///< FITS data
}
pmChip;

/** Cell data structure
 *
 *  A cell consists of one or more readouts.  It also contains a pointer to the
 *  cell's metadata, and its parent chip.  On the astrometry side, it also
 *  contains coordinate transforms from the cell to chip, from the cell to
 *  focal-plane, as well as a "quick and dirty" tranform from the cell to
 *  sky coordinates.
 *
 */
typedef struct
{
    // Offset specifying position on chip
    int col0;                           ///< Offset from the left of chip.
    int row0;                           ///< Offset from the bottom of chip.
    // Astrometric transformations
    psPlaneTransform* toChip;           ///< Transformations from cell to chip coordinates
    psPlaneTransform* toFPA;            ///< Transformations from cell to FPA coordinates
    psPlaneTransform* toSky;            ///< Transformations from cell to sky coordinates
    // Information
    psMetadata *concepts;               ///< Cache for PS concepts
    psMetadata *camera;                 ///< Camera Info
    psMetadata *analysis;               ///< Cell-level analysis metadata
    psArray *readouts;                  ///< The readouts (referred to by number)
    pmChip *parent;                     ///< Parent chip
    bool valid;                         ///< Do we bother about reading and working with this cell?
    p_pmHDU *hdu;                       ///< FITS data
}
pmCell;

/** Readout data structure.
 *
 *  A readout is the result of a single read of a cell (or a portion thereof).
 *  It contains the offset from the lower-left corner of the chip, in the case
 *  that the CCD was windowed, as well as the binning factors and parity (if the
 *  binning value is negative, then the parity is reversed). It also contains the
 *  pixel data, metadata containers for the concepts and analysis, and a link to
 *  the parent.
 *
 */
typedef struct
{
    // Position on the cell
    int col0;                           ///< Offset from the left of chip.
    int row0;                           ///< Offset from the bottom of chip.
    int colBins;                        ///< Amount of binning in x-dimension
    int rowBins;                        ///< Amount of binning in y-dimension
    // Information
    psImage *image;                     ///< Imaging area of readout
    psImage *mask;                      ///< Mask of input image
    psImage *weight;                    ///< Weight of input image
    psList *bias;                       ///< List of bias section (sub-)images
    psMetadata *analysis;               ///< Readout-level analysis metadata
    pmCell *parent;                     ///< Parent cell
}
pmReadout;


/** Allocates a pmReadout
 *
 *  The constructor shall make an empty pmReadout. If the parent cell is not
 *  NULL, the parent link is made and the readout shall be placed in the
 *  parents array of readouts. The metadata containers shall be allocated. All
 *  other pointers in the structure shall be initialized to NULL.
 *
 *  @return pmReadout*    newly allocated pmReadout with all internal pointers set to NULL
 */
pmReadout *pmReadoutAlloc(
    pmCell *cell                        ///< Parent cell
);

/** Allocates a pmCell
 *
 *  The constructor shall make an empty pmCell. If the parent chip is not NULL,
 *  the parent link is made and the cell shall be placed in the parents array of
 *  cells. The readouts array shall be allocated with a zero size, and the
 *  metadata containers constructed. All other pointers in the structure shall be
 *  initialized to NULL.
 *
 *  @return pmCell*    newly allocated pmCell
 */
pmCell *pmCellAlloc(
    pmChip *chip,                        ///< Parent chip
    psMetadata *cameradata,
    psString name
);

/** Allocates a pmChip
 * 
 *  The constructor shall make an empty pmChip. If the parent fpa is not NULL,
 *  the parent link is made and the chip shall be placed in the parent's array
 *  of chips. The cells array shall be allocated with a zero size, and the
 *  metadata containers constructed. All other pointers in the structure shall be
 *  initialized to NULL.
 *
 *  @return pmChip*    newly allocated pmChip
 */
pmChip *pmChipAlloc(
    pmFPA *fpa,
    psString name

);

/** Allocates a pmFPA
 * 
 *  The constructor shall make an empty pmFPA. The chips array shall be
 *  allocated with a zero size, the camera and db pointers set to the values
 *  provided, and the concepts metadata constructed. All other pointers in the
 *  structure shall be initialized to NULL.
 * 
 */
pmFPA *pmFPAAlloc(
    const psMetadata *camera            ///< Camera configuration
);


/** Verify parent links.
 * 
 *  This function checks the validity of the parent links in the FPA hierarchy.
 *  If a parent link is not set (or not set correctly), it is corrected, and the
 *  function shall return false. If all the parent pointers were correct, the
 *  function shall return true.
 * 
 */
bool pmFPACheckParents(
    pmFPA *fpa
);



/** FUNC DESC
 * 
 * 
 * 
 * 
 */



/*****************************************************************************
    Old Stuff
 *****************************************************************************/



/** Find cooresponding cell for given FPA coordinate
 *
 *  @return pmCell*    the cell cooresponding to the coord in FPA
 */
pmCell* pmCellInFPA(
    const psPlane* coord,              ///< the coordinate in FPA plane
    const pmFPA* FPA                   ///< the FPA to search for the cell
);


/** Find cooresponding chip for given FPA coordinate
 *
 *  @return pmChip*    the chip cooresponding to coord
 */
pmChip* pmChipInFPA(
    const psPlane* coord,              ///< the coordinate in FPA plane
    const pmFPA* FPA                   ///< the FPA to search for the cell
);


/** Find cooresponding cell for given Chip coordinate
 *
 *  @return pmCell*    the cell cooresponding to coord
 */
pmCell* pmCellInChip(
    const psPlane* coord,              ///< the coordinate in Chip plane
    const pmChip* chip                 ///< the chip to search for the cell
);


/** Translate a cell coordinate into a chip coordinate
 *
 *  @return psPlane*    the resulting chip coordinate
 */
psPlane* pmCoordCellToChip(
    psPlane* out,                      ///< a plane struct to recycle. If NULL, a new struct is created
    const psPlane* in,                 ///< the coordinate within Cell
    const pmCell* cell                 ///< the Cell in interest
);


/** Translate a chip coordinate into a FPA coordinate
 *
 *  @return psPlane*    the resulting FPA coordinate
 */
psPlane* pmCoordChipToFPA(
    psPlane* out,                      ///< a plane struct to recycle. If NULL, a new struct is created
    const psPlane* in,                 ///< the coordinate within Chip
    const pmChip* chip                 ///< the chip in interest
);


/** Translate a FPA coordinate into a Tangent Plane coordinate
 *
 *  @return psPlane*    the resulting Tangent Plane coordinate
 */
psPlane* pmCoordFPAToTP(
    psPlane* out,                      ///< a plane struct to recycle. If NULL, a new struct is created
    const psPlane* in,                 ///< the coordinate within FPA
    double color,                      ///< Color of source
    double magnitude,                  ///< Magnitude of source
    const pmFPA* fpa                   ///< the FPA in interest
);


/** Translate a Tangent Plane coordinate into a Sky coordinate
 *
 *  @return psSphere*    the resulting Sky coordinate
 */
psSphere* pmCoordTPToSky(
    psSphere* out,                     ///< a sphere struct to recycle. If NULL, a new struct is created
    const psPlane* in,                ///< the coordinate within Tangent Plane
    const psProjection *projection
);

/** Translate a cell coordinate into a FPA coordinate
 *
 *  @return psPlane*    the resulting FPA coordinate
 */
psPlane* pmCoordCellToFPA(
    psPlane* out,                      ///< a plane struct to recycle. If NULL, a new struct is created
    const psPlane* in,                 ///< the coordinate within cell
    const pmCell* cell                 ///< the cell in interest
);


/** Translate a cell coordinate into a Sky coordinate
 *
 *  @return psSphere*    the resulting Sky coordinate
 */
psSphere* pmCoordCellToSky(
    psSphere* out,                     ///< a sphere struct to recycle. If NULL, a new struct is created
    const psPlane* in,                 ///< the coordinate within cell
    double color,                      ///< Color of source
    double magnitude,                  ///< Magnitude of source
    const pmCell* cell                 ///< the cell in interest
);


/** Translate a cell coordinate into a Sky coordinate using a 'quick and
 *  dirty' method
 *
 *  @return psSphere*    the resulting Sky coordinate
 */
psSphere* pmCoordCellToSkyQuick(
    psSphere* out,                     ///< a sphere struct to recycle. If NULL, a new struct is created
    const psPlane* in,                 ///< the coordinate within cell
    const pmCell* cell                 ///< the cell in interest
);


/** Translate a Sky coordinate into a Tangent Plane coordinate
 *
 *  @return psPlane*    the resulting Tangent Plane coordinate
 */
psPlane* pmCoordSkyToTP(
    psPlane* out,                      ///< a plane struct to recycle. If NULL, a new struct is created
    const psSphere* in,                ///< the sky coordinate
    const psProjection *projection
);

/** Translate a Tangent Plane coordinate into a FPA coordinate
 *
 *  @return psPlane*    the resulting FPA coordinate
 */
psPlane* pmCoordTPToFPA(
    psPlane* out,                      ///< a plane struct to recycle. If NULL, a new struct is created
    const psPlane* in,                 ///< the coordinate within tangent plane
    double color,                      ///< Color of source
    double magnitude,                  ///< Magnitude of source
    const pmFPA* fpa                   ///< the FPA of interest
);


/** Translate a FPA coordinate into a chip coordinate
 *
 *  @return psPlane*    the resulting chip coordinate
 */
psPlane* pmCoordFPAToChip(
    psPlane* out,                      ///< a plane struct to recycle. If NULL, a new struct is created
    const psPlane* in,                 ///< the FPA coordinate
    const pmChip* chip                 ///< the chip of interest
);


/** Translate a chip coordinate into a cell coordinate
 *
 *  @return psPlane*    the resulting cell coordinate
 */
psPlane* pmCoordChipToCell(
    psPlane* out,                      ///< a plane struct to recycle. If NULL, a new struct is created
    const psPlane* in,                 ///< the Chip coordinate
    const pmCell* cell                 ///< the cell of interest
);


/** Translate a sky coordinate into a cell coordinate
 *
 *  @return psPlane*    the resulting cell coordinate
 */
psPlane* pmCoordSkyToCell(
    psPlane* out,                      ///< a plane struct to recycle. If NULL, a new struct is created
    const psSphere* in,                ///< the Sky coordinate
    float color,                       ///< Color of source
    float magnitude,                   ///< Magnitude of source
    const pmCell* cell                 ///< the cell of interest
);


/** Translate a sky coordinate into a cell coordinate using a 'quick and
 *  dirty' method
 *
 *  @return psPlane*    the resulting cell coordinate
 */
psPlane* pmCoordSkyToCellQuick(
    psPlane* out,                      ///< a plane struct to recycle. If NULL, a new struct is created
    const psSphere* in,                ///< the Sky coordinate
    const pmCell* cell                 ///< the cell of interest
);

/**
 * 
 * pmFPASelectChip shall set valid to true for the specified chip number
 * (chipNum), and all other chips shall have valid set to false. In the event
 * that the specified chip number does not exist within the fpa, the function
 * shall return false.
 *  
 */
bool pmFPASelectChip(
    pmFPA *fpa,
    int chipNum
);


/**
 * 
 * pmFPAExcludeChip shall set valid to false only for the specified chip
 * number (chipNum). In the event that the specified chip number does not exist
 * within the fpa, the function shall generate a warning, and perform no action.
 * The function shall return the number of chips within the fpa that have valid
 * set to true.
 *  
 */
int pmFPAExcludeChip(
    pmFPA *fpa,
    int chipNum
);


/**
 * 
 * pmFPAConstruct shall construct a focal plane hierarchy from a camera
 * configuration. A db handle is also provided so that may be set in the pmFPA.
 * The resultant pmFPA and its lower-down components shall be ready for to read a
 * FITS file into it by setting the extname pointers at the appropriate levels to
 * the appropriate FITS extension name.
 *  
 */
pmFPA *pmFPAConstruct(
    const psMetadata *camera,
    psDB *db
);


#endif // #ifndef PS_ASTROMETRY_H

