#ifndef PM_SOURCE_MATCH_H
#define PM_SOURCE_MATCH_H

/// Matched sources
///
/// A match between sources on different images.  The index back to the image and source are provided.
/// The magnitudes are pulled out, for convenience.
typedef struct {
    int num;                            // Number of matches
    psVector *image;                    // Image index
    psVector *index;                    // Source index for image
    psVector *mag;                      // Magnitudes
    psVector *magErr;                   // Magnitude errors
    psVector *mask;                     // Mask for measurements
} pmSourceMatch;


// Assert that the source match and its components are non-NULL
#define PM_ASSERT_SOURCE_MATCH_NON_NULL(MATCH, RVAL) { \
    if (!MATCH) { \
        psError(PS_ERR_UNEXPECTED_NULL, true, "Source match %s is NULL.", #MATCH); \
        return RVAL; \
    } \
    PS_ASSERT_VECTOR_NON_NULL((MATCH)->image, RVAL); \
    PS_ASSERT_VECTOR_NON_NULL((MATCH)->index, RVAL); \
    PS_ASSERT_VECTOR_NON_NULL((MATCH)->mag, RVAL); \
    PS_ASSERT_VECTOR_NON_NULL((MATCH)->magErr, RVAL); \
    PS_ASSERT_VECTOR_SIZE((MATCH)->image, (MATCH)->num, RVAL); \
    PS_ASSERT_VECTOR_SIZE((MATCH)->index, (MATCH)->num, RVAL); \
    PS_ASSERT_VECTOR_SIZE((MATCH)->mag, (MATCH)->num, RVAL); \
    PS_ASSERT_VECTOR_SIZE((MATCH)->magErr, (MATCH)->num, RVAL); \
}

/// Allocator for pmSourceMatch
pmSourceMatch *pmSourceMatchAlloc(int num // Maximum number of images
                                  );

/// Add a source to a match
void pmSourceMatchAdd(pmSourceMatch *match, // Match data
                      float mag, float magErr, // Magnitude and error
                      int image, // Image index
                      int index // Source index
                      );



/// Match sources between different images
///
/// Returns an array of psSourceMatch
psArray *pmSourceMatchSources(const psArray *sourceArrays, // Array of arrays of sources on each image
                              float radius // Correlation radius
                              );

/// Perform relative photometry to calibrate images
psVector *pmSourceMatchRelphot(const psArray *matches, // Array of matches
                               const psVector *zp, // Zero points for each image (including airmass term)
                               int maxIter, // Maximum number of iterations
                               float tol, // Relative tolerance for convergence
                               float rejLimit, // Limit on rejection between iterations
                               int transIter, // Clipping iterations for transparency
                               float transClip, // Clipping level for transparency
                               float photoLevel, // Level at which we declare image is photometric
                               float starClip, // Clipping for stars
                               float sysErr // Systematic error in measurements
    );

#endif
