// Copyright (C) 2006  Paul A. Price (price@ifa.hawaii.edu)
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

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

#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#include "pois.h"

void help(void)
{
    fprintf (stderr, "POIS: Pan-STARRS (or Pricey's) Optimal Image Subtraction\n"
             "Usage: pois [-h] [-v] [-k X Y] [-t T] [-s S1 S2] [-b B1 B2] [-B BG] [-o N] [-n NSTAMPS] [-S STAMPS] [-i ITER] [-r REJ] [-m] REF IN OUT\n"
             "where\n"
             "\t-h         Help (this info)\n"
             "\t-v         Increase verbosity level\n"
             "\t-k X Y     Kernel half-size in x and y (5)\n"
             "\t-t T       Threshold for stamps on reference image (0)\n"
             "\t-s S1 S2   Saturation level for reference (S1) and input (S2) (50000)\n"
             "\t-b B1 B2   Bad level for both images (0)\n"
             "\t-B BG      Level to add to background to get above zero (0)\n"
             "\t-o ORDER   Order of spatial variations in the kernel (0)\n"
             "\t-n NSTAMPS Number of stamps in each dimension (5)\n"
             "\t-S STAMPS  File from which to read stamps\n"
             "\t-R         Reverse the sense of the subtraction (REF - IN)\n"
             "\t-i ITER    Number of rejection iterations (10)\n"
             "\t-r REJ     Rejection level in standard deviations (2.5)\n"
             "\t-m         Output mask frame (OUT.mask)\n"
             "\tREF        Reference image\n"
             "\tIN         Input image (to be matched to REF)\n"
             "\tOUT        Output image\n"
        );
}

poisConfig *poisParseConfig(int argc, // Number of command-line arguments
                            char **argv // Command-line arguments
    )
{
    poisConfig *config;                 // Configuration values

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

    /* Initialise configuration */
    config = (poisConfig *) psAlloc(sizeof(poisConfig));
    config->verbose = 0;
    config->refFile = NULL;
    config->inFile = NULL;
    config->outFile = NULL;
    config->xKernel = 5;
    config->yKernel = 5;
    config->footprint = 15;
    config->threshold = 0.0;
    config->refSat = 60000.0;
    config->inSat = 60000.0;
    config->refBad = 0.0;
    config->inBad = 0.0;
    config->background = 0.0;
    config->spatialOrder = 0;
    config->nsx = 5;
    config->nsy = 5;
    config->numIter = 10;
    config->sigmaRej = 2.5;
    config->penalty = 0.0;
    config->stampFile = NULL;
    config->reverse = false;
    config->mask = false;

    /* Parse command-line arguments using getopt */
    while ((opt = getopt(argc, argv, "hvRmk:f:q:t:s:o:b:B:n:i:r:p:S:")) != -1) {
        switch (opt) {
          case 'h':
            help();
            exit(EXIT_SUCCESS);
          case 'v':
            config->verbose++;
            break;
          case 'k':
            if ((sscanf(argv[optind-1], "%d", &config->xKernel) != 1) ||
                (sscanf(argv[optind++], "%d", &config->yKernel) != 1)) {
                /*
                  Note: incrementing optind, so I can read more than
                  one parameter.
                */
                help();
                exit(EXIT_FAILURE);
            }
            break;
          case 'f':
            if (sscanf(optarg, "%d", &config->footprint) != 1) {
                help();
                exit(EXIT_FAILURE);
            }
            break;
          case 't':
            if (sscanf(optarg, "%f", &config->threshold) != 1) {
                help();
                exit(EXIT_FAILURE);
            }
            break;
          case 's':
            if ((sscanf(argv[optind-1], "%f", &config->refSat) != 1) ||
                (sscanf(argv[optind++], "%f", &config->inSat) != 1)) {
                /*
                  Note: incrementing optind, so I can read more than
                  one parameter.
                */
                help();
                exit(EXIT_FAILURE);
            }
            break;
          case 'o':
            if (sscanf(optarg, "%d", &config->spatialOrder) != 1) {
                help();
                exit(EXIT_FAILURE);
            }
            break;
          case 'b':
            if ((sscanf(argv[optind-1], "%f", &config->refBad) != 1) ||
                (sscanf(argv[optind++], "%f", &config->inBad) != 1)) {
                /*
                  Note: incrementing optind, so I can read more than
                  one parameter.
                */
                help();
                exit(EXIT_FAILURE);
            }
            break;
          case 'B':
            if (sscanf(optarg, "%f", &config->background) != 1) {
                help();
                exit(EXIT_FAILURE);
            }
            break;
          case 'n':
            if (sscanf(argv[optind-1], "%d", &config->nsx) != 1) {
                help();
                exit(EXIT_FAILURE);
            }
            config->nsy = config->nsx;
            break;
          case 'i':
            if (sscanf(argv[optind-1], "%d", &config->numIter) != 1) {
                help();
                exit(EXIT_FAILURE);
            }
            break;
          case 'r':
            if (sscanf(argv[optind-1], "%f", &config->sigmaRej) != 1) {
                help();
                exit(EXIT_FAILURE);
            }
            break;
          case 'p':
            if (sscanf(argv[optind-1], "%f", &config->penalty) != 1) {
                help();
                exit(EXIT_FAILURE);
            }
            break;
          case 'S':
            config->stampFile = argv[optind-1];
            config->threshold = -INFINITY;
            break;
          case 'R':
            config->reverse = true;
            break;
          case 'm':
            config->mask = true;
            break;
          default:
            help();
        }
    }

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

    config->refFile = argv[0];
    config->inFile = argv[1];
    config->outFile = argv[2];

    return config;
}

