/** @file  pmObjects.h
 *
 *  This file will ...
 *
 *  @author GLG, MHPCC
 *
 *  @version $Revision: 1.15 $ $Name: not supported by cvs2svn $
 *  @date $Date: 2005-09-11 22:25:39 $
 *
 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
 *
 */

#if !defined(PM_OBJECTS_H)
#define PM_OBJECTS_H

#if HAVE_CONFIG_H
#include <config.h>
#endif

#include<stdio.h>
#include<math.h>
#include "pslib.h"

/** pmPeakType
 * 
 *  A peak pixel may have several features which may be determined when the
 *  peak is found or measured. These are specified by the pmPeakType enum.
 *  PM_PEAK_LONE represents a single pixel which is higher than its 8 immediate
 *  neighbors.  The PM_PEAK_EDGE represents a peak pixel which touching the image
 *  edge. The PM_PEAK_FLAT represents a peak pixel which has more than a specific
 *  number of neighbors at the same value, within some tolarence:
 * 
 */
typedef enum {
    PM_PEAK_LONE,                       ///< Isolated peak.
    PM_PEAK_EDGE,                       ///< Peak on edge.
    PM_PEAK_FLAT,                       ///< Peak has equal-value neighbors.
    PM_PEAK_UNDEF                       ///< Undefined.
} pmPeakType;

/** pmPeak data structure
 *  
 */
typedef struct
{
    int x;                              ///< X-coordinate of peak pixel.
    int y;                              ///< Y-coordinate of peak pixel.
    float counts;                       ///< Value of peak pixel (above sky?).
    pmPeakType class;                   ///< Description of peak.
}
pmPeak;

/** pmMoments data structure
 *  
 */
typedef struct
{
    float x;                            ///< X-coord of centroid.
    float y;                            ///< Y-coord of centroid.
    float Sx;                           ///< x-second moment.
    float Sy;                           ///< y-second moment.
    float Sxy;                          ///< xy cross moment.
    float Sum;                          ///< Pixel sum above sky (background).
    float Peak;                         ///< Peak counts above sky.
    float Sky;                          ///< Sky level (background).
    int nPixels;                        ///< Number of pixels used.
}
pmMoments;

/** pmModelType enumeration
 *  
 */
typedef enum {
    PS_MODEL_GAUSS,                     ///< Regular 2-D Gaussian
    PS_MODEL_PGAUSS,                    ///< Psuedo 2-D Gaussian
    PS_MODEL_TWIST_GAUSS,               ///< 2-D Twisted Gaussian
    PS_MODEL_WAUSS,                     ///< 2-D Waussian
    PS_MODEL_SERSIC,                    ///< Sersic
    PS_MODEL_SERSIC_CORE,               ///< Sersic Core
    PS_MODEL_UNDEFINED                  ///< Undefined
} pmModelType;

/** pmModel data structure
 *  
 */
// XXX: The SDRS has the "type" member of type psS32.
typedef struct
{
    pmModelType type;                   ///< Model to be used.
    psVector *params;                   ///< Paramater values.
    psVector *dparams;                  ///< Parameter errors.
    float chisq;                        ///< Fit chi-squared.
    int nDOF;                           ///< number of degrees of freedom
    int nIter;                          ///< number of iterations to reach min
}
pmModel;

/** pmSourceType enumeration
 *  
 *  
 *  
 */
typedef enum {
    PS_SOURCE_PSFSTAR,
    PS_SOURCE_GALAXY,
    PS_SOURCE_DEFECT,
    PS_SOURCE_SATURATED,
    PS_SOURCE_SATSTAR,
    PS_SOURCE_FAINTSTAR,
    PS_SOURCE_BRIGHTSTAR,
    PS_SOURCE_OTHER
} pmSourceType;

/** pmSource data structure
 *  
 *  This source has the capacity for several types of measurements. The
 *  simplest measurement of a source is the location and flux of the peak pixel
 *  associated with the source:
 *  
 */
typedef struct
{
    pmPeak *peak;                       ///< Description of peak pixel.
    psImage *pixels;                    ///< Rectangular region including object pixels.
    psImage *mask;                      ///< Mask which marks pixels associated with objects.
    pmMoments *moments;                 ///< Basic moments measure for the object.
    pmModel *modelPSF;                  ///< PSF model parameters and type
    pmModel *modelFLT;                  ///< FLT model parameters and type
    pmSourceType type;                  ///< Best identification of object.
}
pmSource;

/** pmPeak data structure
 *  
 *  
 *  
 */
typedef struct
{
    psS32 type;                         ///< PSF Model in use
    psArray *params;                    ///< Model parameters (psPolynomial2D)
    psF32 chisq;                        ///< PSF goodness statistic
    psS32 nPSFstars;                    ///< number of stars used to measure PSF
}
pmPSF;



pmPeak *pmPeakAlloc(
    int x,                              ///< Row-coordinate in image space
    int y,                              ///< Col-coordinate in image space
    float counts,                       ///< The value of the peak pixel
    pmPeakType class                    ///< The type of peak pixel
);

pmMoments *pmMomentsAlloc();
pmModel *pmModelAlloc(pmModelType type);
pmSource *pmSourceAlloc();

/******************************************************************************
pmFindVectorPeaks(vector, threshold): Find all local peaks in the given vector
above the given threshold.  Returns a vector of type PS_TYPE_U32 containing
the location (x value) of all peaks.
 *****************************************************************************/
psVector *pmFindVectorPeaks(
    const psVector *vector,             ///< The input vector (float)
    float threshold                     ///< Threshold above which to find a peak
);

/******************************************************************************
pmFindImagePeaks(image, threshold): Find all local peaks in the given psImage
above the given threshold.  Returns a psList containing the location (x/y
value) of all peaks.
 *****************************************************************************/
psArray *pmFindImagePeaks(
    const psImage *image,               ///< The input image where peaks will be found (float)
    float threshold                     ///< Threshold above which to find a peak
);

/******************************************************************************
psCullPeaks(peaks, maxValue, valid): eliminate peaks from the psList that have
a peak value above the given maximum, or fall outside the valid region.
 *****************************************************************************/
psList *pmCullPeaks(
    psList *peaks,                      ///< The psList of peaks to be culled
    float maxValue,                     ///< Cull peaks above this value
    const psRegion valid               ///< Cull peaks otside this psRegion
);

/******************************************************************************
pmSource *pmSourceLocalSky(image, peak, innerRadius, outerRadius):
 
 *****************************************************************************/
pmSource *pmSourceLocalSky(
    const psImage *image,               ///< The input image (float)
    const pmPeak *peak,                 ///< The peak for which the psSource struct is created.
    psStatsOptions statsOptions,        ///< The statistic used in calculating the background sky
    float innerRadius,                  ///< The inner radius of the suqare annulus for calculating sky
    float outerRadius                   ///< The outer radius of the suqare annulus for calculating sky
);

/******************************************************************************
 *****************************************************************************/
pmSource *pmSourceMoments(
    pmSource *source,                   ///< The input pmSource for which moments will be computed
    float radius                        ///< Use a circle of pixels around the peak
);

/******************************************************************************
pmSourceRoughClass(pmArray *source, psMetaDeta *metadata): make a guess at the
source classification.
 *****************************************************************************/
bool pmSourceRoughClass(
    psArray *source,                    ///< The input pmSource
    psMetadata *metadata                ///< Contains classification parameters
);
/******************************************************************************
pmSourceSetPixelCircle(source, image, radius)
 *****************************************************************************/
bool pmSourceSetPixelsCircle(
    pmSource *source,                   ///< The input pmSource
    const psImage *image,               ///< The input image (float)
    float radius                        ///< The radius of the circle
);

/******************************************************************************
 *****************************************************************************/
bool pmSourceModelGuess(
    pmSource *source,                   ///< The input pmSource
    const psImage *image,               ///< The input image (float)
    pmModelType model                   ///< The type of model to be created.
);

/******************************************************************************
 *****************************************************************************/
typedef enum {
    PS_CONTOUR_CRUDE,
} pmContourType;

psArray *pmSourceContour(
    pmSource *source,                   ///< The input pmSource
    const psImage *image,               ///< The input image (float) (this arg should be removed)
    float level,                        ///< The level of the contour
    pmContourType mode                  ///< Currently this must be PS_CONTOUR_CRUDE
);

/******************************************************************************
 *****************************************************************************/
bool pmSourceFitModel(
    pmSource *source,                   ///< The input pmSource
    const psImage *image                ///< The input image (float)
);

/******************************************************************************
 *****************************************************************************/
bool pmSourceAddModel(
    psImage *image,                     ///< The opuut image (float)
    pmSource *source,                   ///< The input pmSource
    bool center                         ///< A boolean flag that determines whether pixels are centered
);

/******************************************************************************
 *****************************************************************************/
bool pmSourceSubModel(
    psImage *image,                     ///< The output image (float)
    pmSource *source,                   ///< The input pmSource
    bool center                         ///< A boolean flag that determines whether pixels are centered
);

/******************************************************************************
XXX: Why only *x argument?
XXX EAM: psMinimizeLMChi2Func returns psF64, not float
 *****************************************************************************/
float pmMinLM_Gauss2D(
    psVector *deriv,                    ///< A possibly-NULL structure for the output derivatives
    const psVector *params,             ///< A psVector which holds the parameters of this function
    const psVector *x                   ///< A psVector which holds the row/col coordinate
);

/******************************************************************************
 *****************************************************************************/
float pmMinLM_PsuedoGauss2D(
    psVector *deriv,                    ///< A possibly-NULL structure for the output derivatives
    const psVector *params,             ///< A psVector which holds the parameters of this function
    const psVector *x                   ///< A psVector which holds the row/col coordinate
);

/******************************************************************************
 *****************************************************************************/
float pmMinLM_Wauss2D(
    psVector *deriv,                    ///< A possibly-NULL structure for the output derivatives
    const psVector *params,             ///< A psVector which holds the parameters of this function
    const psVector *x                   ///< A psVector which holds the row/col coordinate
);

/******************************************************************************
 *****************************************************************************/
float pmMinLM_TwistGauss2D(
    psVector *deriv,                    ///< A possibly-NULL structure for the output derivatives
    const psVector *params,             ///< A psVector which holds the parameters of this function
    const psVector *x                   ///< A psVector which holds the row/col coordinate
);

/******************************************************************************
 *****************************************************************************/
float pmMinLM_Sersic(
    psVector *deriv,                    ///< A possibly-NULL structure for the output derivatives
    const psVector *params,             ///< A psVector which holds the parameters of this function
    const psVector *x                   ///< A psVector which holds the row/col coordinate
);

/******************************************************************************
 *****************************************************************************/
float pmMinLM_SersicCore(
    psVector *deriv,                    ///< A possibly-NULL structure for the output derivatives
    const psVector *params,             ///< A psVector which holds the parameters of this function
    const psVector *x                   ///< A psVector which holds the row/col coordinate
);

/******************************************************************************
 *****************************************************************************/
float pmMinLM_PsuedoSersic(
    psVector *deriv,                    ///< A possibly-NULL structure for the output derivatives
    const psVector *params,             ///< A psVector which holds the parameters of this function
    const psVector *x                   ///< A psVector which holds the row/col coordinate
);


/**
 * 
 *  The object model functions are defined to allow for the flexible addition
 *  of new object models. Every object model, with parameters represented by
 *  pmModel, has an associated set of functions which provide necessary support
 *  operations. A set of abstract functions allow the programmer to select the
 *  approriate function or property for a specific named object model.
 * 
 */

/**
 * 
 *  This function is the model chi-square minimization function for this model.
 * 
 */
typedef psMinimizeLMChi2Func pmModelFunc;


/**
 * 
 * This function returns the integrated flux for the given model parameters.
 */
typedef psF64 (*pmModelFlux)(const psVector *params);


/**
 * 
 *  This function provides the model guess parameters based on the details of
 *   the given source.
 * 
 */
typedef bool (*pmModelGuessFunc)(pmModel *model, pmSource *source);


/**
 * 
 *  This function constructs the PSF model for the given source based on the
 *  supplied psf and the FLT model for the object.
 * 
 */
typedef bool (*pmModelFromPSFFunc)(pmModel *modelPSF, pmModel *modelFLT, pmPSF *psf);


/**
 * 
 *  This function returns the radius at which the given model and parameters
 *  achieves the given flux.
 * 
 */
typedef psF64 (*pmModelRadius)(const psVector *params, double flux);


/**
 * 
 *  Each of the function types above has a corresponding function which returns
 *  the function given the model type:
 * 
 */
pmModelFunc pmModelFunc_GetFunction (pmModelType type);
pmModelFlux pmModelFlux_GetFunction (pmModelType type);
pmModelGuessFunc pmModelGuessFunc_GetFunction (pmModelType type);
pmModelFromPSFFunc pmModelFromPSFFunc_GetFunction (pmModelType type);
pmModelRadius pmModelRadius_GetFunction (pmModelType type);
psS32 pmModelParameterCount(pmModelType type);
psS32 pmModelSetType(char *name);
char *pmModelGetType(pmModelType type);

#endif
