# include "psphotInternal.h"

bool psphotSetMaskAndVariance (pmConfig *config, const pmFPAview *view) {

    bool status = false;

    // select the appropriate recipe information
    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
    psAssert (recipe, "missing recipe?");

    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");

    // loop over the available readouts
    for (int i = 0; i < num; i++) {

	// Generate the mask and weight images, including the user-defined analysis region of interest
	if (!psphotSetMaskAndVarianceReadout (config, view, "PSPHOT.INPUT", i, recipe)) {
            psError (PSPHOT_ERR_CONFIG, false, "failed to generate mask for PSPHOT.INPUT entry %d", i);
	    return false;
	}
    }
    return true;
}

// generate mask and variance if not defined, additional mask for restricted subregion
bool psphotSetMaskAndVarianceReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe) {

    bool status;

    pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PSPHOT.INPUT", index); // File of interest
    psAssert (file, "missing file?");

    // find the currently selected readout
    pmReadout  *readout = pmFPAviewThisReadout (view, file->fpa);
    psAssert (readout, "missing readout?");

    // save maskSat and maskBad on the psphot recipe (mostly for psphotRoughClass)
    psImageMaskType maskSat  = pmConfigMaskGet("SAT", config); // Mask value for saturated pixels
    psMetadataAddImageMask (recipe, PS_LIST_TAIL, "MASK.SAT", PS_META_REPLACE, "user-defined mask", maskSat);

    psImageMaskType maskBad  = pmConfigMaskGet("LOW", config); // Mask value for low pixels
    if (!maskBad) {
        // for backward compatability look up old name
        maskBad  = pmConfigMaskGet("BAD", config);
    }
    psMetadataAddImageMask (recipe, PS_LIST_TAIL, "MASK.BAD", PS_META_REPLACE, "user-defined mask", maskBad);

    // generate mask & variance images if they don't already exit
    if (!readout->mask) {
        if (!pmReadoutGenerateMask(readout, maskSat, maskBad)) {
            psError (PSPHOT_ERR_CONFIG, false, "trouble creating mask");
            return false;
        }
    }
    if (!readout->variance) {
        if (!pmReadoutGenerateVariance(readout, NULL, true)) {
            psError (PSPHOT_ERR_CONFIG, false, "trouble creating variance");
            return false;
        }
    }

    bool softenVariance = psMetadataLookupBool (&status, recipe, "SOFTEN.VARIANCE");
    float softenFraction = psMetadataLookupF32 (&status, recipe, "SOFTEN.VARIANCE.FRACTION");

    // make this an option via the recipe
    if (softenVariance) {
      psImage *im = readout->image;
      psImage *wt = readout->variance;
      for (int j = 0; j < im->numRows; j++) {
        for (int i = 0; i < im->numCols; i++) {
	    if (!isfinite(im->data.F32[j][i])) continue;
	    if (!isfinite(wt->data.F32[j][i])) continue;
	    float sysError = softenFraction * im->data.F32[j][i];
	    wt->data.F32[j][i] += PS_SQR(sysError);
        }
      }
    }

    // mask the excluded outer pixels
    // these coordinates refer to the parent image
    // these bounds will saturate on the subimage
    // negative upper bounds will subtract from the *subimage*
    float XMIN  = psMetadataLookupF32 (&status, recipe, "XMIN");
    float XMAX  = psMetadataLookupF32 (&status, recipe, "XMAX");
    float YMIN  = psMetadataLookupF32 (&status, recipe, "YMIN");
    float YMAX  = psMetadataLookupF32 (&status, recipe, "YMAX");
    psRegion valid = psRegionSet (XMIN, XMAX, YMIN, YMAX);

    // restrict the supplied region above to the valid area on the image
    psRegion keep = psRegionForImage (readout->image, valid);

    // psImageKeepRegion assumes the region refers to the parent coordinates
    psImageKeepRegion (readout->mask, keep, "OR", maskBad);

    // test output of files at this stage
    if (psTraceGetLevel("psphot") >= 5) {
        psphotSaveImage (NULL, readout->image,  "image.fits");
        psphotSaveImage (NULL, readout->mask,   "mask.fits");
        psphotSaveImage (NULL, readout->variance, "variance.fits");
    }

    // display the image, weight, mask (ch 1,2,3)
    psphotVisualShowImage (readout);

    return true;
}
