/** @file ppSubSetMasks.c
 *
 *  @brief
 *
 *  @ingroup ppSub
 *
 *  @author IfA
 *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
 *  @date $Date: 2009-02-18 00:31:20 $
 *  Copyright 2009 Institute for Astronomy, University of Hawaii
 */

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

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

#include "ppSub.h"

bool ppSubSetMasks(pmConfig *config, const pmFPAview *view)
{
    psAssert(config, "Require configuration");
    psAssert(view, "Require view");

    psImageMaskType maskValue, markValue; // Mask values
    if (!pmConfigMaskSetBits(&maskValue, &markValue, config)) {
        psError(PS_ERR_UNKNOWN, false, "Unable to determine mask value.");
        return false;
    }

    // Set the mask bits needed by psphot (in psphot recipe)
    psphotSetMaskRecipe (config, maskValue, markValue);

    // Look up recipe values
    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSUB_RECIPE); // Recipe for ppSim
    psAssert(recipe, "We checked this earlier, so it should be here.");

    psImageMaskType satValue = pmConfigMaskGet("SAT", config);
    psAssert(satValue, "SAT must be non-zero");

    psImageMaskType badValue = pmConfigMaskGet("BAD", config);
    psAssert(badValue, "BAD must be non-zero");

    // input images
    pmReadout *inRO = pmFPAfileThisReadout(config->files, view, "PPSUB.INPUT"); // Input readout
    pmReadout *refRO = pmFPAfileThisReadout(config->files, view, "PPSUB.REF"); // Reference readout

    psImage *input = inRO->image;       // Input image
    psImage *reference = refRO->image;  // Reference image
    PS_ASSERT_IMAGES_SIZE_EQUAL(input, reference, false);
    int numCols = input->numCols, numRows = input->numRows; // Size of image

    // Generate masks if they don't exist
    if (!inRO->mask) {
        if (psMetadataLookupBool(NULL, recipe, "MASK.GENERATE")) {
            pmReadoutSetMask(inRO, satValue, badValue);
        } else {
            inRO->mask = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK);
            psImageInit(inRO->mask, 0);
        }
    }
    if (!refRO->mask) {
        if (psMetadataLookupBool(NULL, recipe, "MASK.GENERATE")) {
            pmReadoutSetMask(refRO, satValue, badValue);
        } else {
            refRO->mask = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK);
            psImageInit(refRO->mask, 0);
        }
    }

    // Mask the NAN values
    if (!pmReadoutMaskNonfinite(inRO, satValue)) {
        psError(PS_ERR_UNKNOWN, false, "Unable to mask non-finite pixels in input.");
        return false;
    }
    if (!pmReadoutMaskNonfinite(refRO, satValue)) {
        psError(PS_ERR_UNKNOWN, false, "Unable to mask non-finite pixels in reference.");
        return false;
    }


#if 0
    // Interpolation over bad pixels: this takes a while!
    bool mdok = false;
    psString interpModeStr = psMetadataLookupStr(&mdok, recipe, "INTERPOLATION"); // Interpolation mode
    psImageInterpolateMode interpMode = psImageInterpolateModeFromString(interpModeStr); // Interp
    if (interpMode == PS_INTERPOLATE_NONE) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false, "Unknown interpolation mode: %s", interpModeStr);
        return false;
    }
    float poorFrac = psMetadataLookupF32(&mdok, recipe, "POOR.FRACTION"); // Fraction for "poor"

    psImageMaskType maskPoor = pmConfigMaskGet("POOR.WARP", config); // Bits to mask for poor pixels
    psImageMaskType maskBad = pmConfigMaskGet("BLANK", config); // Bits to mask for bad pixels

    // Interpolate over bad pixels, so the bad pixels don't explode
    if (!pmReadoutInterpolateBadPixels(inRO, maskVal, interpMode, poorFrac, maskPoor, maskBad)) {
        psError(PS_ERR_UNKNOWN, false, "Unable to interpolate bad pixels for input image.");
        return false;
    }
    if (!pmReadoutInterpolateBadPixels(refRO, maskVal, interpMode, poorFrac, maskPoor, maskBad)) {
        psError(PS_ERR_UNKNOWN, false, "Unable to interpolate bad pixels for reference image.");
        return false;
    }
    maskVal |= maskBad;
#endif

    return true;
}
