// Copyright (C) 2006  Paul A. Price (price@ifa.hawaii.edu)
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

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

#include <stdio.h>
#include <assert.h>
#include "pslib.h"
#include "pois.h"

#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define MIN(a,b) ((a) < (b) ? (a) : (b))

psImage *poisMakeMask(psImage *mask,    // Mask to update, or NULL
                      const psImage *refImage, // Reference image
                      const psImage *inImage, // Input image
                      const poisConfig *config // Configuration
    )
{
    assert(!mask || mask->type.type == PS_TYPE_U8);
    assert(!mask || (mask->numCols == refImage->numCols && mask->numRows == refImage->numRows));
    assert(refImage->numCols == inImage->numCols && refImage->numRows == inImage->numRows);
    assert(refImage->type.type == PS_TYPE_F32);
    assert(inImage->type.type == PS_TYPE_F32);
    assert(config);

    int nx = config->xImage;            // Size in x
    int ny = config->yImage;            // Size in y

    psTrace("pois.makeMask", 5, "Creating mask: %dx%d\n", nx, ny);

    // Allocate the mask image, if necessary
    if (mask == NULL) {
        mask = psImageAlloc(nx, ny, PS_TYPE_U8);
        // Initialise to zero
        for (int j = 0; j < ny; j++) {
            for (int i = 0; i < nx; i++) {
                mask->data.U8[j][i] = POIS_MASK_OK;
            }
        }
    }

    // Iterate over the images
    for (int y = config->yKernel; y < ny - config->yKernel; y++) {
        for (int x = config->xKernel; x < nx - config->xKernel; x++) {
            // Mask all around something that's saturated in the reference, since it gets convolved
            // But only mask single pixel in the input image, since it doesn't get convolved
            if (refImage->data.F32[y][x] >= config->refSat || refImage->data.F32[y][x] <= config->refBad ||
                isnan(refImage->data.F32[y][x])) {
                mask->data.U8[y][x] |= POIS_MASK_BAD;
                int xlow = MAX(0, x - config->xKernel);
                int xhigh = MIN(nx, x + config->xKernel);
                int ylow = MAX(0, y - config->yKernel);
                int yhigh = MIN(ny, y + config->yKernel);
                for (int v = ylow; v <= yhigh; v++) {
                    for (int u = xlow; u <= xhigh; u++) {
                        mask->data.U8[v][u] |= POIS_MASK_NEAR_BAD;
                    }
                }
            } else if (inImage->data.F32[y][x] >= config->inSat || inImage->data.F32[y][x] <= config->inBad ||
                isnan(inImage->data.F32[y][x])) {
                mask->data.U8[y][x] |= POIS_MASK_BAD;
            }
        }
    }

    return mask;
}
