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

pmConfig *pswarpArguments (int argc, char **argv) {

    bool status;
    int N;

    if (argc == 1) {
        psError(PSWARP_ERR_ARGUMENTS, true, "No arguments supplied");
        return NULL;
    }

    // load config data from default locations
    pmConfig *config = pmConfigRead(&argc, argv, PSWARP_RECIPE);
    if (config == NULL) {
        psError(PSWARP_ERR_CONFIG, false, "Can't read site configuration");
        return NULL;
    }

    // save the following additional recipe values based on command-line options
    // these options override the PSWARP recipe values loaded from recipe files
    pmConfigRecipeOptions (config, PSWARP_RECIPE);

    pmConfigFileSetsMD (config->arguments, &argc, argv, "ASTROM",   "-astrom", "-astromlist");

    // chip selection is used to limit chips to be processed
    if ((N = psArgumentGet(argc, argv, "-chip"))) {
        psArgumentRemove(N, &argc, argv);
        psMetadataAddStr(config->arguments, PS_LIST_TAIL, "CHIP_SELECTIONS", PS_DATA_STRING,
                         "Only process these chips", argv[N]);
        psArgumentRemove(N, &argc, argv);
    }

    // Statistics file
    if ((N = psArgumentGet(argc, argv, "-stats"))) {
        psArgumentRemove(N, &argc, argv);
        psMetadataAddStr(config->arguments, PS_LIST_TAIL, "STATS", PS_DATA_STRING,
                         "Filename for statistics of output image", argv[N]);
        psArgumentRemove(N, &argc, argv);
    }

    status = pmConfigFileSetsMD (config->arguments, &argc, argv, "INPUT", "-file", "-list");
    if (!status) {
        psError(PSWARP_ERR_ARGUMENTS, true, "Missing -file (input) or -list (input)");
        return NULL;
    }

    // the mask and weight entries are optional (build from gain?)
    pmConfigFileSetsMD (config->arguments, &argc, argv, "MASK",   "-mask",   "-masklist");
    pmConfigFileSetsMD (config->arguments, &argc, argv, "WEIGHT", "-weight", "-weightlist");

    if (argc != 3) {
        psError(PSWARP_ERR_ARGUMENTS, true, "Incorrect arguments supplied");
        return NULL;
    }


    psArray *array;

    // output position is fixed
    psMetadataAddStr (config->arguments, PS_LIST_TAIL, "OUTPUT", 0, "", argv[1]);

    // skycell position is fixed
    array = psArrayAlloc(1);
    array->data[0] = psStringCopy (argv[2]);
    status = psMetadataAddPtr (config->arguments, PS_LIST_TAIL, "SKYCELL", PS_DATA_ARRAY, "", array);
    psFree (array);


    // Parse the recipe and format into the arguments
    {

        // Select the appropriate recipe
        psMetadata *recipe  = psMetadataLookupPtr (NULL, config->recipes, PSWARP_RECIPE);
        if (!recipe) {
            psError(PSWARP_ERR_CONFIG, true, "Can't find %s recipe!\n", PSWARP_RECIPE);
            return false;
        }

        // Get grid size
        bool status;                        // Status of MD lookup
        int nGridX = psMetadataLookupS32 (&status, recipe, "GRID.NX");
        if (!status) nGridX = 128;
        int nGridY = psMetadataLookupS32 (&status, recipe, "GRID.NY");
        if (!status) nGridY = 128;

        // Get interpolation mode
        psImageInterpolateMode interpolationMode; // Mode for interpolation
        const char *name = psMetadataLookupStr (&status, recipe, "INTERPOLATION.MODE"); // Name of interp mode
        if (!name) {
            interpolationMode = PS_INTERPOLATE_BILINEAR;
            psLogMsg ("pswarp", 3, "defaulting to bilinear interpolation\n");
        } else {
            interpolationMode = psImageInterpolateModeFromString (name);
            if (interpolationMode == PS_INTERPOLATE_NONE) {
                interpolationMode = PS_INTERPOLATE_BILINEAR;
                psLogMsg ("pswarp", 3,
                          "Unknown interpolation mode %s, defaulting to bilinear interpolation\n", name);
            }
        }

        // Get mask parameters
        psMaskType maskIn, maskPoor, maskBad; // Mask values for input, "poor" and "bad" pixels

        psString maskNames = psMetadataLookupStr(&status, recipe, "MASK.IN");
         if (!status) {
            maskIn = 0x00;
            psWarning("MASK.IN is not set in the %s recipe --- defaulting to %x.", PSWARP_RECIPE, maskIn);
        }
        maskIn = pmConfigMask(maskNames, config); // Mask for input data

        maskNames = psMetadataLookupStr(&status, recipe, "MASK.POOR");
        if (!status) {
            maskPoor = 0x00;
            psWarning("MASK.POOR is not set in the %s recipe --- defaulting to %x.", PSWARP_RECIPE, maskPoor);
        }
        maskPoor = pmConfigMask(maskNames, config); // Mask for "poor" warped data

        maskNames = psMetadataLookupStr(&status, recipe, "MASK.BAD");
        if (!status) {
            maskBad = 0x00;
            psWarning("MASK.BAD is not set in the %s recipe --- defaulting to %x.", PSWARP_RECIPE, maskBad);
        }
        maskBad = pmConfigMask(maskNames, config); // Mask for bad warped data

        float poorFrac = psMetadataLookupF32(&status, recipe, "POOR.FRAC"); // Frac of bad flux for a "poor"
        if (!status) {
            poorFrac = 0.0;
            psWarning("POOR.FRAC is not set in the %s recipe --- defaulting to %f.", PSWARP_RECIPE, poorFrac);
        }

        // Set recipe values in the arguments
        psMetadataAddS32(config->arguments, PS_LIST_TAIL, "GRID.NX", 0,
                         "Iso-astrom grid spacing in x", nGridX);
        psMetadataAddS32(config->arguments, PS_LIST_TAIL, "GRID.NY", 0,
                         "Iso-astrom grid spacing in y", nGridY);
        psMetadataAddS32(config->arguments, PS_LIST_TAIL, "INTERPOLATION.MODE", 0,
                         "Interpolation mode", interpolationMode);
        psMetadataAddU8(config->arguments, PS_LIST_TAIL, "MASK.IN", 0,
                         "Mask for input data", maskIn);
        psMetadataAddU8(config->arguments, PS_LIST_TAIL, "MASK.POOR", 0,
                         "Mask for poor warped data", maskPoor);
        psMetadataAddU8(config->arguments, PS_LIST_TAIL, "MASK.BAD", 0,
                         "Mask for bad warped data", maskBad);
        psMetadataAddF32(config->arguments, PS_LIST_TAIL, "POOR.FRAC", 0,
                         "Fraction of bad flux for a pixel to be marked as poor", poorFrac);
    }

    psTrace("pswarp", 1, "Done with pswarpArguments...\n");
    return (config);
}
