/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
*
* This file is part of SEP
*
* Copyright 1993-2011 Emmanuel Bertin -- IAP/CNRS/UPMC
* Copyright 2014 SEP developers
*
* SEP is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SEP is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with SEP.  If not, see <http://www.gnu.org/licenses/>.
*
*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/

#pragma once

namespace SEP
{

/* datatype codes */
#define SEP_TBYTE        11
/* 8-bit unsigned byte */
#define SEP_TINT         31
/* native int type */
#define SEP_TFLOAT       42
#define SEP_TDOUBLE      82

/* object & aperture flags */
#define SEP_OBJ_MERGED       0x0001  /* object is result of deblending */
#define SEP_OBJ_TRUNC        0x0002  /* object truncated at image boundary */
#define SEP_OBJ_DOVERFLOW    0x0004  /* not currently used, but could be */
#define SEP_OBJ_SINGU        0x0008  /* x,y fully correlated */
#define SEP_APER_TRUNC       0x0010
#define SEP_APER_HASMASKED   0x0020
#define SEP_APER_ALLMASKED   0x0040
#define SEP_APER_NONPOSITIVE 0x0080

/* noise_type values in sep_image */
#define SEP_NOISE_NONE   0
#define SEP_NOISE_STDDEV 1
#define SEP_NOISE_VAR    2

/* input flags for aperture photometry */
#define SEP_MASK_IGNORE      0x0004

/* threshold interpretation for sep_extract */
#define SEP_THRESH_REL 0  /* in units of standard deviations (sigma) */
#define SEP_THRESH_ABS 1  /* absolute data values */

/* filter types for sep_extract */
#define SEP_FILTER_CONV    0
#define SEP_FILTER_MATCHED 1

/* structs ------------------------------------------------------------------*/

/* sep_image
 *
 * Represents an image, including data, noise and mask arrays, and
 * gain.
 */
typedef struct
{
    void *data;        /* data array                */
    void *noise;       /* noise array (can be NULL) */
    void *mask;        /* mask array (can be NULL)  */
    void *segmap;      /* segmap array (can be NULL)  */
    int dtype;         /* element type of image     */
    int ndtype;        /* element type of noise     */
    int mdtype;        /* element type of mask      */
    int sdtype;        /* element type of segmap    */
    int raw_w;         /* data raw image width      */
    int raw_h;         /* data raw image height     */
    int w;             /* array sub width           */
    int h;             /* array sub height          */
    double noiseval;   /* scalar noise value; used only if noise == NULL */
    short noise_type;  /* interpretation of noise value                  */
    double gain;       /* (poisson counts / data unit)                   */
    double maskthresh; /* pixel considered masked if mask > maskthresh   */
} sep_image;

/* sep_bkg
 *
 * The result of sep_background() -- represents a smooth image background
 * and its noise with splines.
 */
typedef struct
{
    int w, h;          /* original image width, height */
    int bw, bh;        /* single tile width, height */
    int nx, ny;        /* number of tiles in x, y */
    int n;             /* nx*ny */
    float global;      /* global mean */
    float globalrms;   /* global sigma */
    float *back;       /* node data for interpolation */
    float *dback;
    float *sigma;
    float *dsigma;
} sep_bkg;

/* sep_catalog
 *
 * The result of sep_extract(). This is a struct of arrays. Each array has
 * one entry per detected object.
 */
typedef struct
{
    int    nobj;                 /* number of objects (length of all arrays) */
    float	 *thresh;              /* threshold (ADU)                          */
    int	 *npix;                 /* # pixels extracted (size of pix array)   */
    int    *tnpix;                /* # pixels above thresh (unconvolved)      */
    int	 *xmin, *xmax;
    int    *ymin, *ymax;
    double *x, *y;                 /* barycenter (first moments)               */
    double *x2, *y2, *xy;		 /* second moments                           */
    double *errx2, *erry2, *errxy;      /* second moment errors            */
    float	 *a, *b, *theta;    /* ellipse parameters                       */
    float	 *cxx, *cyy, *cxy;  /* ellipse parameters (alternative)         */
    float	 *cflux;                /* total flux of pixels (convolved im)      */
    float	 *flux;      		 /* total flux of pixels (unconvolved)       */
    float  *cpeak;                /* peak intensity (ADU) (convolved)         */
    float  *peak;                 /* peak intensity (ADU) (unconvolved)       */
    int    *xcpeak, *ycpeak;       /* x, y coords of peak (convolved) pixel    */
    int    *xpeak, *ypeak;         /* x, y coords of peak (unconvolved) pixel  */
    short	 *flag;                 /* extraction flags                         */
    int    **pix;             /* array giving indicies of object's pixels in   */
    /* image (linearly indexed). Length is `npix`.  */
    /* (pointer to within the `objectspix` buffer)  */
    int    *objectspix;      /* buffer holding pixel indicies for all objects */
} sep_catalog;


/*--------------------- global background estimation ------------------------*/

/* sep_background()
 *
 * Create representation of spatially varying image background and variance.
 *
 * Note that the returned pointer must eventually be freed by calling
 * `sep_bkg_free()`.
 *
 * In addition to the image mask (if present), pixels <= -1e30 and NaN
 * are ignored.
 *
 * Source Extractor defaults:
 *
 * - bw, bh = (64, 64)
 * - fw, fh = (3, 3)
 * - fthresh = 0.0
 */
int sep_background(sep_image *image,
                   int bw, int bh,   /* size of a single background tile */
                   int fw, int fh,   /* filter size in tiles             */
                   double fthresh,   /* filter threshold                 */
                   sep_bkg **bkg);   /* OUTPUT                           */


/* sep_bkg_global[rms]()
 *
 * Get the estimate of the global background "median" or standard deviation.
 */
float sep_bkg_global(sep_bkg *bkg);
float sep_bkg_globalrms(sep_bkg *bkg);


/* sep_bkg_pix()
 *
 * Return background at (x, y).
 * Unlike other routines, this uses simple linear interpolation.
 */
float sep_bkg_pix(sep_bkg *bkg, int x, int y);


/* sep_bkg_[sub,rms]line()
 *
 * Evaluate the background or RMS at line `y`.
 * Uses bicubic spline interpolation between background map verticies.
 * The second function subtracts the background from the input array.
 * Line must be an array with same width as original image.
 */
int sep_bkg_line(sep_bkg *bkg, int y, void *line, int dtype);
int sep_bkg_subline(sep_bkg *bkg, int y, void *line, int dtype);
int sep_bkg_rmsline(sep_bkg *bkg, int y, void *line, int dtype);


/* sep_bkg_[sub,rms]array()
 *
 * Evaluate the background or RMS for entire image.
 * Uses bicubic spline interpolation between background map verticies.
 * The second function subtracts the background from the input array.
 * `arr` must be an array of the same size as original image.
 */
int sep_bkg_array(sep_bkg *bkg, void *arr, int dtype);
int sep_bkg_subarray(sep_bkg *bkg, void *arr, int dtype);
int sep_bkg_rmsarray(sep_bkg *bkg, void *arr, int dtype);

/* sep_bkg_free()
 *
 * Free memory associated with bkg.
 */
void sep_bkg_free(sep_bkg *bkg);

/*-------------------------- aperture photometry ----------------------------*/


/* Sum array values within a circular aperture.
 *
 * Notes
 * -----
 * error : Can be a scalar (default), an array, or NULL
 *         If an array, set the flag SEP_ERROR_IS_ARRAY in `inflags`.
 *         Can represent 1-sigma std. deviation (default) or variance.
 *         If variance, set the flag SEP_ERROR_IS_VARIANCE in `inflags`.
 *
 * gain : If 0.0, poisson noise on sum is ignored when calculating error.
 *        Otherwise, (sum / gain) is added to the variance on sum.
 *
 * area : Total pixel area included in sum. Includes masked pixels that were
 *        corrected. The area can differ from the exact area of a circle due
 *        to inexact subpixel sampling and intersection with array boundaries.
 */
int sep_sum_circle(sep_image *image,
                   double x,          /* center of aperture in x */
                   double y,          /* center of aperture in y */
                   double r,          /* radius of aperture */
                   int id,            /* optional id to test against segmap array */
                   int subpix,        /* subpixel sampling */
                   short inflags,     /* input flags (see below) */
                   double *sum,       /* OUTPUT: sum */
                   double *sumerr,    /* OUTPUT: error on sum */
                   double *area,      /* OUTPUT: area included in sum */
                   short *flag);      /* OUTPUT: flags */


int sep_sum_circann(sep_image *image,
                    double x, double y, double rin, double rout,
                    int id, int subpix, short inflags,
                    double *sum, double *sumerr, double *area, short *flag);

int sep_sum_ellipse(sep_image *image,
                    double x, double y, double a, double b, double theta,
                    double r, int id, int subpix, short inflags,
                    double *sum, double *sumerr, double *area, short *flag);

int sep_sum_ellipann(sep_image *image,
                     double x, double y, double a, double b, double theta,
                     double rin, double rout, int id, int subpix, short inflags,
                     double *sum, double *sumerr, double *area, short *flag);

/* sep_sum_circann_multi()
 *
 * Sum an array of circular annuli more efficiently (but with no exact mode).
 *
 * Notable parameters:
 *
 * rmax:     Input radii are  [rmax/n, 2*rmax/n, 3*rmax/n, ..., rmax].
 * n:        Length of input and output arrays.
 * sum:      Preallocated array of length n holding sums in annuli. sum[0]
 *           corrresponds to r=[0, rmax/n], sum[n-1] to outermost annulus.
 * sumvar:   Preallocated array of length n holding variance on sums.
 * area:     Preallocated array of length n holding area summed in each annulus.
 * maskarea: Preallocated array of length n holding masked area in each
             annulus (if mask not NULL).
 * flag:     Output flag (non-array).
 */
int sep_sum_circann_multi(sep_image *im,
                          double x, double y, double rmax, int n, int id, int subpix,
                          short inflag,
                          double *sum, double *sumvar, double *area,
                          double *maskarea, short *flag);

/* sep_flux_radius()
 *
 * Calculate the radii enclosing the requested fraction of flux relative
 * to radius rmax.
 *
 * (see previous functions for most arguments)
 * rmax : maximum radius to analyze
 * fluxtot : scale requested flux fractions to this. (If NULL, flux within
             `rmax` is used.)
 * fluxfrac : array of requested fractions.
 * n : length of fluxfrac
 * r : (output) result array of length n.
 * flag : (output) scalar flag
 */
int sep_flux_radius(sep_image *im,
                    double x, double y, double rmax, int id, int subpix, short inflag,
                    double *fluxtot, double *fluxfrac, int n,
                    double *r, short *flag);

/* sep_kron_radius()
 *
 * Calculate Kron radius within an ellipse given by
 *
 *     cxx*(x'-x)^2 + cyy*(y'-y)^2 + cxy*(x'-x)*(y'-y) < r^2
 *
 * The Kron radius is sum(r_i * v_i) / sum(v_i) where v_i is the value of pixel
 * i and r_i is the "radius" of pixel i, as given by the left hand side of
 * the above equation.
 *
 * Flags that might be set:
 * SEP_APER_HASMASKED - at least one of the pixels in the ellipse is masked.
 * SEP_APER_ALLMASKED - All pixels in the ellipse are masked. kronrad = 0.
 * SEP_APER_NONPOSITIVE - There was a nonpositive numerator or deminator.
 *                        kronrad = 0.
 */
int sep_kron_radius(sep_image *im, double x, double y,
                    double cxx, double cyy, double cxy, double r, int id,
                    double *kronrad, short *flag);


/* sep_windowed()
 *
 * Calculate "windowed" position parameters via an iterative procedure.
 *
 * x, y       : initial center
 * sig        : sigma of Gaussian to use for weighting. The integration
 *              radius is 4 * sig.
 * subpix     : Subpixels to use in aperture-pixel overlap.
 *              SExtractor uses 11. 0 is supported for exact overlap.
 * xout, yout : output center.
 * niter      : number of iterations used.
 */
int sep_windowed(sep_image *im,
                 double x, double y, double sig, int subpix, short inflag,
                 double *xout, double *yout, int *niter, short *flag);


/* sep_set_ellipse()
 *
 * Set array elements within an ellipitcal aperture to a given value.
 *
 * Ellipse: cxx*(x'-x)^2 + cyy*(y'-y)^2 + cxy*(x'-x)*(y'-y) = r^2
 */
void sep_set_ellipse(unsigned char *arr, int w, int h,
                     double x, double y, double cxx, double cyy, double cxy,
                     double r, unsigned char val);


/* sep_ellipse_axes()
 * sep_ellipse_coeffs()
 *
 * Convert between coefficient representation of ellipse,
 * cxx*(x'-x)^2 + cyy*(y'-y)^2 + cxy*(x'-x)*(y'-y) = r^2,
 * and axis representation of an ellipse. The axis representation is
 * defined by:
 *
 * a = semimajor axis
 * b = semiminor axis
 * theta = angle in radians counter-clockwise from positive x axis
 */
int sep_ellipse_axes(double cxx, double cyy, double cxy,
                     double *a, double *b, double *theta);
void sep_ellipse_coeffs(double a, double b, double theta,
                        double *cxx, double *cyy, double *cxy);

/*----------------------- info & error messaging ----------------------------*/

/* sep_version_string : library version (e.g., "0.2.0") */
extern char *sep_version_string;

/* sep_get_errmsg()
 *
 * Return a short descriptive error message that corresponds to the input
 * error status value.  The message may be up to 60 characters long, plus
 * the terminating null character.
 */
void sep_get_errmsg(int status, char *errtext);


/* sep_get_errdetail()
 *
 * Return a longer error message with more specifics about the problem.
 * The message may be up to 512 characters.
 */
void sep_get_errdetail(char *errtext);

}
