/* @file  pmObjects.h
 * @brief Functions to define and manipulate object models
 *
 * @author GLG, MHPCC
 * @author EAM, IfA
 *
 * @version $Revision: 1.11 $ $Name: not supported by cvs2svn $
 * @date $Date: 2007-06-20 02:22:26 $
 *
 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii
 */

# ifndef PM_MODEL_H
# define PM_MODEL_H

/// @addtogroup Objects Object Detection / Analysis Functions
/// @{

// type of model carried by the pmModel structure
typedef int pmModelType;

typedef enum {
    PM_MODEL_STATUS_NONE         = 0x00, ///< model fit not yet attempted, no other info
    PM_MODEL_STATUS_FITTED       = 0x01, ///< model fit completed
    PM_MODEL_STATUS_NONCONVERGE  = 0x02, ///< model fit did not converge
    PM_MODEL_STATUS_OFFIMAGE     = 0x04, ///< model fit drove out of range
    PM_MODEL_STATUS_BADARGS      = 0x08, ///< model fit called with invalid args
    PM_MODEL_STATUS_LIMITS       = 0x10  ///< model parameters hit limits
} pmModelStatus;

typedef enum {
    PM_MODEL_OP_NONE    = 0x00,
    PM_MODEL_OP_FUNC    = 0x01,
    PM_MODEL_OP_RES0    = 0x02,
    PM_MODEL_OP_RES1    = 0x04,
    PM_MODEL_OP_FULL    = 0x07,
    PM_MODEL_OP_SKY     = 0x08,
    PM_MODEL_OP_CENTER  = 0x10,
    PM_MODEL_OP_NORM    = 0x20,
    PM_MODEL_OP_NOISE   = 0x40,
} pmModelOpMode;

/** pmModel data structure
 *
 * Every source may have two types of models: a PSF model and a EXT (extended-source)
 * model. The PSF model represents the best fit of the image PSF to the specific
 * object. In this case, the PSF-dependent parameters are specified for the
 * object by the PSF, not by the fit. The EXT model represents the best fit of
 * the given model to the object, with all shape parameters floating in the fit.
 *
 */
typedef struct
{
    pmModelType type;                   ///< Model to be used.
    psVector *params;                   ///< Paramater values.
    psVector *dparams;                  ///< Parameter errors.
    float chisq;                        ///< Fit chi-squared.
    float chisqNorm;                    ///< re-normalized fit chi-squared.
    int nDOF;                           ///< number of degrees of freedom
    int nIter;                          ///< number of iterations to reach min
    pmModelStatus flags;                ///< model status flags
    float radiusFit;                    ///< fit radius actually used
    pmResiduals *residuals;             ///< normalized PSF residuals
}
pmModel;

/* XXX we are currently saving the residuals with the pmModel.  It might be better to save this
 * in the pmSource.  we may want an API to Add/Sub a pmModel (analytical model only) or a
 * pmSource (analytical + residuals).
 */

/** Symbolic names for the elements of [d]params
 * Note: these are #defines not enums as a given element of [d]params
 * may/will correspond to different parameters in different contexts
 */
#define PM_PAR_SKY 0   ///< Sky
#define PM_PAR_I0 1   ///< Central intensity
#define PM_PAR_XPOS 2   ///< X centre of object
#define PM_PAR_YPOS 3   ///< Y centre of object
#define PM_PAR_SXX 4   ///< shape X^2 moment
#define PM_PAR_SYY 5   ///< shape Y^2 moment
#define PM_PAR_SXY 6   ///< shape XY moment
#define PM_PAR_7 7   ///< ??? Unknown parameter
#define PM_PAR_8 8   ///< ??? Unknown parameter

/** pmModelAlloc()
 *
 */
pmModel *pmModelAlloc(pmModelType type);

// copy model to a new structure
pmModel *pmModelCopy (pmModel *model);

psF32 pmModelEval(pmModel *model, psImage *image, psS32 col, psS32 row);

/** pmModelAdd()
 *
 * Add the given source model flux to/from the provided image. The boolean
 * option center selects if the source is re-centered to the image center or if
 * it is placed at its centroid location. The boolean option sky selects if the
 * background sky is applied (TRUE) or not. The pixel range in the target image
 * is at most the pixel range specified by the source.pixels image. The success
 * status is returned.
 *
 */
bool pmModelAdd(
    psImage *image,                     ///< The output image (float)
    psImage *mask,                      ///< The image pixel mask (valid == 0)
    pmModel *model,                     ///< The input pmModel
    pmModelOpMode mode,                 ///< mode to control how the model is added into the image
    psMaskType maskVal                  ///< Value to mask
);

/** pmModelSub()
 *
 * Subtract the given source model flux to/from the provided image. The
 * boolean option center selects if the source is re-centered to the image center
 * or if it is placed at its centroid location. The boolean option sky selects if
 * the background sky is applied (TRUE) or not. The pixel range in the target
 * image is at most the pixel range specified by the source.pixels image. The
 * success status is returned.
 *
 */
bool pmModelSub(
    psImage *image,                     ///< The output image (float)
    psImage *mask,                      ///< The image pixel mask (valid == 0)
    pmModel *model,                     ///< The input pmModel
    pmModelOpMode mode,                 ///< mode to control how the model is added into the image
    psMaskType maskVal                  ///< Value to mask
);

/** pmModelFitStatus()
 *
 * This function wraps the call to the model-specific function returned by
 * pmModelFitStatusFunc_GetFunction.  The model-specific function examines the
 * model parameters, parameter errors, Chisq, S/N, and other parameters available
 * from model to decide if the particular fit was successful or not.
 *
 * XXX: Must code this.
 *
 */
bool pmModelFitStatus(
    pmModel *model                      ///< Model to be used
);

/// @}
# endif /* PM_MODEL_H */
