#include <ppStats.h>
#include "pswarp.h"

// this loop loads the data from the input files and selects the
// brighter stars for astrometry
// at the end of this function, the complete stellar data is loaded
// into the correct fpa structure locations (readout.analysis:PSPHOT.SOURCES)

// all of the different astrometry analysis modes use the same data load loop
bool pswarpDataSave(pmConfig *config) {

    pmChip *chip;
    pmCell *cell;
    pmReadout *readout;

    // select the input data sources
    pmFPAfile *input = psMetadataLookupPtr (NULL, config->files, "PSWARP.INPUT");
    if (!input) {
        psError(PSWARP_ERR_CONFIG, true, "Can't find input data!\n");
        return false;
    }

    bool mdok;                          // Status of MD lookup
    const char *statsName = psMetadataLookupStr(&mdok, config->arguments, "STATS"); // Filename for statistics
    psMetadata *stats = NULL;           // Container for statistics
    FILE *statsFile = NULL;             // File stream for statistics
    if (mdok && statsName && strlen(statsName) > 0) {
        psString resolved = pmConfigConvertFilename(statsName, config, true);
        statsFile = fopen(resolved, "w");
        if (!statsFile) {
            psError(PS_ERR_IO, true, "Unable to open statistics file %s for writing.\n", resolved);
            psFree(resolved);
            return false;
        }
        psFree(resolved);
        stats = psMetadataAlloc();
    }

    // de-activate all files except PSWARP.OUTPUT
    pmFPAfileActivate (config->files, false, NULL);
    pmFPAfileActivate (config->files, true, "PSWARP.OUTPUT");
    pmFPAfileActivate (config->files, true, "PSWARP.OUTPUT.MASK");
    pmFPAfileActivate (config->files, true, "PSWARP.OUTPUT.WEIGHT");
    pmFPAview *view = pmFPAviewAlloc (0);

    // files associated with the science image
    pmFPAfileIOChecks (config, view, PM_FPA_BEFORE);

    while ((chip = pmFPAviewNextChip (view, input->fpa, 1)) != NULL) {
        psTrace ("pswarp", 4, "Chip %d: %x %x\n", view->chip, chip->file_exists, chip->process);
        if (!chip->process || !chip->file_exists) { continue; }
        pmFPAfileIOChecks (config, view, PM_FPA_BEFORE);

        while ((cell = pmFPAviewNextCell (view, input->fpa, 1)) != NULL) {
            psTrace ("pswarp", 4, "Cell %d: %x %x\n", view->cell, cell->file_exists, cell->process);
            if (!cell->process || !cell->file_exists) { continue; }
            pmFPAfileIOChecks (config, view, PM_FPA_BEFORE);

            // Perform statistics on the cell
            if (stats) {
                bool mdok;              // Status of MD lookup
                pmFPAfile *output = psMetadataLookupPtr(&mdok, config->files, "PSWARP.OUTPUT");
                if (!mdok || !output) {
                    psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find file PSWARP.OUTPUT.\n");
                    psFree(view);
                    psFree(stats);
                    return false;
                }
                ppStats(stats, output->fpa, view, config);
            }

            pmHDU *hdu = pmHDUFromCell(cell); // HDU that owns the cell

            // Process readouts
            while ((readout = pmFPAviewNextReadout(view, input->fpa, 1)) != NULL) {
                pmFPAfileIOChecks (config, view, PM_FPA_BEFORE);
                if (!readout->data_exists) {
                    continue;
                }

                // pswarpConvertReadout (readout, config);

                // Add MD5 information for readout
                const char *chipName = psMetadataLookupStr(NULL, chip->concepts, "CHIP.NAME");
                const char *cellName = psMetadataLookupStr(NULL, cell->concepts, "CELL.NAME");
                psString headerName = NULL; // Header name for MD5
                psStringAppend(&headerName, "MD5_%s_%s_%d", chipName, cellName, view->readout);
                psVector *md5 = psImageMD5(readout->image); // md5 hash
                psString md5string = psMD5toString(md5); // String
                psFree(md5);
                psMetadataAddStr(hdu->header, PS_LIST_TAIL, headerName, PS_META_REPLACE,
                                 "Image MD5", md5string);
                psFree(md5string);
                psFree(headerName);

                pmFPAfileIOChecks (config, view, PM_FPA_AFTER);
            }
            pmFPAfileIOChecks (config, view, PM_FPA_AFTER);
        }
        pmFPAfileIOChecks (config, view, PM_FPA_AFTER);
    }
    pmFPAfileIOChecks (config, view, PM_FPA_AFTER);
    psFree (view);

    // re-activate all pmFPAfiles
    pmFPAfileActivate (config->files, true, NULL);

    // Write out summary statistics
    if (stats) {
        const char *statsMDC = psMetadataConfigFormat(stats);
        if (!statsMDC || strlen(statsMDC) == 0) {
            psError(PS_ERR_IO, false, "Unable to get statistics MDC file.\n");
            psFree(stats);
            fclose(statsFile);
            return false;
        }
        fprintf(statsFile, "%s", statsMDC);
        psFree((void*)statsMDC);
        fclose(statsFile);

        psFree(stats);
    }

    return true;
}
