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

#include <stdio.h>
#include "pslib.h"
#include "stac.h"
#include "combineConfig.h"

int main(int argc, char **argv)
{
    // Set trace levels
    (void)psTraceSetLevel(".", 0);
    (void)psTraceSetLevel("stac.checkMemory", 10);
    (void)psTraceSetLevel("stac.read", 10);
    (void)psTraceSetLevel("stac.scales", 7);
    (void)psTraceSetLevel("stac.rescale", 10);
    (void)psTraceSetLevel("stac.combine", 10);
    (void)psTraceSetLevel("combine", 10);

    // Set logging level
    psLogSetLevel(9);

    // Parse command line
    combineConfig *config = combineParseConfig(argc, argv); // Configuration

    psArray *headers = NULL;            // Array of headers
    psArray *images = stacReadImages(&headers, config->inNames); // The images
    // Make fake errors
    psArray *errors = psArrayAlloc(images->n);
    for (int i = 0; i < images->n; i++) {
        psImage *image = images->data[i];
        psImage *err = psImageAlloc(image->numCols, image->numRows, PS_TYPE_F32);
        for (int y = 0; y < image->numRows; y++) {
            for (int x = 0; x < image->numCols; x++) {
                err->data.F32[y][x] = 1.0;
            }
        }
        errors->data[i] = err;
    }

    // Calculate scales between images
    psVector *scales = NULL;            // Relative scales between images
    psVector *offsets = NULL;           // Offsets between images
    (void)stacScales(&scales, &offsets, images, config->starFile, config->starMap, 0.0, 0.0, config->aper);

    // Set the saturation and bad values
    psVector *saturated = psVectorAlloc(images->n, PS_TYPE_F32); // Saturation limits
    psVector *bad = psVectorAlloc(images->n, PS_TYPE_F32); // Bad limits
    for (int i = 0; i < images->n; i++) {
        saturated->data.F32[i] = (config->saturated - offsets->data.F32[i]) / scales->data.F32[i];
        bad->data.F32[i] = (config->bad - offsets->data.F32[i]) / scales->data.F32[i];
    }

    // Rescale the images
    (void)stacRescale(images, errors, NULL, scales, offsets);

    // Combine the images
    psImage *combined = NULL;           // Combined image
    psArray *rejected = NULL;           // Array of rejection masks
    stacCombine(&combined, &rejected, images, errors, config->nReject, NULL, saturated, bad, config->reject);

    psFits *outFile = psFitsOpen(config->outName, "w");
    if (!psFitsWriteImage(outFile, headers->data[0], combined, 0, NULL)) {
        psErrorStackPrint(stderr, "Unable to write image: %s\n", config->outName);
    }
    psTrace("combine", 1, "Combined image written to %s\n", config->outName);
    psFitsClose(outFile);

    // Clean up
    psFree(headers);
    psFree(combined);
    psFree(rejected);
    psFree(images);
    psFree(errors);
    psFree(saturated);
    psFree(bad);
    psFree(scales);
    psFree(offsets);
    combineConfigFree(config);

#ifdef TESTING
    // Check memory for leaks, corruption
    stacCheckMemory();
#endif

}
