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

# include "ppImage.h"

// the top portion of this function is equivalent to psphotParseCamera,
// but different in a few important ways.  
// XXX move this section to ppImageParseCamera?
bool ppImagePhotom (pmConfig *config, pmFPAview *view) {

    bool status;
    pmCell *cell;
    pmReadout *readout;

    psphotModelGroupInit ();

    // select recipe options supplied on command line
    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);

    // find or define a pmFPAfile PSPHOT.INPUT
    pmFPAfile *input = psMetadataLookupPtr (&status, config->files, "PSPHOT.INPUT");
    if (!status) {
	// psphotReadout requires a pmFPAfile supplied with the name PSPHOT.INPUT
	// create a pmFPAfile which points to PPIMAGE.OUTPUT.CHIP (guaranteed to be mosaiced by chip)
	// mode is 'REFERENCE' to prevent double frees of the fpa
	pmFPAfile *output = psMetadataLookupPtr (&status, config->files, "PPIMAGE.OUTPUT.CHIP");
	input = pmFPAfileDefineInput (config, output->fpa, "PSPHOT.INPUT");
	input->mode = PM_FPA_MODE_REFERENCE;

	// we set the freeLevel to be FPA so this pmFPAfile may be used as input to psastro
	// XXX make this the resonsibility of a ppImageAstrom call?
	// XXX test for psastro requests?
	// XXX need to make this an INTERNAL file if output is not requested.
	bool saveOutput = psMetadataLookupBool (NULL, recipe, "SAVE.OUTPUT");
	if (saveOutput) {
	  pmFPAfile *outfile = pmFPAfileDefineOutput (config, input->fpa, "PSPHOT.OUTPUT");
	  outfile->freeLevel = PM_FPA_LEVEL_FPA;
	}
    }

    // if we have requested PSPHOT.SRC (externally supplied sources), attempt to resolve it 
    if (psMetadataLookupPtr(NULL, config->arguments, "PSPHOT.SRC")) { 
	pmFPAfileDefineFromArgs (&status, config, "PSPHOT.SRC", "PSPHOT.SRC");
	if (!status) {
	    psError(PSPHOT_ERR_CONFIG, false, "Failed to find/build PSPHOT.SRC");
	    return status;
	}
    }

    // NOTE the difference here from psphotParseCamera: the mask and weight
    // images are supplied by ppImage and need not / should not be loaded here.

    // optionally load the PSF Model and/or fixed stars
    pmFPAfileBindFromArgs (NULL, input, config, "PSPHOT.PSF", "PSPHOT.PSF");

    // set default recipe values here
    // XXX place this in a psphot library function?
    psMetadataAddStr (recipe, PS_LIST_TAIL, "FITMODE",         PS_META_NO_REPLACE, "default fitting mode", "NONE");
    psMetadataAddStr (recipe, PS_LIST_TAIL, "BREAK_POINT",     PS_META_NO_REPLACE, "default break point",  "NONE");
    psMetadataAddF32 (recipe, PS_LIST_TAIL, "ZERO_PT",         PS_META_NO_REPLACE, "default zero point",    25.00);
    psMetadataAddS32 (recipe, PS_LIST_TAIL, "BACKGROUND.XBIN", PS_META_NO_REPLACE, "default binning",          64);
    psMetadataAddS32 (recipe, PS_LIST_TAIL, "BACKGROUND.YBIN", PS_META_NO_REPLACE, "default binning",          64);

    // determine PHOTCODE from fpa & view, overwrite in recipe
    char *photcode = pmConceptsPhotcodeForView (config, input, view);
    if (photcode) {
	psMetadataAddStr (recipe, PS_LIST_TAIL, "PHOTCODE", PS_META_REPLACE, "photcode from FPA concepts", photcode);
	psFree (photcode);
    }

    // optionally save the residual image 
    if (psMetadataLookupBool(NULL, recipe, "SAVE.RESID")) {
	if (!pmFPAfileDefineOutput (config, input->fpa, "PSPHOT.RESID")) {
	    psError(PSPHOT_ERR_CONFIG, false, "Cannot find a rule for PSPHOT.BACKMDL");
	    return false;
	}
    }

    int DX = psMetadataLookupS32 (&status, recipe, "BACKGROUND.XBIN");
    int DY = psMetadataLookupS32 (&status, recipe, "BACKGROUND.YBIN");

    // these calls construct a new fpa for the I/O handle 

    // optionally save the background model (small FITS image)
    if (psMetadataLookupBool(NULL, recipe, "SAVE.BACKMDL")) {
	if (!pmFPAfileDefineFromFPA (config, input->fpa, DX, DY, "PSPHOT.BACKMDL")) {
	    psError(PSPHOT_ERR_CONFIG, false, "Cannot find a rule for PSPHOT.BACKMDL");
	    return false;
	}
    }
    // optionally save the full background image
    if (psMetadataLookupBool(NULL, recipe, "SAVE.BACKGND")) {
	if (!pmFPAfileDefineFromFPA (config, input->fpa,  1,  1, "PSPHOT.BACKGND")) {
	    psError(PSPHOT_ERR_CONFIG, false, "Cannot find a rule for PSPHOT.BACKGND");
	    return false;
	}
    }
    // optionally save the background-subtracted image
    if (psMetadataLookupBool(NULL, recipe, "SAVE.BACKSUB")) {
	if (!pmFPAfileDefineFromFPA (config, input->fpa,  1,  1, "PSPHOT.BACKSUB")) {
	    psError(PSPHOT_ERR_CONFIG, false, "Cannot find a rule for PSPHOT.");
	    return false;
	}
    }
    // optionally save the PSF Model
    if (psMetadataLookupBool(NULL, recipe, "SAVE.PSF")) {
	if (!pmFPAfileDefineOutput (config, input->fpa, "PSPHOT.PSF.SAVE")) {
	    psError(PSPHOT_ERR_CONFIG, false, "Cannot find a rule for PSPHOT.PSF.SAVE");
	    return false;
	}
    }

    // optionally save output plots
    if (psMetadataLookupBool(NULL, recipe, "SAVE.PLOTS")) {
	if (!pmFPAfileDefineOutput (config, input->fpa, "SOURCE.PLOT.MOMENTS")) {
	    psTrace ("psphot", 3, "Cannot find a rule for SOURCE.PLOT.MOMENTS");
	}
	if (!pmFPAfileDefineOutput (config, input->fpa, "SOURCE.PLOT.PSFMODEL")) {
	    psTrace ("psphot", 3, "Cannot find a rule for SOURCE.PLOT.PSFMODEL");
	}
    }

    // XXX not tested (or defined?)
    // pmFPAfileConstruct (config->files, format, config->camera, "PSPHOT.PSF_SAMPLE");

    // XXX probably need to deactivate all files and activate the psphot ones explicitly

    // In this section, we iterate over the cells and readout for this chip
    // and run the psphot analysis routine here
    // XXX worry about this not having unique PHOTCODES...
    // view->cell = -1;
    // iterate over the cells in the current chip
    while ((cell = pmFPAviewNextCell (view, input->fpa, 1)) != NULL) {
	psLogMsg ("ppImagePhotom", 4, "Cell %d: %x %x\n", view->cell, cell->file_exists, cell->process);
	if (! cell->process || ! cell->file_exists) { continue; }

	// process each of the readouts
	while ((readout = pmFPAviewNextReadout (view, input->fpa, 1)) != NULL) {
	    if (! readout->data_exists) { continue; }

	    // run the actual photometry analysis
	    psphotReadout (config, view);
	}
    }

    // the PSPHOT.INPUT file is a temporary file used to carry PPIMAGE.OUTPUT.CHIP to psphotReadout
    pmFPAfileActivate (config->files, false, "PSPHOT.INPUT");

    return true;
}
