# include "ppSimSequence.h"
# include <sys/stat.h>

int main (int argc, char **argv) {

    bool status;
    int argNum;
    char line[1024];
    unsigned int nFail;

    psLibInit(NULL);

    char *dbname = NULL;
    if ((argNum = psArgumentGet (argc, argv, "-dbname"))) { 
        psArgumentRemove(argNum, &argc, argv);
	dbname = psStringCopy (argv[argNum]);
        psArgumentRemove(argNum, &argc, argv);
    }

    char *path = NULL;
    if ((argNum = psArgumentGet (argc, argv, "-path"))) { 
        psArgumentRemove(argNum, &argc, argv);
	path = psStringCopy (argv[argNum]);
        psArgumentRemove(argNum, &argc, argv);
	sprintf (line, "mkdir -p %s", path);
	system (line);
    }

    char *workdir = NULL;
    if ((argNum = psArgumentGet (argc, argv, "-workdir"))) { 
        psArgumentRemove(argNum, &argc, argv);
	workdir = psStringCopy (argv[argNum]);
        psArgumentRemove(argNum, &argc, argv);
    }

    char *dvodb = NULL;
    if ((argNum = psArgumentGet (argc, argv, "-dvodb"))) { 
        psArgumentRemove(argNum, &argc, argv);
	dvodb = psStringCopy (argv[argNum]);
        psArgumentRemove(argNum, &argc, argv);
    }

    char *tess_id = NULL;
    if ((argNum = psArgumentGet (argc, argv, "-tess_id"))) { 
        psArgumentRemove(argNum, &argc, argv);
	tess_id = psStringCopy (argv[argNum]);
        psArgumentRemove(argNum, &argc, argv);
    }

    char *basename = NULL;
    if ((argNum = psArgumentGet (argc, argv, "-basename"))) { 
        psArgumentRemove(argNum, &argc, argv);
	basename = psStringCopy (argv[argNum]);
        psArgumentRemove(argNum, &argc, argv);
    } else {
	basename = psStringCopy ("simtest");
    }

    char *label = NULL;
    if ((argNum = psArgumentGet (argc, argv, "-label"))) { 
        psArgumentRemove(argNum, &argc, argv);
	label = psStringCopy (argv[argNum]);
        psArgumentRemove(argNum, &argc, argv);
    }

    if (argc != 4) {
	fprintf (stderr, "USAGE: ppSimSequence (sequence) (simulate) (inject) [options]\n");
	fprintf (stderr, "generates a set of simulated data defined by the sequence file\n");
	fprintf (stderr, " (sequence) : a mdc-file describing the desired image sequences\n");
	fprintf (stderr, " (simulate) : an output file with commands to generate the images\n");
	fprintf (stderr, " (inject)   : an output file with commands to inject the images into the pipeline\n");
	fprintf (stderr, "options:\n");
	fprintf (stderr, " -dbname (dbname)\n");
	fprintf (stderr, " -path (path)\n");
	fprintf (stderr, " -workdir (workdir)\n");
	fprintf (stderr, " -basename (basename)\n");
	fprintf (stderr, " -label (label)\n");
	fprintf (stderr, " -dvodb (dvodb)\n");
	fprintf (stderr, " -tess_id (tess_id)\n");
	exit (2);
    }

    // load the sequence description
    psMetadata *config = psMetadataConfigRead (NULL, &nFail, argv[1], false);
    if (!config) {
	psLogMsg ("ppSimSequence", PS_LOG_WARN, "unable to read sequence description from %s", argv[1]);
	exit (1);
    }
    
    FILE *simfile = fopen (argv[2], "w");
    if (!simfile) {
	psLogMsg ("ppSimSequence", PS_LOG_WARN, "unable to open %s for output", argv[2]);
	exit (1);
    }
	
    FILE *inject = fopen (argv[3], "w");
    if (!inject) {
	psLogMsg ("ppSimSequence", PS_LOG_WARN, "unable to open %s for output", argv[3]);
	exit (1);
    }

    // build the base injectCommand string
    psString injectCommand = psStringCopy ("ipp_inject_fileset.pl --telescope SIMTEST");
    if (dbname)  psStringAppend (&injectCommand, " --dbname %s",  dbname);
    if (workdir) psStringAppend (&injectCommand, " --workdir %s", workdir);
    if (label)   psStringAppend (&injectCommand, " --label %s", label);
    if (dvodb)   psStringAppend (&injectCommand, " --dvodb %s", dvodb);
    if (tess_id) psStringAppend (&injectCommand, " --tess_id %s", tess_id);

    unsigned long seed = psMetadataLookupS32 (&status, config, "RND_SEED");
    if (!status) seed = 0;
    psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS, seed);

    psMetadataItem *item = psMetadataLookup (config, "SEQUENCE");
    if (item == NULL) {
	psLogMsg ("ppSimSequence", PS_LOG_WARN, "missing SEQUENCE description");
	exit (1);
    }

    psArray *sequences = NULL;
    if (item->type == PS_DATA_METADATA) {
	sequences = psArrayAlloc(1);
	sequences->data[0] = psMemIncrRefCounter (item->data.V);
    } else {
	if (item->type != PS_DATA_METADATA_MULTI)  {
	    psLogMsg ("ppSimSequence", PS_LOG_WARN, "SEQUENCE is not MULTI or METADATA");
	    exit (1);
	}
	sequences = psListToArray (item->data.list);
    }

    for (int i = 0; i < sequences->n; i++) {

	// XXX this is not obvious: the entry on the list is a metadata item 
	// containing the psMetadata :: why is this not just a metadata?
	psMetadataItem *item = sequences->data[i];
	psMetadata *sequence = item->data.V;
	// double check item type?
      
	// determine the sequence type
	char *type = psMetadataLookupStr (&status, sequence, "OBSTYPE");
	if (!status) {
	    psLogMsg ("ppSimSequence", PS_LOG_WARN, "SEQUENCE %d is missing a type", i);
	    exit (1);
	}

	if (!strcasecmp (type, "BIAS")) {
	    ppSimSequenceBias (simfile, inject, sequence, i, rng, path, basename, injectCommand);
	    continue;
	}
	if (!strcasecmp (type, "DARK")) {
	    ppSimSequenceDark (simfile, inject, sequence, i, rng, path, basename, injectCommand);
	    continue;
	}
	if (!strcasecmp (type, "FLAT")) {
	    ppSimSequenceFlat (simfile, inject, sequence, i, rng, path, basename, injectCommand);
	    continue;
	}
	if (!strcasecmp (type, "OBJECT")) {
	    ppSimSequenceObject (simfile, inject, sequence, i, rng, path, basename, injectCommand);
	    continue;
	}

	psLogMsg ("ppSimSequence", PS_LOG_WARN, "SEQUENCE %d has an unknown type: %s", i, type);
	exit (1);
    }

    exit (0);
}
