// 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 <math.h>
#include "pslib.h"
#include "pois.h"


psArray *poisFindStamps(psArray *stamps, // Existing list of stamps, or NULL
                        const psImage *image, // Image for which to find stamps
                        const psImage *mask, // Mask image
                        const poisConfig *config // Configuration values
    )
{
    int nx = config->xImage;            // Size of image in x
    int ny = config->yImage;            // Size of image in y

    assert(image->numCols == nx && image->numRows == ny);
    assert(mask->numCols == nx && mask->numRows == ny);
    assert(image->type.type == PS_TYPE_F32);
    assert(mask->type.type == PS_TYPE_U8);
    assert(!stamps || stamps->n == config->nsx * config->nsy);

    int footprint = config->footprint;  // Footprint for stamps
    int borderx = footprint + config->xKernel; // Border around image in x
    int bordery = footprint + config->yKernel; // Border around image in y
    int nsx = config->nsx;              // Number of stamps in x
    int nsy = config->nsy;              // Number of stamps in y

    psF32 **pixels = image->data.F32;   // The image pixels

    if (stamps == NULL) {
        stamps = psArrayAlloc(nsx * nsy);
        // Initialise
        for (int i = 0; i < nsx * nsy; i++) {
            stamps->data[i] = poisStampAlloc();
        }
    }

    // Iterate over the image sections
    int num = 0;
    for (int i = 0; i < nsx; i++) {
        for (int j = 0; j < nsy; j++) {
            poisStamp *stamp = stamps->data[num]; // The stamp

            // Only find a new stamp if we need to
            if ((stamp->x == 0 && stamp->y == 0) || stamp->status == POIS_STAMP_RESET) {
                // Find maximum non-masked value in the image section, but don't include a footprint around
                // the edge
                float max = - INFINITY;         // Negative infinity
                int bestx = 0, besty = 0;       // Position of maximum

                for (int y = bordery + j * (ny - 2.0 * bordery) / nsy;
                     y < bordery + (j + 1) * (ny - 2.0 * bordery) / nsy; y++) {
                    for (int x = borderx + i * (nx - 2.0 * borderx) / nsx;
                         x < borderx + (i + 1) * (nx - 2.0 * borderx) / nsx; x++) {
                        if (pixels[y][x] > max && poisCheckStamp(image, mask, x, y, config)) {
                            max = pixels[y][x];
                            bestx = x;
                            besty = y;
                        }
                    }
                } // Done iterating over this image section

                // Store the stamp
                if (max != - INFINITY) {
                    stamp->x = bestx;
                    stamp->y = besty;
                    stamp->status = POIS_STAMP_RECALC;
                } else {
                    // No stamp in this section
                    stamp->status = POIS_STAMP_BAD;
                }
            } // Finding a new stamp

            psTrace("pois.findStamps", 7, "Stamp %d: %d,%d\n", num, stamp->x, stamp->y);
            num++;
        }
    } // Done iterating over sections

    return stamps;
}
