#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <string.h>
#include "stac.h"

void help(const char *name)
{
    fprintf (stderr, "STAC: Simultaneous Telescope Array Combination\n"
	     "Usage: %s [-h] [-v] [-g GAIN] [-r RN] [-o NX NY] [-s SAT] [-b BAD] [-k REJ] [-k FRAC] OUT IN1 IN2...\n"
	     "where\n"
	     "\t-h           Help (this info)\n"
	     "\t-v           Increase verbosity level\n"
	     "\t-g           Gain (e/ADU) for detectors\n"
	     "\t-r           Read noise (e) for detectors\n"
	     "\t-o NX NY     Size of output image (512, 512)\n"
	     "\t-s SAT       Saturation level (65536)\n"
	     "\t-b BAD       Bad level (0)\n"
	     "\t-k REJ       Rejection level (k-sigma; 3.5)\n"
	     "\t-f FRAC      Fraction of pixel to be marked before considered bad (0.8)\n"
	     "\tOUT          Output image\n"
	     "\tIN1, IN2...  Input images, which have associated .map files.\n",
	     name
	);
}


stacConfig *stacConfigAlloc(void)
{
    // Allocate memory
    stacConfig *config = (stacConfig*) psAlloc(sizeof(stacConfig));
    // Set defaults
    config->verbose = 0;
    config->gain = 1.0;
    config->readnoise = 0.0;
    config->inputs = NULL;
    config->output = NULL;
    config->outnx = 512;
    config->outny = 512;
    config->saturated = 65536.0;
    config->bad = 0.0;
    config->reject = 2.75;
    config->frac = 0.5;

    return config;
}


void stacConfigFree(stacConfig *config)
{
    // Free the vector, if necessary
    if (config->inputs) {
	psFree(config->inputs);
    }
    // Free everything
    psFree(config);
}


stacConfig *stacParseConfig(int argc,	// Number of command-line arguments
			    char **argv // Command-line arguments
    )
{
    stacConfig *config = stacConfigAlloc(); // Configuration values
    const char *programName = argv[0];	// Program name

    /* Variables for getopt */
    int opt;   /* Option, from getopt */
    extern char *optarg;   /* Argument accompanying switch */
    extern int optind;   /* getopt variables */

    /* Parse command-line arguments using getopt */
    while ((opt = getopt(argc, argv, "hvg:r:o:s:b:k:f:")) != -1) {
        switch (opt) {
	  case 'h':
	    help(programName);
	    exit(EXIT_SUCCESS);
	  case 'v':
            config->verbose++;
            break;
	  case 'g':
	    if (sscanf(optarg, "%f", &config->gain) != 1) {
		help(programName);
	    }
	    break;
	  case 'r':
	    if (sscanf(optarg, "%f", &config->readnoise) != 1) {
		help(programName);
	    }
	    break;
	  case 'o':
            if ((sscanf(argv[optind-1], "%d", &config->outnx) != 1) ||
                (sscanf(argv[optind++], "%d", &config->outny) != 1)) {
                /*
                  Note: incrementing optind, so I can read more than
                  one parameter.
                */
                help(programName);
                exit(EXIT_FAILURE);
            }
	    break;
	  case 's':
	    if (sscanf(optarg, "%f", &config->saturated) != 1) {
		help(programName);
	    }
	    break;
	  case 'b':
	    if (sscanf(optarg, "%f", &config->bad) != 1) {
		help(programName);
	    }
	    break;
	  case 'k':
	    if (sscanf(optarg, "%f", &config->reject) != 1) {
		help(programName);
	    }
	    break;
	  case 'f':
	    if (sscanf(optarg, "%f", &config->frac) != 1) {
		help(programName);
	    }
	    break;
	  default:
	    help(programName);
	}
    }

    /* Get the remaining, mandatory values */
    argc -= optind;
    argv += optind;
    if (argc < 2) {
        help(programName);
        exit(EXIT_FAILURE);
    }

    config->output = argv[0];		// Output file
    // Get the input files
    config->inputs = psArrayAlloc(argc-1);
    for (int i = 1; i < argc; i++) {
	config->inputs->data[i-1] = psAlloc(strlen(argv[i]));
	strncpy(config->inputs->data[i-1], argv[i], strlen(argv[i]));
    }

    // Debugging output
    psTrace("stac.config", 8, "Parsed command line for configuration\n");
    psTrace("stac.config", 9, "Verbosity level: %d\n",config->verbose);
    psTrace("stac.config", 9, "%d inputs:\n",config->inputs->n);
    for (int i = 0; i < config->inputs->n; i++) {
	psTrace("stac.config", 9, "\t%s\n", config->inputs->data[i]);
    }
    psTrace("stac.config", 9, "Output file is %s\n",config->output);
    psTrace("stac.config", 9, "Output file size is %dx%d\n", config->outnx, config->outny);

    return config;
}

