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

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <pslib.h>
#include <psmodules.h>

#include "ppMerge.h"
#include "ppMergeData.h"
#include "ppMergeMask.h"


// Generate a mask
bool ppMergeMask(ppMergeData *data,  // Data
                 ppMergeOptions *options, // Options
                 pmConfig *config    // Configuration
    )
{
    psArray *filenames = psMetadataLookupPtr(NULL, config->arguments, "INPUT"); // The input file names
    assert(filenames);                  // It should be here --- it's put here in ppMergeConfig

    psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS, 0); // Random number generator
    pmFPA *fpaOut = data->out;          // Output FPA

    // Iterate over each file
    for (int i = 0; i < filenames->n; i++) {
        if (! filenames->data[i] || strlen(filenames->data[i]) == 0) {
            continue;
        }
        psFits *fits = data->files->data[i]; // FITS file handle
        if (!fits) {
            continue;
        }
        psTrace("ppMerge", 3, "File %d: %s\n", i, (const char*)filenames->data[i]);

        pmFPA *fpaIn = data->in->data[i]; // Input FPA
        pmFPAview *view = pmFPAviewAlloc(0); // View of FPA, for iteration
        pmChip *chipIn;                 // Input chip of interest
        while ((chipIn = pmFPAviewNextChip(view, fpaIn, 1))) {
            pmCell *cellIn;             // Input cell of interest
            while ((cellIn = pmFPAviewNextCell(view, fpaIn, 1))) {
                if (!pmCellRead(cellIn, fits, config->database)) {
                    continue;
                }
                if (cellIn->readouts->n == 0) {
                    continue;
                }

                pmCell *cellOut = pmFPAviewThisCell(view, fpaOut); // Output cell
                // Suspect pixels image
                psImage *suspect = psMetadataLookupPtr(NULL, cellOut->analysis, "MASK.SUSPECT");
                bool first = suspect ? false : true;

                pmReadout *roIn;        // Input readout of interest
                while ((roIn = pmFPAviewNextReadout(view, fpaIn, 1))) {
                    if (!roIn->image) {
                        continue;
                    }
                    psTrace("ppMerge", 4, "Flagging suspect pixels in chip %d, cell %d, ro %d\n",
                            view->chip, view->cell, view->readout);
                    float frac = options->sample / (float)(roIn->image->numCols * roIn->image->numRows);
                    suspect = pmMaskFlagSuspectPixels(suspect, roIn, options->maskSuspect,
                                                      options->combine->maskVal, frac, rng);
                }

                if (first) {
                    psMetadataAddImage(cellOut->analysis, PS_LIST_TAIL, "MASK.SUSPECT", 0,
                                       "Suspect pixels", suspect);
                    psFree(suspect);
                }

                pmCellFreeData(cellIn);
            }
            pmChipFreeData(chipIn);
        }
        pmFPAFreeData(fpaIn);
        psFree(view);
    }
    psFree(rng);

    pmFPAview *view = pmFPAviewAlloc(0);// View of FPA, for iteration
    pmFPAWriteMask(fpaOut, data->outFile, config->database, true, false); // Write header only
    pmChip *chipOut;                    // Output chip of interest
    while ((chipOut = pmFPAviewNextChip(view, fpaOut, 1))) {
        pmChipWriteMask(chipOut, data->outFile, config->database, true, false); // Write header only
        pmCell *cellOut;                   // Output cell of interest
        while ((cellOut = pmFPAviewNextCell(view, fpaOut, 1))) {
            pmCellWriteMask(cellOut, data->outFile, config->database, true); // Write header only

            psImage *suspect = psMetadataLookupPtr(NULL, cellOut->analysis, "MASK.SUSPECT");
            if (! suspect) {
                continue;
            }

            pmReadout *roOut = pmReadoutAlloc(cellOut); // Output readout
            roOut->mask = pmMaskIdentifyBadPixels(suspect, options->maskBad, options->combine->maskVal);
            psFree(roOut);              // Drop reference

            if (cellOut->hdu && !cellOut->hdu->blankPHU) {
                psTrace("ppMerge", 5, "Writing out cell HDU.\n");
                pmCellWriteMask(cellOut, data->outFile, config->database, false);
                pmCellFreeData(cellOut);
            }
        }

        if (chipOut->hdu && !chipOut->hdu->blankPHU) {
            psTrace("ppMerge", 5, "Writing out chip HDU.\n");
            pmChipWriteMask(chipOut, data->outFile, config->database, false, false);
            pmChipFreeData(chipOut);
        }
    }

    if (fpaOut->hdu && !fpaOut->hdu->blankPHU) {
        psTrace("ppMerge", 5, "Writing out FPA HDU.\n");
        pmFPAWriteMask(fpaOut, data->outFile, config->database, false, false);
    }
    pmFPAFreeData(fpaOut);

    psFree(view);

    return true;
}
