# include "pswarp.h"

bool pswarpParseCamera (pmConfig *config) {

    bool status;
    bool mdok;                          // Status of MD lookup
    pmFPAfile *skycell = NULL;
    pmConfig *skyConfig = NULL;

    // the input image(s) are required arguments; they define the camera
    status = false;
    pmFPAfile *input = pmFPAfileDefineFromArgs(&status, config, "PSWARP.INPUT", "INPUT");
    if (!input || !status) {
        psError(PSWARP_ERR_CONFIG, false, "Failed to build FPA from PSWARP.INPUT");
        return false;
    }

    // the input image(s) are required arguments; they define the camera
    status = false;
    pmFPAfile *astrom = pmFPAfileDefineFromArgs(&status, config, "PSWARP.ASTROM", "ASTROM");
    if (!status) {
        psError (PS_ERR_UNKNOWN, false, "failed to load find definition");
        return NULL;
    }
    if (astrom) {
        psLogMsg ("pswarp", 3, "using supplied astrometry\n");
    } else {
        psLogMsg ("pswarp", 3, "using header astrometry\n");
    }

    // the mask is not required - but must conform to input camera
    pmFPAfile *inMask = pmFPAfileBindFromArgs(&status, input, config, "PSWARP.MASK", "MASK");
    if (!status) {
        psError (PS_ERR_UNKNOWN, false, "failed to load find definition");
        return NULL;
    }
    if (!inMask) {
        psLogMsg ("pswarp", 3, "no mask supplied\n");
    }
    
    // loading the mask here should have invoked pmConfigMaskReadHeader()
    if (!pswarpSetMaskBits (config)) {
        psError(PS_ERR_IO, false, "failed to set mask bits");
        return NULL;
    }

    pmFPAfile *inWeight = pmFPAfileBindFromArgs(&status, input, config, "PSWARP.WEIGHT", "WEIGHT");
    if (!status) {
        psError (PS_ERR_UNKNOWN, false, "failed to load find definition");
        return NULL;
    }
    if (!inWeight) {
        psLogMsg ("pswarp", 3, "no weight supplied\n");
    }

    // the input skycell is a required argument: it defines the output image
    // XXX we may need a different skycell structure here
    status = pswarpDefineSkycell(&skycell, &skyConfig, config, "PSWARP.SKYCELL", "SKYCELL");
    if (!status) {
        psError(PSWARP_ERR_CONFIG, 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(PSWARP_ERR_CONFIG, false, "Failed to build FPA from PSWARP.OUTPUT");
        return false;
    }
    pmFPAfile *outMask = pmFPAfileDefineSkycell(config, output->fpa, "PSWARP.OUTPUT.MASK");
    if (!outMask) {
        psError(PSWARP_ERR_CONFIG, false, "Failed to build FPA from PSWARP.OUTPUT.MASK");
        return false;
    }

    output->save = true;
    outMask->save = true;

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

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

    if (psMetadataLookupBool(&mdok, config->arguments, "PSF")) {
        // This file, PSPHOT.INPUT, is just used as a carrier; output files (eg, PSPHOT.RESID) are defined by
        // psphotDefineFiles
        pmFPAfile *psphotInput = pmFPAfileDefineSkycell(config, output->fpa, "PSPHOT.INPUT");
        if (!psphotInput) {
            psError(PS_ERR_IO, false, _("Unable to generate output file from PSPHOT.INPUT"));
            return false;
        }

        // Ensure psphot defines an output file for the PSF.
        psMetadata *psphotRecipe = psMetadataLookupPtr(NULL, config->recipes, PSPHOT_RECIPE); // Recipe
        if (!psphotRecipe) {
            psError(PS_ERR_UNEXPECTED_NULL, 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(PSPHOT_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_CONFIG, true, "Chip number %d doesn't exist in camera.\n", chipNum);
                    return false;
                }
            }
        }
        psFree (chips);
    }

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