# include "psphotStandAlone.h"

static void writeHelpInfo(const char* program, pmConfig* config, FILE* ofile)
{
  fprintf(ofile,
	  "Usage: one of the following\n"
	  "%s -file fname1[,fname2,...] -mask maskfile1[,maskfile2,...]\n"
	  "     -variance varfile1[,varfile2,...] OutFileBaseName\n"
	  "\n"
	  "%s -list FileNameList [-masklist MaskFileNameList] \n"
	  "     -variancelist VarFileNameList OutFileBaseName\n"
	  "\n"
	  "%s -help\n"
	  "\n"
	  "%s -version\n"
	  "\n"
	  "where:\n"
	  "  FileNameList is a text file containing filenames, one per line\n"
	  "  MaskFileNameList is a text file of mask filenames, one per line\n"
	  "  VarFileNameList is a text file of variance filenames, one per line\n"
	  "  OutFileBaseName is the 'root name' for output files\n"
	  "\n"
	  "additional options:\n"
	  "  -modeltest xObj yObj [-model DEFAULT|ModelName] \n"
	  "        [-fitmode DEFAULT|PSF|CONV] [-fitset FitFileName]\n"
	  "     Test fit for object at the given coordinates.  ModelName\n"
	  "     is one of PS_MODEL_GAUSS, PS_MODEL_PGAUSS, PS_MODEL_QGAUSS,\n"
	  "     PS_MODEL_RGAUSS, PS_MODEL_PS1_V1, or PS_MODEL_SERSIC.\n"
	  "     FitFileName is a file of x,y,Io triples.\n"
	  "  -psf PsfFile1[,PsfFile2,...] or -psflist PsfFileNameList\n"
	  "     specify PSF rather than letting %s estimate it\n"
	  "  -src SrcFile1[,SrcFile2,...] or -srclist SrcFileNameList\n"
	  "     specify additional sources for PSF generation\n"
	  "  -chip nn[,nn,...]\n"
	  "     select detector chips to process; default is all.\n"
	  "     Indices correspond to zero-based offset in the FPA metadata table.\n"
	  "  -photcode PhotoCodeName\n"
	  "     specify photocode\n"
	  "  -region RegionString\n"
	  "     specify analysis region.  String is of form '[x0:x1,y0:y1]'\n"
	  "     To use this option you must define a default in psphot.config\n"
	  "  -visual\n"
	  "     turns on interactive display mode\n"
	  "  -dumpconfig CfgFileName\n"
          "     causes config info to be dumped to the named file.\n"
	  "  -break NOTHING|BACKMDL|PEAKS|MOMENTS|PSFMODEL|ENSEMBLE|PASS1\n"
	  "     choose a point at which to exit processing early\n"
	  "  -nthreads n\n"
	  "     set number of parallel threads of execution\n"
	  "  -F OldFileRule ReplacementFileRule\n"
	  "     change file naming rule; e.g. '-F PSPHOT.OUTPUT PSPHOT.OUT.CMF.MEF'\n"
	  "  -D name stringval\n"
	  "     set a string-valued config parameter\n"
	  "  -Di name intval\n"
	  "     set an integer-valued config parameter\n"
	  "  -Df name fval\n"
	  "     set a float-valued config parameter\n"
	  "  -Db name boolval\n"
	  "     set a boolean-valued config parameter\n"
	  "  -v, -vv, -vvv\n"
	  "     set increasing levels of verbosity\n"
	  "  -logfmt FormatString\n"
	  "     set format string used for log messages\n"
	  "  -trace Fac Lvl\n"
	  "     set tracing for facility Fac to integer Lvl, e.g. '-trace err 10'\n"
	  "  -trace-levels\n"
	  "     print current trace levels\n",
	  program,program,program,program,program);
    psFree(config);
    pmConfigDone();
    psLibFinalize();
    exit(PS_EXIT_SUCCESS);
}

static void usage(const char *program,  // Name of the program
                  psMetadata *arguments, // Command-line arguments
                  pmConfig *config,      // Configuration
		  int exitCode
		  ) 
{
  fprintf(stderr,
	  "Usage: one of the following\n"
	  "%s -file fname1[,fname2,...] -mask maskfile1[,maskfile2,...]\n"
	  "     -variance varfile1[,varfile2,...] OutFileBaseName\n"
	  "\n"
	  "%s -list FileNameList [-masklist MaskFileNameList] \n"
	  "     -variancelist VarFileNameList OutFileBaseName\n"
	  "\n"
	  "Try '%s -help' for more options and explanation\n",
	  program,program,program);
    if (exitCode != PS_EXIT_SUCCESS)
      psErrorStackPrint(stderr, "Error reading arguments\n");
    psFree(config);
    pmConfigDone();
    psLibFinalize();
    exit(exitCode);
}

pmConfig *psphotArguments(int argc, char **argv) {

    int N;
    bool status;

    // load config data from default locations
    pmConfig *config = pmConfigRead(&argc, argv, PSPHOT_RECIPE);
    if (config == NULL) {
        psError(PSPHOT_ERR_CONFIG, false, "Can't read site configuration");
	exit(PS_EXIT_CONFIG_ERROR);
    }

    PSARGUMENTS_INSTANTIATE_GENERICS( psphot, config, argc, argv );

    // save the following additional recipe values based on command-line options
    // these options override the PSPHOT recipe values loaded from recipe files
    psMetadata *options = pmConfigRecipeOptions (config, PSPHOT_RECIPE);

    // Number of threads is handled
    PSARGUMENTS_INSTANTIATE_THREADSARG( psphot, config, argc, argv )

    // run the test model (requires X,Y coordinate)
    if ((N = psArgumentGet (argc, argv, "-modeltest"))) {
        if (argc<=N+2) {
          psError(PSPHOT_ERR_ARGUMENTS, true, 
		  "Expected to see 2 more arguments; saw %d", argc - 1);
	  exit(PS_EXIT_CONFIG_ERROR);
	}

        psMetadataAddBool (options, PS_LIST_TAIL, "TEST_FIT",   0, "", true);
        psMetadataAddF32  (options, PS_LIST_TAIL, "TEST_FIT_X", 0, "", atof(argv[N+1]));
        psMetadataAddF32  (options, PS_LIST_TAIL, "TEST_FIT_Y", 0, "", atof(argv[N+2]));

        psArgumentRemove (N, &argc, argv);
        psArgumentRemove (N, &argc, argv);
        psArgumentRemove (N, &argc, argv);

        // specify the modeltest model
        if ((N = psArgumentGet (argc, argv, "-model"))) {
	    if (argc<=N+1) {
	      psError(PSPHOT_ERR_ARGUMENTS, true, 
		      "Expected to see 1 more argument; saw %d", argc - 1);
	      exit(PS_EXIT_CONFIG_ERROR);
	    }
            psArgumentRemove (N, &argc, argv);
            psMetadataAddStr (options, PS_LIST_TAIL, "TEST_FIT_MODEL", 0, "", argv[N]);
            psArgumentRemove (N, &argc, argv);
        }

        // specify the test fit mode
        if ((N = psArgumentGet (argc, argv, "-fitmode"))) {
	    if (argc<=N+1) {
	      psError(PSPHOT_ERR_ARGUMENTS, true, 
		      "Expected to see 1 more argument; saw %d", argc - 1);
	      exit(PS_EXIT_CONFIG_ERROR);
	    }
            psArgumentRemove (N, &argc, argv);
            psMetadataAddStr (options, PS_LIST_TAIL, "TEST_FIT_MODE", 0, "", argv[N]);
            psArgumentRemove (N, &argc, argv);
        }
        if ((N = psArgumentGet (argc, argv, "-fitset"))) {
	    if (argc<=N+1) {
	      psError(PSPHOT_ERR_ARGUMENTS, true, 
		      "Expected to see 1 more argument; saw %d", argc - 1);
	      exit(PS_EXIT_CONFIG_ERROR);
	    }
            psArgumentRemove (N, &argc, argv);
            psMetadataAddStr (options, PS_LIST_TAIL, "TEST_FIT_SET", 0, "", argv[N]);
            psArgumentRemove (N, &argc, argv);
        }
    }

    // photcode : used in output to supplement header data (argument or recipe?)
    if ((N = psArgumentGet (argc, argv, "-photcode"))) {
        if (argc<=N+1) {
	  psError(PSPHOT_ERR_ARGUMENTS, true, 
		  "Expected to see 1 more argument; saw %d", argc - 1);
	  exit(PS_EXIT_CONFIG_ERROR);
	}
        psArgumentRemove (N, &argc, argv);
        psMetadataAddStr (options, PS_LIST_TAIL, "PHOTCODE", PS_META_REPLACE, "", argv[N]);
        psArgumentRemove (N, &argc, argv);
    }

    // visual : interactive display mode
    if ((N = psArgumentGet (argc, argv, "-visual"))) {
        psArgumentRemove (N, &argc, argv);
        pmVisualSetVisual(true);
    }

    // break : used from recipe throughout psphotReadout
    if ((N = psArgumentGet (argc, argv, "-break"))) {
	if (argc<=N+1) {
	  psError(PSPHOT_ERR_ARGUMENTS, true, 
		  "Expected to see 1 more argument; saw %d", argc - 1);
	  exit(PS_EXIT_CONFIG_ERROR);
	}
        psArgumentRemove (N, &argc, argv);
        psMetadataAddStr (options, PS_LIST_TAIL, "BREAK_POINT", PS_META_REPLACE, "", argv[N]);
        psArgumentRemove (N, &argc, argv);
    }

    // analysis region : overrides recipe value, used in psphotReadout/psphotEnsemblePSF
    if ((N = psArgumentGet (argc, argv, "-region"))) {
	if (argc<=N+1) {
	  psError(PSPHOT_ERR_ARGUMENTS, true, 
		  "Expected to see 1 more argument; saw %d", argc - 1);
	  exit(PS_EXIT_CONFIG_ERROR);
	}
        psArgumentRemove (N, &argc, argv);
        psMetadataAddStr (options, PS_LIST_TAIL, "ANALYSIS_REGION", 0, "", argv[N]);
        psArgumentRemove (N, &argc, argv);
    }

    // chip selection is used to limit chips to be processed
    if ((N = psArgumentGet (argc, argv, "-chip"))) {
	if (argc<=N+1) {
	  psError(PSPHOT_ERR_ARGUMENTS, true, 
		  "Expected to see 1 more argument; saw %d", argc - 1);
	  exit(PS_EXIT_CONFIG_ERROR);
	}
        psArgumentRemove (N, &argc, argv);
        psMetadataAddStr (config->arguments, PS_LIST_TAIL, "CHIP_SELECTIONS", PS_DATA_STRING, "", argv[N]);
        psArgumentRemove (N, &argc, argv);
    }

    // if these command-line options are supplied, load the file name lists into config->arguments
    // override any configuration-specified source for these files
    //
    pmConfigFileSetsMD (config->arguments, &argc, argv, "MASK",   "-mask",   "-masklist");
    pmConfigFileSetsMD (config->arguments, &argc, argv, "VARIANCE", "-variance", "-variancelist");
    pmConfigFileSetsMD (config->arguments, &argc, argv, "PSPHOT.PSF", "-psf", "-psflist");
    pmConfigFileSetsMD (config->arguments, &argc, argv, "SRC",    "-src",    "-srclist");

    if (argc == 1) {
        psError(PSPHOT_ERR_ARGUMENTS, true, "Too few arguments: %d", argc);
	usage(argv[0], config->arguments, config, PS_EXIT_CONFIG_ERROR);
    }

    if (psArgumentGet(argc, argv, "-help")
	|| psArgumentGet(argc, argv, "-h"))
      writeHelpInfo(argv[0], config, stdout);
      
    // the input file is a required argument; if not found, we will exit
    status = pmConfigFileSetsMD (config->arguments, &argc, argv, "INPUT", "-file", "-list");
    if (!status) {
        psError(PSPHOT_ERR_ARGUMENTS, false, "pmConfigFileSetsMD failed to parse arguments");
	usage(argv[0], config->arguments, config, PS_EXIT_CONFIG_ERROR);
    }

    if (argc != 2) {
        psError(PSPHOT_ERR_ARGUMENTS, true, "Expected to see one more argument; saw %d", argc - 1);
	usage(argv[0], config->arguments, config, PS_EXIT_CONFIG_ERROR);
    }

    // output position is fixed
    psMetadataAddStr (config->arguments, PS_LIST_TAIL, "OUTPUT", 0, "", argv[1]);

    psTrace("psphot", 1, "Done with psphotArguments...\n");
    return (config);
}
