#ifndef PS_VIDEOPHOT_H
#define PS_VIDEOPHOT_H

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <string.h>
#include <strings.h>  // for strcasecmp
#include <unistd.h>   // for unlink
#include "pslib.h"
#include "psmodules.h"
#include "psphot.h"
#include "psastro.h"
#include "ppStats.h"

#define RECIPE_NAME "PSVIDEOPHOT"           // Name of the recipe to use
#define TIMER_TOTAL   "PSVIDEOPHOT.TOTAL"   // Name of timer for total time
#define TIMER_DETREND "PSVIDEOPHOT.DETREND" // Name of timer for detrend time
#define TIMER_PHOT    "PSVIDEOPHOT.PHOT"    // Name of timer for photometry time

// Options for psvideophot processing
typedef struct {
    // actions which psvideophot should perform
    bool doMaskBuild;                   // Build internal mask
    bool doVarianceBuild;               // Build internal variance map
    bool doMaskBurntool;                // mask potential burntool trails
    bool doMaskSat;                     // mask saturated pixels
    bool doMaskLow;                     // mask low pixels
    bool doMask;                        // Mask bad pixels
    bool doNonLin;                      // Non-linearity correction
    bool doOverscan;                    // Overscan subtraction
    bool doNoiseMap;                    // Bias subtraction
    bool doBias;                        // Bias subtraction
    bool doDark;                        // Dark subtraction
    bool doRemnance;                    // Remnance masking
    bool doShutter;                     // Shutter correction
    bool doFlat;                        // Flat-field normalisation
    bool doPatternRow;                  // Row pattern correction
    bool doPatternCell;                 // Cell pattern correction
    bool doFringe;                      // Fringe subtraction
    bool doPhotom;                      // Source identification and photometry
    bool doBG;                          // Background subtraction
    bool doAstromChip;                  // per-chip Astrometry
    bool doAstromMosaic;                // full-mosaic Astrometry
    bool doStats;                       // call ppStats on the image
    bool checkCTE;                      // measure pixel-based variance
    bool applyParity;                   // Apply Cell parities

  bool doMaskStats;                      // Calculate mask statistics
  
    bool doCrosstalkMeasure;            // measure crosstalk signal
    bool doCrosstalkCorrect;            // apply crosstalk correction

    // output files requested
    bool BaseFITS;
    bool BaseMaskFITS;
    bool BaseVarianceFITS;

    bool ChipFITS;
    bool ChipMaskFITS;
    bool ChipVarianceFITS;

    bool FPA1FITS;
    bool FPA2FITS;
    bool Bin1FITS;
    bool Bin1JPEG;
    bool Bin2FITS;
    bool Bin2JPEG;

    // make values for abstract concepts of masking
    psImageMaskType maskValue;          // apply this bit-mask to choose masked bits
    psImageMaskType markValue;          // apply this bit-mask to choose masked bits
    psImageMaskType satMask;            // Mask value to give saturated pixels
    psImageMaskType lowMask;            // Mask value to give bad pixels
    psImageMaskType flatMask;           // Mask value to give bad flat pixels
    psImageMaskType darkMask;           // Mask value to give bad dark pixels
    psImageMaskType blankMask;          // Mask value to give blank pixels
    psImageMaskType burntoolMask;       // Suspect pixels that fall where a burntool trail is expected.
    // non-linear correction parameters
    psDataType nonLinearType;
    psMetadataItem *nonLinearData;
    void *nonLinearSource;

    // options for the analysis
    pmOverscanOptions *overscan;        // Overscan options
    int burntoolTrails;
    // binning parameters
    int xBin1;                          // x-binning, scale 1
    int yBin1;                          // y-binning, scale 1
    int xBin2;                          // x-binning, scale 2
    int yBin2;                          // y-binning, scale 2

    // parameters used by the fringe analysis
    float fringeRej;                    // Fringe rejection limit
    int fringeIter;                     // Fringe iterations
    float fringeKeep;                   // Fringe keep fraction

    // Pattern correction
    int patternRowOrder;                   // Polynomial order
    int patternRowIter;                    // Clipping iterations
    float patternRowRej;                   // Clipping threshold
    float patternRowThresh;                // Ignore threshold
    psStatsOptions patternRowMean;         // Statistic for mean
    psStatsOptions patternRowStdev;        // Statistic for stdev
    psStatsOptions patternCellBG;          // statistic for background
    psStatsOptions patternCellMean;        // Statistic for mean

    int remnanceSize;                   // Size for remnance detection
    float remnanceThresh;               // Threshold for remnance detection

    char *normClass;                    // class to use for per-class normalization

  psU16 maskstat_static;
  psU16 maskstat_dynamic;
  psU16 maskstat_magic;
  psU16 maskstat_advisory;
  
} psvideophotOptions;

// Cells to be used in the detrend
typedef struct {
    pmCell *input;                      // The input cell, to be operated upon
    pmCell *mask;                       // The bad pixel mask
    pmCell *bias;                       // The bias correction
    pmCell *dark;                       // The dark correction
    pmCell *flat;                       // The flat-field correction
} psvideophotDetrend;

psvideophotOptions *psvideophotOptionsAlloc(void);

// Determine the processing options
psvideophotOptions *psvideophotOptionsParse(pmConfig *config);

// Get the configuration
pmConfig *psvideophotArguments(int argc, char **argv);

// Determine what type of camera, and initialise
psvideophotOptions *psvideophotParseCamera(pmConfig *config);
bool psvideophotSetMaskBits (pmConfig *config, psvideophotOptions *options);

// apply the cell flips to the input data before analysis
bool psvideophotParityFlip (pmConfig *config, const psvideophotOptions *options, const pmFPAview *view, bool native);

// Loop over the input
bool psvideophotLoop(pmConfig *config, psvideophotOptions *options);

// free memory, check for leaks
void psvideophotCleanup (pmConfig *config, psvideophotOptions *options);

// perform the detrend analysis on the current readout
bool psvideophotDetrendReadout (pmConfig *config, psvideophotOptions *options, pmFPAview *view);

bool psvideophotDetrendBias(pmReadout *inputReadout, pmReadout *bias, pmReadout *dark, psvideophotOptions *options);

//bool psvideophotDetrendNonLinear(pmReadout *input, psvideophotOptions *options);
bool psvideophotDetrendNonLinear(pmReadout *input, pmFPAview *linearity, pmConfig *config);
bool psvideophotDetrendNonLinearLookup(pmReadout *input, psMetadataItem *dataItem);
bool psvideophotDetrendNonLinearPolynomial(pmReadout *input, psMetadataItem *dataItem);

bool psvideophotDetrendCell(psvideophotDetrend *detrend, psvideophotOptions *options, pmConfig *config);
bool psvideophotDetrendBias(pmReadout *inputReadout, pmReadout *bias, pmReadout *dark, psvideophotOptions *options);
pmReadout* psvideophotDetrendSelectFirst(pmCell *cell, char *name, bool doThis);

bool psvideophotDetrendFree(pmConfig *config, pmFPAview *view);
bool psvideophotFringeFree(pmConfig *config, pmFPAview *view);

bool psvideophotCheckCTE(pmConfig *config, psvideophotOptions *options, pmFPAview *view);

bool psvideophotBurntoolMask(pmConfig *config, psvideophotOptions *options, pmFPAview *view, pmReadout *mask);

bool psvideophotDetrendPatternApply(pmConfig *config, pmChip *chip, const pmFPAview *inputView, const psvideophotOptions *options);

// Record which detrend file was used for the detrending
bool psvideophotDetrendRecord(
    pmCell *cell,                       // Cell of interest
    const pmConfig *config,             // Configuration
    const psvideophotOptions *options,      // Processing options
    const pmFPAview *view               // View to cell
    );

bool psvideophotRebinChip (pmConfig *config, pmFPAview *view, psvideophotOptions *options, char *outName);

bool psvideophotPhotom(psMetadata *stats, pmConfig *config, pmFPAview *view);
bool psvideophotAstrom(pmConfig *config, psMetadata *stats);
bool psvideophotAddstar(pmConfig *config);

// Subtract background from the chip-mosaicked image
bool psvideophotSubtractBackground(
    pmConfig *config,                   // Configuration
    const pmFPAview *view,              // View to chip of interest
    const psvideophotOptions *options       // Processing options
    );

bool psvideophotMosaicChip (pmConfig *config, const psvideophotOptions *options, const pmFPAview *view,
                        const char *outFile, const char *inFile);
bool psvideophotMosaicFPA (pmConfig *config, const psvideophotOptions *options,
                       const char *outFile, const char *inFile);

bool psvideophotSetMaskBits (pmConfig *config, psvideophotOptions *options);

void psvideophotFileCheck (pmConfig *config);

// functions used by ppFocus
pmConfig *ppFocusArguments(int argc, char **argv);
psvideophotOptions *ppFocusParseCamera (pmConfig *config, int entry);
bool ppFocusGetFWHM (pmConfig *config, psVector *focus, psVector *fwhm);
bool ppFocusFitFWHM (pmConfig *config, psVector *focus, psVector *fwhm);

void ppFocusDropCamera (pmConfig *config);

bool psvideophotDefineFile (pmConfig *config, pmFPA *input, char *filerule, char *argname, pmFPAfileType fileType, pmDetrendType detrendType);

// write stats to output file
bool psvideophotStatsOutput(pmConfig *config, // Configuration
                        psMetadata *stats, // Statistics output
                        const psvideophotOptions *options // Options
    );


// measure the crosstalk signal
bool psvideophotMeasureCrosstalk(pmConfig *config, psvideophotOptions *options, pmFPAview *view);

// correct the crosstalk signal
bool psvideophotCorrectCrosstalk(pmConfig *config, psvideophotOptions *options, pmFPAview *view);

// Measure fringes
bool psvideophotDetrendFringeMeasure(pmReadout *readout, // Readout to measure
                                 pmCell *fringe, // Fringe cell (each readout is a different component)
                                 const bool isResidual,
                                 const psvideophotOptions *options // Options
    );

// Solve the fringe system
bool psvideophotDetrendFringeSolve(pmChip *scienceChip, // Chip with science
                               const pmChip *refChip, // Chip with reference fringes
                               const bool isResidual,
                               const psvideophotOptions *options // Options
    );

// Generate fringe frame
bool psvideophotDetrendFringeGenerate(pmCell *science, // Science cell
                                  pmCell *fringes, // Fringe cell, one readout per fringe component
                                  const psvideophotOptions *options // Options
    );


bool psvideophotDetrendFringeApply (pmConfig *config, // config
                                pmChip *chip, // science chip
                                const pmFPAview *inputView, // current view
                                const psvideophotOptions *options // options
    );

/// Return short version information
psString psvideophotVersion(void);

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

/// Return long version information
psString psvideophotVersionLong(void);

/// Populate the header with version information for all dependencies
bool psvideophotVersionHeader(psMetadata *metadata ///< Header to populate
    );

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


// calculate stats, including MD5
bool psvideophotPixelStats(pmConfig *config,// Configuration
                       psMetadata *stats, // Statistics output
                       const psvideophotOptions *options, // Options
                       const pmFPAview *inputView // View to data
    );

// Calculate Mask statistics
bool psvideophotMaskStats(pmConfig *config, pmFPAview *view, psMetadata *stats);

// calculate stats from headers and concepts
bool psvideophotMetadataStats(pmConfig *config, // Configuration
                          psMetadata *stats, // Statistics output
                          const psvideophotOptions *options // Options
    );

void psvideophotFileCheck(pmConfig *config);

/// Dump memory summary to text file
void psvideophotMemoryDump(const char *description);

#endif
