# include "psphotInternal.h"

bool psphotFindFootprints (pmDetections *detections, psImage *significance, pmReadout *readout, psMetadata *recipe, const int pass, psImageMaskType maskVal) {

    bool status;

    psTimerStart ("psphot.footprints");

    int npixMin = psMetadataLookupS32(&status, recipe, "FOOTPRINT_NPIXMIN");
    PS_ASSERT (status, false);

    float FOOTPRINT_NSIGMA_LIMIT;
    if (pass == 1) {
        FOOTPRINT_NSIGMA_LIMIT = psMetadataLookupS32(&status, recipe, "FOOTPRINT_NSIGMA_LIMIT");
    } else {
        FOOTPRINT_NSIGMA_LIMIT = psMetadataLookupS32(&status, recipe, "FOOTPRINT_NSIGMA_LIMIT_2");
    }
    PS_ASSERT (status, false);

    // XXX do we need to use the same threshold here as for peaks?  does it make sense for
    // these to be different?

    float threshold = PS_SQR(FOOTPRINT_NSIGMA_LIMIT);

    int growRadius = 0;
    if (pass == 1) {
        growRadius = psMetadataLookupS32(&status, recipe, "FOOTPRINT_GROW_RADIUS");
    } else {
        growRadius = psMetadataLookupS32(&status, recipe, "FOOTPRINT_GROW_RADIUS_2");
    }
    PS_ASSERT (status, false);

    // find the raw footprints & assign the peaks to those footprints
    psArray *footprints = pmFootprintsFind (significance, threshold, npixMin);

    pmFootprintsAssignPeaks(footprints, detections->peaks);
    // XXX handle the error conditions here

    // footprints now owns the peaks; after culling (below), we will rebuild the peaks array
    psFree (detections->peaks);

    psLogMsg ("psphot", PS_LOG_MINUTIA, "found %ld footprints: %f sec\n", footprints->n, psTimerMark ("psphot.footprints"));

    // optionally grow footprints isotropically by growRadius pixels
    if (growRadius > 0) {
        bool oldThreads = psImageConvolveSetThreads(true); // Old value of threading for psImageConvolve
        psArray *tmp = pmFootprintArrayGrow(footprints, growRadius);
        psImageConvolveSetThreads(oldThreads);
        psLogMsg ("psphot", PS_LOG_MINUTIA, "grow footprint coverage by %d pixels, %ld footprints become %ld footprints: %f sec\n", growRadius, footprints->n, tmp->n, psTimerMark ("psphot.footprints"));
        psFree(footprints);
        footprints = tmp;
    }

    if (pass == 2) {
        // merge in old peaks;
        const int includePeaks = 0x0 | 0x2; // i.e. just from newFootprints

        // XXX EAM : still not sure I understand this: are we double-couning or undercounting peaks

        psArray *mergedFootprints = pmFootprintArraysMerge(detections->footprints, footprints, includePeaks);
        psLogMsg ("psphot", PS_LOG_MINUTIA, "merged %ld new footprints with %ld existing ones: %f sec\n", footprints->n, detections->footprints->n, psTimerMark ("psphot.footprints"));

        psFree(footprints);
        psFree(detections->footprints);
        detections->footprints = mergedFootprints;
    } else {
        detections->footprints = footprints;
    }

    psphotCullPeaks(readout->image, readout->variance, recipe, detections->footprints);
    detections->peaks = pmFootprintArrayToPeaks(detections->footprints);
    psLogMsg ("psphot", PS_LOG_INFO, "%ld peaks, %ld total footprints: %f sec\n", detections->peaks->n, detections->footprints->n, psTimerMark ("psphot.footprints"));

    return detections;
}
