/** @file  pmAstrometry.h
*
*  @brief This file defines the basic types for astronomical coordinate
*  transformation
*
*  @ingroup AstroImage
*
*  @author GLG, MHPCC
*
*  @version $Revision: 1.1 $ $Name: not supported by cvs2svn $
*  @date $Date: 2005-09-28 20:43:52 $
*
*  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
/// @{

/** 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
    // FITS data
    psMetadata *header;                 ///< The FITS header, if it corresponds to this level
    psDB *db;                           ///< Database handle
}
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?
    // FITS data
    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
}
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 *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?
    // FITS data
    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
}
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
    // XXX: The following mask was removed from the pmReadout struct in recent SDRS
    // versions.  However, I'm keeping it here since al ot of modules still require
    // it.
    psImage *mask;                      ///< Mask of input image
    psMetadata *analysis;               ///< Readout-level analysis metadata
    psMetadata *concepts;               ///< Cache for PS Concepts
    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
);

/** 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);

/** 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
    psDB *db                            ///< Database handle
);


/** 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* psCoordCellToChip(
    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* psCoordChipToFPA(
    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* psCoordFPAToTP(
    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* psCoordTPToSky(
    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* psCoordCellToFPA(
    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* psCoordCellToSky(
    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* psCoordCellToSkyQuick(
    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* psCoordSkyToTP(
    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* psCoordTPToFPA(
    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* psCoordFPAToChip(
    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* psCoordChipToCell(
    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* psCoordSkyToCell(
    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* psCoordSkyToCellQuick(
    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
);


psMetadataItem *pmCellGetConcept(pmCell *cell, const char *concept);
psMetadataItem *pmChipGetConcept(pmChip *chip, const char *concept);
psMetadataItem *pmFPAGetConcept(pmFPA *fpa, const char *concept);

/**
 * 
 *  We next specify a series of specific functions for concept lookups. These
 *  will generally be what the user utilises, so the goal is to provide a simple
 *  interface providing a single type back, so the user doesnt have to go to the
 *  trouble of checking types, etc. These functions should employ the above three
 *  general lookup functions and deal with the result appropriately.
 *
 */
float pmFPAGetAirmass(pmFPA *fpa); // FPA.AIRMASS
psString pmFPAGetFilter(pmFPA *fpa); // FPA.FILTER
float pmFPAGetPosAngle(pmFPA *fpa); // FPA.POSANGLE
double pmFPAGetRA(pmFPA *fpa); // FPA.RA
double pmFPAGetDec(pmFPA *fpa); // FPA.DEC
psString pmFPAGetRADecSys(pmFPA *fpa); // FPA.RADECSYS
psString pmFPAGetName(pmFPA *fpa); // FPA.NAME
psString pmChipGetName(pmChip *chip); // CHIP.NAME
psString pmCellGetName(pmCell *cell); // CELL.NAME
psTime *pmCellGetTime(pmCell *cell); // CELL.TIME
psList *pmCellGetBiasSec(pmCell *cell); // CELL.BIASSEC
psRegion pmCellGetTrimSec(pmCell *cell); // CELL.TRIMSEC
float pmCellGetGain(pmCell *cell); // CELL.GAIN
float pmCellGetReadNoise(pmCell *cell); // CELL.READNOISE
float pmCellGetSaturation(pmCell *cell); // CELL.SATURATION
float pmCellGetBad(pmCell *cell); // CELL.BAD
psPixelCoord pmCellGetBin(pmCell *cell); // CELL.BIN
psPixelCoord pmCellGetParity(pmCell *cell); // CELL.PARITY
float pmReadoutGetExposure(pmReadout *readout); // READOUT.EXPOSURE
float pmReadoutGetDarkTime(pmReadout *readout); // READOUT.DARKTIME



#endif // #ifndef PS_ASTROMETRY_H
