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

# include "psvideophot.h"

psvideophotOptions *psvideophotParseCamera(pmConfig *config)
{
    bool status = false;

    if (!psvideophotDefineFile(config, NULL, "PSVIDEOPHOT.INPUT", "INPUT", PM_FPA_FILE_IMAGE, PM_DETREND_TYPE_NONE)) {
        psError(PS_ERR_IO, false, "Can't find an input image source");
        return NULL;
    }
    pmFPAfile *input = psMetadataLookupPtr(NULL, config->files, "PSVIDEOPHOT.INPUT"); // Input file
    psAssert(input, "We just put it there!");

    // add recipe options supplied on command line
    psMetadata *recipe  = psMetadataLookupPtr(&status, config->recipes, RECIPE_NAME);

    // parse the options from the metadata format to the psvideophotOptions structure
    psvideophotOptions *options = psvideophotOptionsParse(config);

    // the following are defined from the argument list, if given,
    // otherwise they revert to the config information
    // not all input or output images are used in a given recipe
    
    int nThreads = psMetadataLookupS32(&status, config->arguments, "NTHREADS");
    if (nThreads > 0) {
        int nScanRows = psMetadataLookupS32(&status, recipe, "SCAN.ROWS");
        pmDetrendSetThreadTasks(nScanRows);
    }

    // the following files are output targets
    pmFPAfile *outImage = pmFPAfileDefineOutput(config, input->fpa, "PSVIDEOPHOT.OUTPUT");
    if (!outImage) {
        psError(PS_ERR_IO, false, _("Unable to generate output file from PSVIDEOPHOT.OUTPUT"));
        psFree(options);
        return NULL;
    }
    if (outImage->type != PM_FPA_FILE_OBJ) {
        psError(PS_ERR_IO, true, "PSVIDEOPHOT.OUTPUT is not of type OBJ");
        psFree(options);
        return NULL;
    }
    
    // XXX should these be bound explicitly to the outImage->fpa rather than the input->fpa?
    pmFPAfile *chipImage = pmFPAfileDefineChipMosaic(config, input->fpa, "PSVIDEOPHOT.CHIP");
    if (!chipImage) {
        psError(PS_ERR_IO, false, _("Unable to generate new file from PSVIDEOPHOT.CHIP"));
        psFree(options);
        return NULL;
    }
    if (chipImage->type != PM_FPA_FILE_OBJ) {
        psError(PS_ERR_IO, true, "PSVIDEOPHOT.CHIP is not of type OBJ");
        psFree(options);
        return NULL;
    }
    

    // chipImage    -> psphotInput  (pmFPAfileDefineFromFile)       : fpa is constructed
    // psphotInput  -> psphotOutput (pmFPAfileDefineOutputFromFile) : fpa is equated
    // psphotOutput -> psastroInput (pmFPAfileDefineInput)          : fpa is ref-copied
    // psastroInput -> psastroModel (pmFPAfileDefineFromArgs        : fpa is ref-copied
    // psastroInput -> psastroModel (pmFPAfileDefineFromConf        : fpa is constructed
    // psastroInput -> psastroModel (pmFPAfileDefineFromDetDB       : fpa is constructed (pmDetrendSelect uses input concepts )

    // For photometry, we operate on the chip-mosaicked image
    // we create a copy of the mosaicked image for psphot so we can write out a clean image
    

        // this file is just used as a carrier; output files (eg, PSPHOT.RESID) are defined by
        // psphotDefineFiles
        pmFPAfile *psphotInput = pmFPAfileDefineFromFile (config, chipImage, 1, 1, "PSPHOT.INPUT");
        PS_ASSERT (psphotInput, false);

        // specify the number of psphot input images
        psMetadataAddS32 (config->arguments, PS_LIST_TAIL, "PSPHOT.INPUT.NUM", PS_META_REPLACE, "number of inputs", 1);

        // define associated psphot input/output files
        if (!psphotDefineFiles (config, psphotInput)) {
            psError(PSPHOT_ERR_CONFIG, false,
                    "Trouble defining the additional input/output files for psphot");
            return false;
        }
    

    // For photometry, we operate on the chip-mosaicked image
    

    // save any of these files?
    outImage->save   = options->BaseFITS;
    

    chipImage->save  = options->ChipFITS;
    

    
    // outImage is used as a carrier: input to chipImage -> require the data to remain at the CHIP level
    outImage->freeLevel = PS_MIN(outImage->freeLevel, PM_FPA_LEVEL_CHIP);
    outImage->dataLevel = outImage->freeLevel;
    outImage->fileLevel = PS_MIN(outImage->fileLevel, outImage->dataLevel);

    // outMask and outVariance must be freed at the same level as outImage (all freed by pmFPAFreeData)
    

    // the input data is the same as the outImage data : force the free levels to match
    input->freeLevel = PS_MIN(outImage->freeLevel, input->freeLevel);

    // define the binned target files (which may just be carriers for some camera configurations)
    
    // Chip selection: turn on only the chips specified (pass status to suppress missing-key log msg)
    char *chipLine = psMetadataLookupStr(&status, config->arguments, "CHIP_SELECTIONS");
    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(PS_ERR_IO, false, "Chip number %d doesn't exist in camera.\n", chipNum);
                psFree(options);
                return false;
            }
        }
    }
    psFree (chips);

    if (psMetadataLookupBool(NULL, config->arguments, "INPUT_IS_FRINGE")) {
        // It's a fringe file, so change the file type
        input->type = PM_FPA_FILE_FRINGE;
        outImage->type = PM_FPA_FILE_FRINGE;
    }
    if (psMetadataLookupBool(NULL, config->arguments, "INPUT_IS_DARK")) {
        // It's a dark file, so change the file type
        input->type = PM_FPA_FILE_DARK;
        outImage->type = PM_FPA_FILE_DARK;
        // Turn off compression --- there are just too many nasties that can happen
        psFree(outImage->compression);
        outImage->compression = NULL;
        psFree(outImage->options);
        outImage->options = NULL;
    }

    // Turn off mask and variance output if we're not doing anything interesting
    
    if (psTraceGetLevel("psvideophot.config") > 0) {
        // Get a look inside all the files.
        psMetadataIterator *filesIter = psMetadataIteratorAlloc(config->files, PS_LIST_HEAD, NULL);
        psMetadataItem *item;               // Item from iteration
        fprintf(stderr, "Files:\n");
        while ((item = psMetadataGetAndIncrement(filesIter))) {
            pmFPAfile *file = item->data.V; // File of interest
            fprintf(stderr, "%s: %p %p %p (%p) %p\n", file->name,
                    file->src, file->fpa,
                    file->camera, file->fpa->camera, file->format);
        }
        psFree(filesIter);
    }

    // Change the input dark type between the old (IMAGE) and new (multi-DARK).
    // Hopefully this is a temporary change until we all move over to using the new dark types
    bool mdok;                          // Status of MD lookup
    if (options->doDark && psMetadataLookupBool(&mdok, recipe, "OLDDARK")) {
        pmFPAfile *dark = psMetadataLookupPtr(NULL, config->files, "PSVIDEOPHOT.DARK");
        assert(dark);
        dark->type = PM_FPA_FILE_IMAGE;
    }

    return (options);
}
