/** @file pswarpParseCamera.c
 *
 *  @brief
 *
 *  @ingroup pswarp
 *
 *  @author IfA
 *  @version $Revision: 1.24 $ $Name: not supported by cvs2svn $
 *  @date $Date: 2009-02-06 03:10:36 $
 *  Copyright 2009 Institute for Astronomy, University of Hawaii
 */

#include "pswarp.h"

// Define an input file
static pmFPAfile *defineInputFile(pmConfig *config,// Configuration
                                  pmFPAfile *bind,    // File to which to bind, or NULL
                                  char *filerule,     // Name of file rule
                                  char *argname,      // Argument name
                                  pmFPAfileType fileType // Type of file
    )
{
    bool status;

    pmFPAfile *file = NULL;
    // look for the file on the argument list
    if (bind) {
        file = pmFPAfileBindFromArgs(&status, bind, config, filerule, argname);
    } else {
        file = pmFPAfileDefineFromArgs(&status, config, filerule, argname);
    }
    if (!status) {
        psError(psErrorCodeLast(), false, "Failed to load file definition for %s", filerule);
        return false;
    }
    if (!file) {
        // look for the file on the RUN metadata
        file = pmFPAfileDefineFromRun(&status, bind, config, filerule); // File to return
        if (!status) {
            psError(psErrorCodeLast(), false, "Failed to load file definition for %s", filerule);
            return NULL;
        }
    }

    if (!file) {
        return NULL;
    }

    if (file->type != fileType) {
        psError(PSWARP_ERR_CONFIG, true, "%s is not of type %s", filerule, pmFPAfileStringFromType(fileType));
        return NULL;
    }

    return file;
}




bool pswarpParseCamera(pmConfig *config)
{
    psAssert(config, "Require configuration");

    // The input image(s) is required: it defines the camera
    pmFPAfile *input = defineInputFile(config, NULL, "PSWARP.INPUT", "INPUT", PM_FPA_FILE_IMAGE);
    if (!input) {
        psError(psErrorCodeLast(), false, "Failed to build FPA from PSWARP.INPUT");
        return false;
    }

    pmFPAfile *astrom = defineInputFile(config, NULL, "PSWARP.ASTROM", "ASTROM", PM_FPA_FILE_CMF);
    psLogMsg("pswarp", PS_LOG_INFO, "Astrometry source: %s", astrom ? "supplied" : "header");

    pmFPAfile *inMask = defineInputFile(config, input, "PSWARP.MASK", "MASK", PM_FPA_FILE_MASK);
    if (!inMask) {
        psLogMsg("pswarp", PS_LOG_INFO, "No mask supplied");
    }

    pmFPAfile *inVariance = defineInputFile(config, input, "PSWARP.VARIANCE", "VARIANCE",
                                            PM_FPA_FILE_VARIANCE);
    if (!inVariance) {
        psLogMsg("pswarp", PS_LOG_INFO, "No variance supplied");
    }

    // The input skycell is a required argument: it defines the output image
    // XXX we may need a different skycell structure here
    pmFPAfile *skycell = NULL;
    pmConfig *skyConfig = NULL;
    bool status = pswarpDefineSkycell(&skycell, &skyConfig, config, "PSWARP.SKYCELL", "SKYCELL");
    if (!status) {
        psError(psErrorCodeLast(), false, "Failed to build FPA from PSWARP.SKYCELL");
        return false;
    }
    psFree(skyConfig);

    // The output skycell
    pmFPAfile *output = pmFPAfileDefineSkycell(config, NULL, "PSWARP.OUTPUT");
    if (!output) {
        psError(psErrorCodeLast(), false, "Failed to build FPA from PSWARP.OUTPUT");
        return false;
    }
    output->save = true;

    pmFPAfile *outMask = pmFPAfileDefineSkycell(config, output->fpa, "PSWARP.OUTPUT.MASK");
    if (!outMask) {
        psError(psErrorCodeLast(), false, "Failed to build FPA from PSWARP.OUTPUT.MASK");
        return false;
    }
    outMask->save = true;

    if (inVariance) {
        pmFPAfile *outVariance = pmFPAfileDefineSkycell(config, output->fpa, "PSWARP.OUTPUT.VARIANCE");
        if (!outVariance) {
            psError(psErrorCodeLast(), false, "Failed to build FPA from PSWARP.OUTPUT.VARIANCE");
            return false;
        }
        outVariance->save = true;
    }

    if (astrom) {
        pmFPAfile *outSources = pmFPAfileDefineSkycell(config, output->fpa, "PSWARP.OUTPUT.SOURCES");
        if (!outSources) {
            psError(psErrorCodeLast(), false, "Failed to build FPA from PSWARP.OUTPUT.SOURCES");
            return false;
        }
        outSources->save = true;
    }

    psMetadata *recipe = psMetadataLookupPtr (&status, config->recipes, PSWARP_RECIPE);
    if (!recipe) {
        psError(PSWARP_ERR_CONFIG, false, "missing recipe %s", PSWARP_RECIPE);
        return false;
    }

    bool mdok;                          // Status of MD lookup
    if (psMetadataLookupBool(&mdok, recipe, "PSF")) {
        // This file, PSPHOT.INPUT, is just used as a carrier; output files (eg, PSPHOT.RESID) are defined by
        // psphotDefineFiles
        pmFPAfile *psphotInput = pmFPAfileDefineSkycell(config, NULL, "PSPHOT.INPUT");
        if (!psphotInput) {
            psError(psErrorCodeLast(), false, _("Unable to generate output file from PSPHOT.INPUT"));
            return false;
        }
        psphotInput->src = psMemIncrRefCounter(output->fpa);
        // specify the number of psphot input images
        psMetadataAddS32 (config->arguments, PS_LIST_TAIL, "PSPHOT.INPUT.NUM", PS_META_REPLACE, "number of inputs", 1);

        pmFPAfile *psphotInSources = pmFPAfileDefineSkycell(config, output->fpa, "PSPHOT.INPUT.CMF");
        if (!psphotInSources) {
            psError(psErrorCodeLast(), false, _("Unable to generate output file from PSPHOT.INPUT.CMF"));
            return false;
        }

        // Ensure psphot defines an output file for the PSF.
        psMetadata *psphotRecipe = psMetadataLookupPtr(NULL, config->recipes, PSPHOT_RECIPE); // Recipe
        if (!psphotRecipe) {
            psError(PSWARP_ERR_CONFIG, false, "Unable to find %s recipe.", PSPHOT_RECIPE);
            return false;
        }
        psMetadataAddBool(psphotRecipe, PS_LIST_TAIL, "SAVE.PSF", PS_META_REPLACE, "Save PSF?", true);

        // Define associated psphot input/output files
        if (!psphotDefineFiles(config, psphotInput)) {
            psError(PSWARP_ERR_CONFIG, false,
                    "Unable to define the additional input/output files for psphot");
            return false;
        }

        // Turn off writing the sources we find as part of deriving the PSF --- they might clobber the ones we
        // get from transforming the input coordinates.
        pmFPAfile *psphotSources = psMetadataLookupPtr(NULL, config->files, "PSPHOT.OUTPUT");
        assert(psphotSources);
        psphotSources->save = false;
    }

    // Chip selection: turn on only the chips specified
    char *chipLine = psMetadataLookupStr(&mdok, config->arguments, "CHIP_SELECTIONS");
    if (mdok) {
        psArray *chips = psStringSplitArray (chipLine, ",", false);
        if (chips->n > 0) {
            pmFPASelectChip (input->fpa, -1, true); // deselect all chips
            for (int i = 0; i < chips->n; i++) {
                int chipNum = atoi(chips->data[i]);
                if (! pmFPASelectChip(input->fpa, chipNum, false)) {
                    psError(PSWARP_ERR_ARGUMENTS, true, "Chip number %d doesn't exist in camera.\n", chipNum);
                    return false;
                }
            }
        }
        psFree(chips);
    }

    psTrace("pswarp", 1, "Done with pswarpParseCamera...\n");
    return true;
}
