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

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

#include "ppStack.h"
#include "ppStackLoop.h"


bool ppStackCleanup(ppStackThreadData *stack, ppStackOptions *options, pmConfig *config)
{
    psAssert(stack, "Require stack");
    psAssert(options, "Require options");
    psAssert(config, "Require configuration");

    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // ppStack recipe
    psAssert(recipe, "We've thrown an error on this before.");

#if 0
    // Ensure masked regions really look masked
    {
        psString maskBadStr = psMetadataLookupStr(NULL, recipe, "MASK.BAD"); // Name of bits for bad
        psImageMaskType maskBad = pmConfigMaskGet(maskBadStr, config); // Bits to mask for bad pixels
        if (!pmReadoutMaskApply(options->outRO, maskBad)) {
            psWarning("Unable to apply mask");
        }
    }
#endif

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

        // Target cells
        pmFPAview *view = pmFPAviewAlloc(0); // View to cells of interest
        view->chip = view->cell = 0;
        pmCell *cell1 = pmFPAfileThisCell(config->files, view, "PPSTACK.OUTPUT.JPEG1");
        pmCell *cell2 = pmFPAfileThisCell(config->files, view, "PPSTACK.OUTPUT.JPEG2");
        psImageMaskType maskValue = pmConfigMaskGet("BLANK", config); // Bits to mask
        psFree(view);

        pmReadout *ro1 = pmReadoutAlloc(cell1), *ro2 = pmReadoutAlloc(cell2); // Binned readouts
        if (!pmReadoutRebin(ro1, options->outRO, maskValue, bin1, bin1) ||
            !pmReadoutRebin(ro2, ro1, 0, bin2, bin2)) {
            psError(PPSTACK_ERR_DATA, false, "Unable to bin output.");
            psFree(ro1);
            psFree(ro2);
            return false;
        }
        psFree(ro1);
        psFree(ro2);
    }

    // Statistics on output
    if (options->stats) {
        psTrace("ppStack", 1, "Gathering statistics on stacked image....\n");
        psString maskBadStr = psMetadataLookupStr(NULL, recipe, "MASK.BAD"); // Name of bits for bad
        psImageMaskType maskBad = pmConfigMaskGet(maskBadStr, config); // Bits to mask for bad pixels

        pmFPAview *view = pmFPAviewAlloc(0); // View to readout
        view->chip = view->cell = view->readout = 0;

        ppStatsFPA(options->stats, options->outRO->parent->parent->parent, view, maskBad, config);

        psFree(view);
    }

    if (!ppStackFilesIterateUp(config)) {
        psError(psErrorCodeLast(), false, "Unable to close files.");
        return false;
    }
    ppStackFileActivation(config, PPSTACK_FILES_STACK, false);
    ppStackFileActivation(config, PPSTACK_FILES_PHOT, false);

    // Ensure files are freed
    {
        options->outRO->data_exists = false;
        options->outRO->parent->data_exists = false;
        options->outRO->parent->parent->data_exists = false;
        psFree(options->outRO);
        options->outRO = NULL;

        options->expRO->data_exists = false;
        options->expRO->parent->data_exists = false;
        options->expRO->parent->parent->data_exists = false;
        psFree(options->expRO);
        options->expRO = NULL;

        pmFPAview *view = pmFPAviewAlloc(0);// Pointer into FPA hierarchy
        view->chip = view->cell = 0;        // pmFPAviewFreeData doesn't want to deal with readouts
        pmFPAfile *jpeg1 = pmFPAfileSelectSingle(config->files, "PPSTACK.OUTPUT.JPEG1", 0); // JPEG file
        pmFPAviewFreeData(view, jpeg1);
        pmFPAfile *jpeg2 = pmFPAfileSelectSingle(config->files, "PPSTACK.OUTPUT.JPEG2", 0); // JPEG file
        pmFPAviewFreeData(view, jpeg2);
        pmFPAfile *phot = NULL;         // Photometry file
        if (options->photometry) {
            phot = pmFPAfileSelectSingle(config->files, "PSPHOT.INPUT", 0); // Photometry file
            pmFPAviewFreeData(view, phot);
        }

        view->readout = 0;
        pmReadout *ro1 = pmFPAviewThisReadout(view, jpeg1->fpa); // JPEG readout
        ro1->data_exists = ro1->parent->data_exists = ro1->parent->parent->data_exists = false;
        pmReadout *ro2 = pmFPAviewThisReadout(view, jpeg2->fpa); // JPEG readout
        ro2->data_exists = ro2->parent->data_exists = ro2->parent->parent->data_exists = false;
        if (options->photometry) {
            pmReadout *ro = pmFPAviewThisReadout(view, phot->fpa); // Photometry readout
            ro->data_exists = ro->parent->data_exists = ro->parent->parent->data_exists = false;
        }
        psFree(view);
    }

    return true;
}
