#if !defined(PHASE2_H)
#define PHASE2_H

/** TO BE DEFINED:
 *  1. Is it the responsibility of the phase2Whatever function to get the appropriate metadata, or should
 *  it be supplied by the caller?
 *  2. We want to carry masks around with each image.  Should these be separate psImages, or should we
 *  incorporate the mask into the definition of psImage?
 *  3. In some cases, we don't yet know the best algorithm.  How do we make these APIs robust against
 *  variation of algorithms and input parameters?  For example, the number of parameters may vary.
 *
 *  Possible answers:
 *  1. It's the responsibility of the caller to supply all relevant information.  This means that the
 *  caller has to worry about getting the current best choice parameters, not the function itself; the
 *  function can just be dumb, and do what it's told.
 *  2. Masks will be provided as a member (psImage *mask) of psReadout.
 *  3. Provide an "int algorithmNumber" plus "void *parameters" which will point to a struct containing the
 *  parameters for the task.
 *
 */

/************************************************************************************************************/

/* Bias/overscan subtraction and trim */

/** Overscan axis */
typedef enum {
    PM_OVERSCAN_NONE,			///< No overscan subtraction
    PM_OVERSCAN_ROWS,			///< Subtract rows
    PM_OVERSCAN_COLUMNS, 		///< Subtract columns
    PM_OVERSCAN_ALL			///< Subtract the statistic of all pixels in overscan region
} pmOverscanAxis;

/** Fit types */
typedef enum {
    PM_FIT_NONE,			///< No fit
    PM_FIT_POLYNOMIAL,			///< Fit polynomial
    PM_FIT_SPLINE			///< Fit cubic splines
} pmFit;

/** Subtracts an overscan and bias from the input image. */
psReadout *pmSubtractBias(psReadout *in, ///< Input image to be de-biased, and output
			  void *fitSpec, ///< Polynomial/Spline/Some other function(?) specification,
			                 ///< Also outputted
			  const psList *overscans, ///< Linked list of subimages of overscans
			  pmOverscanAxis overscanAxis, ///< Overscan axis
			  const psStats *stat, ///< Statistic to use
			  int nBin, ///< Number of bins for overscan vector before fitting
			  pmFit fit, ///< How to fit the bias
			  const psReadout *bias ///< Bias (or dark) image to subtract
    );

/************************************************************************************************************/

/* Correction for non-linearity */

/** Non-linearity correction via polynomial */
psReadout *pmNonLinearityPolynomial(psReadout *in, ///< Input image to be corrected, and output
				    const psPolynomial1D *coeff ///< Polynomial with which to correct
    );

/** Non-linearity correction via lookup table */
psReadout *pmNonLinearityLookup(psReadout *in, ///< Input image to be corrected, and output
				const psVector *inFlux, ///< Input flux values
				const psVector *outFlux ///< Output flux values
    );

/************************************************************************************************************/

/** Flat-fields the image. */
psReadout *pmFlatField(psReadout *in, ///< Input image to be flat-fielded, and output
		       const psReadout *flat ///< Flat-field image
    );

/************************************************************************************************************/

/* Masking */

/** Mask values */
typedef enum {
    PM_MASK_TRAP       = 0x0001,	///< The pixel is a charge trap
    PM_MASK_BADCOL     = 0x0002,	///< The pixel is a bad column
    PM_MASK_SAT        = 0x0004,	///< The pixel is saturated
    PM_MASK_FLAT       = 0x0008,	///< The pixel is non-positive in the flat-field
    PM_MASK_CR_MORPH   = 0x000F,	///< The pixel is determined to be a cosmic ray, from morphology
} pmMaskValue;

/** Returns an image that has the bad pixels masked.  Also masks saturated pixels */
psReadout *pmMaskBadPixels(psReadout *in, ///< Image to be masked, and output
			   const psImage *mask, ///< Bad pixel mask to apply
			   unsigned int maskVal, ///< Mask the pixels for which mask & maskVal > 0.
			   float sat, ///< Saturation level: pixels brighter than this level are masked
			   unsigned int growVal, ///< Grow bad pixels for which mask & growVal > 0.
			   int grow ///< Radius to grow the bad pixels
    );

/************************************************************************************************************/
/************************************************************************************************************/
/************************************************************************************************************/

/* Below functions are still under development */

/************************************************************************************************************/
/************************************************************************************************************/
/************************************************************************************************************/

/* Reading in an image */

/** Generate an FPA structure on the basis of the configuration file */
psFPA *psFPAGenerate(FILE *config,	///< Configuration file, already open
		     const char *fpaName ///< FPA name to generate for
		     );

/** Read all pixel data into a generated FPA structure */
psFPA *psFPAReadAll(psFPA *in		///< FPA to read into, and output
		    );

/** Read only a particular chip */
psFPA *psFPAReadChip(psFPA *in,		///< FPA to read into, and output
		     const char *chipName ///< Chip name to read
		     );

/** Read only a particular cell into a chip that has been set up with psFPAGenerate */
psChip *psChipReadCell(psChip *in,	///< Chip to read into, and output
		       const char *cellName ///< Cell name to read
		       );

/** Read only a particular readout into a cell that has been set up with psFPAGenerate */
psCell *psCellReadReadout(psCell *in,	///< Cell to read into, and output
			  const char *readoutName ///< Readout name to read
			  );

/************************************************************************************************************/

/** Masks Cosmic Rays on the input image on the basis of morphology. */
psReadout *psPhase2MaskCRs(psReadout *in, ///< Input image to be masked, and output
			   int algorithm, ///< Algorithm number to use
			   const void *params ///< Parameters for algorithm
			   );

/** Masks optical defects in the input image */
psChip *psPhase2MaskOpticalDefects(psChip *in, ///< Image to be masked (with astrometry), and output
				   const psDlist *catalog, ///< Catalog stars nearby: a list of psObjects
				   int grow ///< Number of pixels to grow
				   );

/************************************************************************************************************/

/** Simple sky subtraction */
psReadout *psPhase2SubtractSky(psReadout *in, ///< Input image to be sky-subtracted, and output
			       void *fitSpec, ///< Polynomial/Spline specification, returns coeffcients
			       psFit fit, ///< Fit type
			       int binFactor, ///< Binning factor to use on image before solving for polynomial
			       psStats *stats, ///< Statistics to use in binning
			       float clipSD ///< Standard deviations to clip at after binning.
			       );

/************************************************************************************************************/

/* Object finding */

/** Measures the PSF on the input image.  Returns the PSF */
psImage *psPhase2MeasurePSF(const psReadout *in, ///< Input image for which to measure the PSF
			    int algorithm, ///< Algorithm number to use
			    const void *params ///< Parameters for algorithm
			    );

/** Find and measure objects on the input image.  Fills in the "objects" member of the psReadout. */
/** THIS NEEDS WORK. */
psReadout *psPhase2FindObjects(psReadout *in, ///< Input image on which to find objects, and output
			       const psImage *psf, ///< PSF to use to find objects
			       const psVector *levels ///< Threshold levels (std dev.s)
			       );

/************************************************************************************************************/

/* Astrometry */

/** Corrects astrometry on the input chip */
psChip *psPhase2Astrometry(psChip *in,	///< Input chip for which to do astrometry, and output
			   const psDlist *catalog, ///< Catalog stars on the chip: a list of psObjects
			   int nClips,	///< Number of clipping iterations
			   float clipLevel ///< Level at which to clip
			   );

/************************************************************************************************************/

/* Postage stamps */

/** Specification of a postage stamp: location on the sky */
typedef struct {
    psSphereCoord *center;		///< Centre of postage stamp
    psSphereCoord *size;		///< Size of postage stamp
} psPostageStampSpec;

/** Return postage stamps of a set of regions */
psImageArray *psPhase2PostageStamps(const psChip *in, ///< Chip from which to form postage stamps
				    const psDlist *regions ///< Regions to postage-stampise: a list of
				                           ///< psPostageStampSpec
				    );

/************************************************************************************************************/

#endif
