#ifndef PM_SUBTRACTION_STAMPS_H
#define PM_SUBTRACTION_STAMPS_H

#include <pslib.h>

#include "pmSubtractionKernels.h"

/// Status of stamp
typedef enum {
    PM_SUBTRACTION_STAMP_INIT,          ///< Initial state
    PM_SUBTRACTION_STAMP_USED,          ///< Use this stamp
    PM_SUBTRACTION_STAMP_REJECTED,      ///< This stamp has been rejected
    PM_SUBTRACTION_STAMP_CALCULATE,     ///< Calculate matrix and vector values for this stamp
    PM_SUBTRACTION_STAMP_NONE           ///< No stamp in this region
} pmSubtractionStampStatus;

/// A stamp for image subtraction
typedef struct {
    float x, y;                         ///< Position
    float flux;                         ///< Flux
    float xNorm, yNorm;                 ///< Normalised position
    psKernel *reference;                ///< Reference image postage stamp
    psKernel *input;                    ///< Input image postage stamp
    psKernel *weight;                   ///< Weight image postage stamp
    psArray *convolutions;              ///< Convolutions of the reference for each kernel component
    psImage *matrix;                    ///< Associated matrix
    psVector *vector;                   ///< Assoicated vector
    pmSubtractionStampStatus status;    ///< Status ofstamp
} pmSubtractionStamp;

/// Find stamps on an image
psArray *pmSubtractionFindStamps(psArray *stamps, ///< Output stamps, or NULL
                                 const psImage *image, ///< Image for which to find stamps
                                 const psImage *mask, ///< Mask, or NULL
                                 const psRegion *region, ///< Region in which to search for stamps, or NULL
                                 float threshold, ///< Threshold for stamps in the image
                                 float spacing ///< Rough spacing for stamps
    );

/// Set stamps based on a list of x,y
psArray *pmSubtractionSetStamps(const psVector *x, ///< x coordinates for each stamp
                                const psVector *y, ///< y coordinates for each stamp
                                const psVector *flux, ///< Flux for each stamp, or NULL
                                const psImage *mask, ///< Mask, or NULL
                                const psRegion *region ///< Region in which to search for stamps, or NULL
    );

/// Extract stamps from the images
bool pmSubtractionExtractStamps(psArray *stamps, ///< Stamps
                                psImage *reference, ///< Reference image
                                psImage *input, ///< Input image (or NULL)
                                psImage *weight, ///< Weight (variance) map
                                int footprint, ///< Stamp footprint size
                                int kernelSize ///< Kernel half-size
    );

/// Generate target for stamps based on list
bool pmSubtractionGenerateStamps(psArray *stamps, ///< Stamps
                                 float fwhm, ///< FWHM for each stamp
                                 int footprint, ///< Stamp footprint size
                                 int size ///< Kernel half-size
    );

#endif
