# include "ppSim.h"

// XXX this function forces us to define the camera (on the command line) and format (via the
// PPSIM.OUTPUT entry).  In this case, we need to set config->format,formatName based on these
// values.  This will be a problem when we want to load an input image (in order to add fake
// stars).  We will need to add some logic in ppSimArguments to distinguish the cases of 1)
// input image and 2) specified camera

pmFPAfile *ppSimCreate(pmConfig *config)
{
    bool status;
    bool simImage = false;
    PS_ASSERT_PTR_NON_NULL(config, NULL);
    pmFPA *fpa = NULL;

    // the input image defines the camera.  if it is not supplied, the user must have
    // supplied a camera and other metadata on the command line
    pmFPAfile *input = pmFPAfileDefineFromArgs (&status, config, "PPIMAGE.INPUT", "INPUT");
    if (!input) {
	simImage = true;
	fpa = pmFPAConstruct(config->camera); // FPA to contain the observation
	if (!fpa) {
	    psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to construct an FPA from camera configuration.");
	    return NULL;
	}
    } else {
	simImage = false;
	if (input->type != PM_FPA_FILE_IMAGE) {
	    psError(PS_ERR_IO, true, "PPIMAGE.INPUT is not of type IMAGE");
	    return NULL;
	}
	fpa = input->fpa;
    }

    pmFPAfile *file = pmFPAfileDefineOutput(config, fpa, OUTPUT_FILE);
    if (!file) {
        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to create output file from %s.  "
                "Did you forget to specify the format?", OUTPUT_FILE);
        return NULL;
    }
    if (file->type != PM_FPA_FILE_IMAGE) {
        psError(PS_ERR_BAD_PARAMETER_TYPE, true, "%s type is not IMAGE", OUTPUT_FILE);
	psFree(fpa);
        psFree(file);
        return NULL;
    }
    file->save = true;

    config->format = psMemIncrRefCounter (file->format);
    config->formatName = psStringCopy (file->formatName);

    // have we supplied a psf model?
    if (psMetadataLookupPtr(NULL, config->arguments, "PSPHOT.PSF")) {
	bool status = false;

	// tie the psf file to the chipMosaic 
        pmFPAfileBindFromArgs(&status, file, config, "PSPHOT.PSF.LOAD", "PSPHOT.PSF");
        if (!status) {
            psError(PS_ERR_UNKNOWN, false, "Failed to find/build PSPHOT.PSF.LOAD");
	    psFree(fpa);
	    psFree(file);
            return NULL;
        }
    }

    // XXX only invoke this code for OBJECT types of images
    // PPSIM.SOURCES carries the constructed, fake sources with their true parameters
    pmFPAfile *simSources = pmFPAfileDefineOutput (config, file->fpa, "PPSIM.SOURCES");
    if (!simSources) {
        psError(PS_ERR_UNKNOWN, false, "Cannot find a rule for PPSIM.SOURCES");
        return false;
    }
    simSources->save = true;

    // if we have loaded an input image, we do not need to populate the fpa
    if (!simImage) {
	return file;
    }

    pmFPALevel phuLevel = pmFPAPHULevel(file->format); // Level at which PHU goes

    pmFPAview *view = pmFPAviewAlloc(0);// View for current level

    if (phuLevel == PM_FPA_LEVEL_FPA) {
        if (!pmFPAAddSourceFromView(fpa, "Simulation", view, file->format)) {
            psError(PS_ERR_UNKNOWN, false, "Unable to add PHU to FPA.");
            psFree(fpa);
            psFree(view);
	    psFree(file);
            return NULL;
        }
    }

    pmChip *chip;                       // Chip from FPA
    while ((chip = pmFPAviewNextChip(view, fpa, 1))) {
        if (phuLevel == PM_FPA_LEVEL_CHIP) {
            if (!pmFPAAddSourceFromView(fpa, "Simulation", view, file->format)) {
                psError(PS_ERR_UNKNOWN, false, "Unable to add PHU to FPA.");
                psFree(fpa);
                psFree(view);
		psFree(file);
                return NULL;
            }
        }

        pmCell *cell;                   // Cell from chip
        while ((cell = pmFPAviewNextCell(view, fpa, 1))) {
            if (phuLevel == PM_FPA_LEVEL_CELL) {
                if (!pmFPAAddSourceFromView(fpa, "Simulation", view, file->format)) {
                    psError(PS_ERR_UNKNOWN, false, "Unable to add PHU to FPA.");
                    psFree(fpa);
                    psFree(view);
		    psFree(file);
                    return NULL;
                }
            }
        }
    }

    psFree(fpa);
    psFree(view);

    return file;
}
