/** @file ppSubReadoutUpdate.c
 *
 *  @brief
 *
 *  @ingroup ppSub
 *
 *  @author IfA
 *  @version $Revision: 1.4 $ $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 "ppSub.h"

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

    bool mdok = false;                  // Status of MD lookup

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

    pmFPAfile *outFile = psMetadataLookupPtr(&mdok, config->files, "PPSUB.OUTPUT"); // Output file
    pmReadout *outRO = pmFPAfileThisReadout(config->files, view, "PPSUB.OUTPUT"); // Output image
    pmFPA *outFPA = outFile->fpa;       // Output FPA
    pmHDU *outHDU = outFPA->hdu;        // Output HDU

    // Add additional data to the header
    pmFPAfile *refFile = psMetadataLookupPtr(NULL, config->files, "PPSUB.REF"); // Reference file
    pmFPAfile *inFile = psMetadataLookupPtr(NULL, config->files, "PPSUB.INPUT"); // Input file
    psMetadataAddStr(outHDU->header, PS_LIST_TAIL, "PPSUB.REFERENCE", 0,
                     "Subtraction reference", refFile->filename);
    psMetadataAddStr(outHDU->header, PS_LIST_TAIL, "PPSUB.INPUT", 0,
                     "Subtraction input", inFile->filename);
    ppSubVersionHeader(outHDU->header);

    // Statistics on the matching
    if (stats) {
        psMetadataCopySingle(stats, outRO->analysis, PM_SUBTRACTION_ANALYSIS_MODE);
        psMetadataCopySingle(stats, outRO->analysis, PM_SUBTRACTION_ANALYSIS_STAMPS);
        psMetadataCopySingle(stats, outRO->analysis, PM_SUBTRACTION_ANALYSIS_DEV_MEAN);
        psMetadataCopySingle(stats, outRO->analysis, PM_SUBTRACTION_ANALYSIS_DEV_RMS);
        psMetadataCopySingle(stats, outRO->analysis, PM_SUBTRACTION_ANALYSIS_NORM);
        psMetadataCopySingle(stats, outRO->analysis, PM_SUBTRACTION_ANALYSIS_BGDIFF);
        psMetadataCopySingle(stats, outRO->analysis, PM_SUBTRACTION_ANALYSIS_MX);
        psMetadataCopySingle(stats, outRO->analysis, PM_SUBTRACTION_ANALYSIS_MY);
        psMetadataCopySingle(stats, outRO->analysis, PM_SUBTRACTION_ANALYSIS_MXX);
        psMetadataCopySingle(stats, outRO->analysis, PM_SUBTRACTION_ANALYSIS_MXY);
        psMetadataCopySingle(stats, outRO->analysis, PM_SUBTRACTION_ANALYSIS_MYY);

        psMetadataAddF32(stats, PS_LIST_TAIL, "TIME_MATCH", 0, "Time to match PSFs",
                         psTimerClear("PPSUB_MATCH"));
    }

    // Generate binned JPEGs
    {
        psImageMaskType maskBad = pmConfigMaskGet("BLANK", config); // Bits to mask for bad pixels

        int bin1 = psMetadataLookupS32(NULL, recipe, "BIN1"); // First binning level
        int bin2 = psMetadataLookupS32(NULL, recipe, "BIN2"); // Second binning level

        // Target cells
        pmCell *cell1 = pmFPAfileThisCell(config->files, view, "PPSUB.OUTPUT.JPEG1"); // Rebinned cell once
        pmCell *cell2 = pmFPAfileThisCell(config->files, view, "PPSUB.OUTPUT.JPEG2"); // Rebinned cell twice

        pmReadout *ro1 = pmReadoutAlloc(cell1), *ro2 = pmReadoutAlloc(cell2); // Binned readouts
        if (!pmReadoutRebin(ro1, outRO, maskBad, bin1, bin1)) {
            psError(PS_ERR_UNKNOWN, false, "Unable to bin output (1st binning)");
            psFree(ro1);
            psFree(ro2);
            return false;
        }
        if (!pmReadoutRebin(ro2, ro1, 0, bin2, bin2)) {
            psError(PS_ERR_UNKNOWN, false, "Unable to bin output (2nd binning)");
            psFree(ro1);
            psFree(ro2);
            return false;
        }
        psFree(ro1);
        psFree(ro2);
    }

#ifdef TESTING
    // Significance image
    {
        psImage *sig = (psImage*)psBinaryOp(NULL, outRO->image, "*", outRO->image);
        psBinaryOp(sig, sig, "/", outRO->variance);
        psFits *fits = psFitsOpen("significance.fits", "w");
        psFitsWriteImage(fits, NULL, sig, 0, NULL);
        psFitsClose(fits);
        psFree(sig);
    }
#endif

    return true;
}
