# include "psphotInternal.h"

// generate mask and variance if not defined, additional mask for restricted subregion
bool psphotSetMaskAndVariance (pmConfig *config, pmReadout *readout, psMetadata *recipe) {

    bool status;

    // ** Interpret the mask values:
    // XXX drop the write to recipe and move config into psphotRoughClass?
    // XXX alternatively, define a function to set the psphot recipe masks
    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) {
        // XXX: 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");
    }

    return true;
}
