#ifndef PPSTACK_H
#define PPSTACK_H

#define PPSTACK_RECIPE "PPSTACK"        // Name of the recipe
#define PPSTACK_INSPECT_PIXELS "PPSTACK.PIXELS" // Name of rejected pixels metadata items

#include <pslib.h>
#include <psmodules.h>

// Mask values for inputs
typedef enum {
    PPSTACK_MASK_CAL    = 0x01,         // Photometric calibration failed
    PPSTACK_MASK_MATCH  = 0x02,         // PSF-matching failed
    PPSTACK_MASK_CHI2   = 0x04,         // Chi^2 too deviant
    PPSTACK_MASK_REJECT = 0x08,         // Rejection failed
    PPSTACK_MASK_BAD    = 0x10,         // Bad image (too many pixels rejected)
    PPSTACK_MASK_ALL    = 0xff          // All errors
} ppStackMask;

// List of files
typedef enum {
    PPSTACK_FILES_PREPARE,              // Files for preparation
    PPSTACK_FILES_CONVOLVE,             // Files for convolution
    PPSTACK_FILES_COMBINE,              // Files for combination
    PPSTACK_FILES_PHOT                  // Files for photometry
} ppStackFileList;


// Setup command-line arguments
bool ppStackArgumentsSetup(int argc, char *argv[], // Command-line arguments
                           pmConfig *config  // Configuration
    );

// Parse command-line arguments
bool ppStackArgumentsParse(pmConfig *config  // Configuration
    );

// Parse cameras
bool ppStackCamera(pmConfig *config     // Configuration
    );

// Determine target PSF for input images
pmPSF *ppStackPSF(const pmConfig *config, // Configuration
                  int numCols, int numRows, // Size of image
                  const psArray *psfs,  // List of input PSFs
                  const psVector *inputMask // Mask for inputs
    );

// Re-do photometry on input sources
//
// Photometry for the sources is replaced by what is measured
bool ppStackInputPhotometry(const pmReadout *ro, // Readout
                            const psArray *sources, // Sources to photometer
                            const pmConfig *config // Configuration
    );

// Perform stacking on a readout
//
// Returns an array of pixels to inspect for each input image
psArray *ppStackReadoutInitial(const pmConfig *config,   // Configuration
                               pmReadout *outRO,   // Output readout
                               const psArray *readouts, // Input readouts
                               const psVector *mask, // Mask for input readouts
                               const psVector *weightings, // Weighting factors for each image
                               const psVector *addVariance // Additional variance for rejection
    );

// Thread entry point for ppStackReadoutInitial
bool ppStackReadoutInitialThread(psThreadJob *job // Job to process
    );

// Concatenate inspection lists for each input image
bool ppStackInspect(psThreadJob *job    // Job to process
    );

// Perform stacking on a readout
bool ppStackReadoutFinal(const pmConfig *config,   // Configuration
                         pmReadout *outRO,   // Output readout
                         const psArray *readouts, // Input readouts
                         const psVector *mask, // Mask for input readouts
                         const psArray *rejected, // Array with pixels rejected in each image
                         const psVector *weightings, // Weighting factors for each image
                         const psVector *addVariance // Additional variance for rejection
    );

// Thread entry point for ppStackReadoutFinal
bool ppStackReadoutFinalThread(psThreadJob *job // Job to process
    );

// Return software version
psString ppStackVersion(void);

/// Return software source
psString ppStackSource(void);

// Return long description of software version
psString ppStackVersionLong(void);

// Supplement header with software version
bool ppStackVersionHeader(psMetadata *header // Header to supplement
    );

/// Print version information
void ppStackVersionPrint(void);

/// Convolve image to match specified seeing
bool ppStackMatch(pmReadout *readout,   // Readout to be convolved; replaced with output
                  psArray **regions,    // Array of regions used in each PSF matching, returned
                  psArray **kernels,    // Array of kernels used in each PSF matching, returned
                  float *chi2,          // Chi^2 from the stamps
                  float *weighting,     // Stack weighting (1/noise^2)
                  psArray *sources,     // Array of sources
                  const pmPSF *psf,     // Target PSF
                  psRandom *rng,        // Random number generator
                  const pmConfig *config // Configuration
    );


/// Calculate transparency differences between images
///
/// Corrects the source PSF photometry to a common system.  Return the sum of the exposure times.
float ppStackSourcesTransparency(const psArray *sourceLists, // Sources for each input
                                 psVector *inputMask, // Indicates bad input
                                 const pmFPAview *view, // View to readout
                                 const pmConfig *config // Configuration
    );

/// Dump memory debugging information
void ppStackMemDump(
    const char *name                    ///< Stage name, for inclusion in the output file name
    );

/// Activate/deactivate a list of files
void ppStackFileActivation(
    pmConfig *config,                   // Configuration
    ppStackFileList list,               // Files to turn on/off
    bool state                          // Activation state
    );

// Activate/deactivate a single element for a list
void ppStackFileActivationSingle(
    pmConfig *config,                   // Configuration
    ppStackFileList list,               // Files to turn on/off
    bool state,                         // Activation state
    int num                             // Number of file in sequence
    );

/// Iterate down the hierarchy, loading files
///
/// We can get away with this simplistic treatment of the FPA hierarchy because we're working on skycells.
pmFPAview *ppStackFilesIterateDown(
    pmConfig *config                    // Configuration
    );

/// Iterate up the hierarchy, writing files
///
/// We can get away with this simplistic treatment of the FPA hierarchy because we're working on skycells.
bool ppStackFilesIterateUp(
    pmConfig *config                    // Configuration
    );

/// Write an image to a FITS file
bool ppStackWriteImage(
    const char *name,                   // Name of image
    psMetadata *header,                 // Header
    const psImage *image,               // Image
    pmConfig *config                    // Configuration
    );


#endif
