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

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

#include "pswarp.h"

bool pswarpPixelFraction(const pmReadout *readout, psMetadata *stats, const pmConfig *config)
{
    PS_ASSERT_PTR_NON_NULL(readout, false);
    PS_ASSERT_IMAGE_NON_NULL(readout->image, false);
    PS_ASSERT_IMAGE_TYPE(readout->image, PS_TYPE_F32, false);
    if (!readout->mask) {
        // Can't do anything
        return true;
    }
    PS_ASSERT_IMAGE_NON_NULL(readout->mask, false);
    PS_ASSERT_IMAGES_SIZE_EQUAL(readout->mask, readout->image, false);
    PS_ASSERT_IMAGE_TYPE(readout->mask, PS_TYPE_MASK, false);

    if (stats) {
        PS_ASSERT_METADATA_NON_NULL(stats, false);
    }
    PS_ASSERT_PTR_NON_NULL(config, false);
    PS_ASSERT_METADATA_NON_NULL(config->arguments, false);

    bool status; 

    float minFrac = psMetadataLookupF32(NULL, config->arguments, "ACCEPT.FRAC"); // Minimum fraction

    // load the recipe
    psMetadata *recipe = psMetadataLookupPtr (NULL, config->recipes, PSWARP_RECIPE);
    if (!recipe) {
        psError(PSPHOT_ERR_CONFIG, false, "missing recipe %s", PSWARP_RECIPE);
        return false;
    }

    // output mask bits
    psMaskType maskValue = psMetadataLookupU8(&status, recipe, "MASK.OUTPUT"); 
    psAssert (status, "MASK.OUTPUT was not defined");

    psImage *image = readout->image;    // Image of interest
    psImage *mask = readout->mask;      // Mask image

    int numCols = image->numCols, numRows = image->numRows; // Size of image
    long numPix = numCols * numRows;

    // Range of valid pixels
    int xMin = INT_MAX, xMax = -INT_MAX, yMin = INT_MAX, yMax = -INT_MAX;

    long numBad = 0;                     // Number of bad pixels
    for (int y = 0; y < numRows; y++) {
        for (int x = 0; x < numCols; x++) {
            if (mask->data.PS_TYPE_MASK_DATA[y][x] & maskValue) {
                numBad++;
            } else {
                if (y > yMax) {
                    yMax = y;
                }
                if (y < yMin) {
                    yMin = y;
                }
                if (x > xMax) {
                    xMax = x;
                }
                if (x < xMin) {
                    xMin = x;
                }
            }
        }
    }

    float goodFrac = (numPix - numBad) / (float)numPix; // Fraction of good pixels
    bool accept = (goodFrac >= minFrac ? true : false); // Accept this readout?

    if (stats) {
        psMetadataAddBool(stats, PS_LIST_HEAD, "ACCEPT", 0, "Accept this readout?", accept);

        psMetadataAddS32(stats, PS_LIST_TAIL, "RANGE.XMIN", 0, "Minimum valid x value", xMin);
        psMetadataAddS32(stats, PS_LIST_TAIL, "RANGE.XMAX", 0, "Maximum valid x value", xMax);
        psMetadataAddS32(stats, PS_LIST_TAIL, "RANGE.YMIN", 0, "Minimum valid y value", yMin);
        psMetadataAddS32(stats, PS_LIST_TAIL, "RANGE.YMAX", 0, "Maximum valid y value", yMax);
    }

    return accept;
}

