# include "relastro.h"
void usage (void);
void usage_client (void);
void usage_merge_source (void);
void usage_merge_source_id (char *name);

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

  int N;
  double trange;
  char *endptr;

  /* possible operations */
  FIT_TARGET = TARGET_NONE;
  RELASTRO_OP = OP_NONE;
  FIT_MODE = FIT_AVERAGE;

  OBJ_ID_SRC = OBJ_ID_DST = 0;
  CAT_ID_SRC = CAT_ID_DST = 0;

  if ((N = get_argument (argc, argv, "-merge-source"))) {
    if (N > argc - 6) usage_merge_source();
    if (strcmp(argv[N+3], "into")) usage_merge_source();
    RELASTRO_OP = OP_MERGE_SOURCE;
    remove_argument (N, &argc, argv);
    OBJ_ID_SRC = strtol(argv[N], &endptr, 0);
    if (*endptr) usage_merge_source_id (argv[N]); 
    remove_argument (N, &argc, argv);
    CAT_ID_SRC = strtol(argv[N], &endptr, 0);
    if (*endptr) usage_merge_source_id (argv[N]); 
    remove_argument (N, &argc, argv);
    remove_argument (N, &argc, argv); // remove the 'into'
    OBJ_ID_DST = strtol(argv[N], &endptr, 0);
    if (*endptr) usage_merge_source_id (argv[N]); 
    remove_argument (N, &argc, argv);
    CAT_ID_DST = strtol(argv[N], &endptr, 0);
    if (*endptr) usage_merge_source_id (argv[N]); 
    remove_argument (N, &argc, argv);

    if (argc != 1) usage ();
    return TRUE;
  }

  if ((N = get_argument (argc, argv, "-update-objects"))) {
    remove_argument (N, &argc, argv);
    RELASTRO_OP = OP_UPDATE_OBJECTS;
  }

  if ((N = get_argument (argc, argv, "-update-offsets"))) {
    remove_argument (N, &argc, argv);
    RELASTRO_OP = OP_UPDATE_OFFSETS;
  }

  // elements needed for parallel regions / parallel images
  REGION_FILE = NULL;
  if ((N = get_argument (argc, argv, "-region-hosts"))) {
    remove_argument (N, &argc, argv);
    REGION_FILE = strcreate (argv[N]);
    remove_argument (N, &argc, argv);
  }

  REGION_HOST_ID = 0;
  if ((N = get_argument (argc, argv, "-region-hostID"))) {
    remove_argument (N, &argc, argv);
    REGION_HOST_ID = atoi (argv[N]);
    remove_argument (N, &argc, argv);
  }

  IMAGE_TABLE = NULL;
  if ((N = get_argument (argc, argv, "-parallel-images"))) {
    remove_argument (N, &argc, argv);
    RELASTRO_OP = OP_PARALLEL_IMAGES;
    if (N >= argc) usage();
    IMAGE_TABLE = strcreate (argv[N]);
    remove_argument (N, &argc, argv);
    if (!REGION_FILE) usage();
  }

  if ((N = get_argument (argc, argv, "-images"))) {
    remove_argument (N, &argc, argv);
    RELASTRO_OP = OP_IMAGES;
  }

  PARALLEL_REGIONS_MANUAL = FALSE;
  if ((N = get_argument (argc, argv, "-parallel-regions"))) {
    remove_argument (N, &argc, argv);
    RELASTRO_OP = OP_PARALLEL_REGIONS;
    if (!REGION_FILE) usage();
    if ((N = get_argument (argc, argv, "-parallel-regions-manual"))) {
      remove_argument (N, &argc, argv);
      PARALLEL_REGIONS_MANUAL = TRUE;
    }
  }

  if ((N = get_argument (argc, argv, "-testobj1"))) {
    if (N > argc - 3) usage ();
    remove_argument (N, &argc, argv);
    OBJ_ID_SRC = strtol(argv[N], &endptr, 0);
    if (*endptr) usage ();
    remove_argument (N, &argc, argv);
    CAT_ID_SRC = strtol(argv[N], &endptr, 0);
    if (*endptr) usage (); 
    remove_argument (N, &argc, argv);
  }

  if ((N = get_argument (argc, argv, "-testobj2"))) {
    if (N > argc - 3) usage ();
    remove_argument (N, &argc, argv);
    OBJ_ID_DST = strtol(argv[N], &endptr, 0);
    if (*endptr) usage ();
    remove_argument (N, &argc, argv);
    CAT_ID_DST = strtol(argv[N], &endptr, 0);
    if (*endptr) usage (); 
    remove_argument (N, &argc, argv);
  }

  // check for object fitting modes
  if ((N = get_argument (argc, argv, "-pm"))) {
    remove_argument (N, &argc, argv);
    FIT_MODE = FIT_PM_ONLY;
  }
  if ((N = get_argument (argc, argv, "-par"))) {
    remove_argument (N, &argc, argv);
    FIT_MODE = FIT_PAR_ONLY;
  }
  if ((N = get_argument (argc, argv, "-pmpar"))) {
    remove_argument (N, &argc, argv);
    FIT_MODE = FIT_PM_AND_PAR;
  }

  if ((N = get_argument (argc, argv, "-high-speed"))) {
    // XXX include a parallax / no-parallax option
    if (N >= argc - 4) usage();
    RELASTRO_OP = OP_HIGH_SPEED;
    remove_argument (N, &argc, argv);
    PHOTCODE_A_LIST = strcreate(argv[N]);
    remove_argument (N, &argc, argv);
    PHOTCODE_B_LIST = strcreate(argv[N]);
    remove_argument (N, &argc, argv);
    RADIUS = atof(argv[N]);
    remove_argument (N, &argc, argv);
    HIGH_SPEED_DIR = abspath(argv[N], DVO_MAX_PATH);
    remove_argument (N, &argc, argv);
  }

  if ((N = get_argument (argc, argv, "-hpm"))) {
    if (N >= argc - 2) usage();
    RELASTRO_OP = OP_HPM;
    remove_argument (N, &argc, argv);
    RADIUS = atof(argv[N]);
    remove_argument (N, &argc, argv);
    HIGH_SPEED_DIR = abspath(argv[N], DVO_MAX_PATH);
    remove_argument (N, &argc, argv);
  }

  PARALLEL_OUTPUT = FALSE;
  if ((N = get_argument (argc, argv, "-parallel-output"))) {
    remove_argument (N, &argc, argv);
    PARALLEL_OUTPUT = TRUE;
    if ((RELASTRO_OP != OP_HIGH_SPEED) && (RELASTRO_OP != OP_HPM)) {
      fprintf (stderr, "-parallel-output only valid for -high-speed or -hpm modes\n");
      exit (1);
    }
  }

  if ((N = get_argument (argc, argv, "-update-simple"))) {
    remove_argument (N, &argc, argv);
    FIT_TARGET = TARGET_SIMPLE;
  }
  if ((N = get_argument (argc, argv, "-update-chips"))) {
    remove_argument (N, &argc, argv);
    FIT_TARGET = TARGET_CHIPS;
  }
  if ((N = get_argument (argc, argv, "-update-mosaics"))) {
    remove_argument (N, &argc, argv);
    FIT_TARGET = TARGET_MOSAICS;
  }

  FlagOutlier = FALSE;
  if ((N = get_argument (argc, argv, "-clip"))) {
    fprintf (stderr, "-clip is currently disabled\n");
    remove_argument (N, &argc, argv);
    CLIP_THRESH = atof (argv[N]);
    remove_argument (N, &argc, argv);
    FlagOutlier = TRUE;
  }

  ExcludeBogus = FALSE;
  ExcludeBogusRadius = 0.0;
  if ((N = get_argument (argc, argv, "-exclude-bogus"))) {
    remove_argument (N, &argc, argv);
    ExcludeBogusRadius = atof (argv[N]);
    remove_argument (N, &argc, argv);
    ExcludeBogus = TRUE;
  }

  if (RELASTRO_OP == OP_NONE) usage();

  if (((RELASTRO_OP == OP_IMAGES) || (RELASTRO_OP == OP_PARALLEL_REGIONS) || (RELASTRO_OP == OP_PARALLEL_IMAGES)) && (FIT_TARGET == TARGET_NONE)) usage();

  /* specify portion of the sky : allow default of all sky? */
  UserPatch.Rmin = 0;
  UserPatch.Rmax = 360;
  UserPatch.Dmin = -90;
  UserPatch.Dmax = +90;
  if ((N = get_argument (argc, argv, "-region"))) {
    remove_argument (N, &argc, argv);
    UserPatch.Rmin = atof (argv[N]);
    remove_argument (N, &argc, argv);
    UserPatch.Rmax = atof (argv[N]);
    remove_argument (N, &argc, argv);
    UserPatch.Dmin = atof (argv[N]);
    remove_argument (N, &argc, argv);
    UserPatch.Dmax = atof (argv[N]);
    remove_argument (N, &argc, argv);
  } 
  if ((N = get_argument (argc, argv, "-catalog"))) {
    remove_argument (N, &argc, argv);
    UserPatch.Rmin = atof (argv[N]);
    UserPatch.Rmax = UserPatch.Rmin + 0.001;
    remove_argument (N, &argc, argv);
    UserPatch.Dmin = atof (argv[N]);
    UserPatch.Dmax = UserPatch.Dmin + 0.001;
    remove_argument (N, &argc, argv);
  }

  // XXX for the moment, make this selection manual.  it needs to be automatic 
  // based on the state of the SkyTable
  PARALLEL = FALSE;
  if ((N = get_argument (argc, argv, "-parallel"))) {
    PARALLEL = TRUE;
    remove_argument (N, &argc, argv);
  }
  // this is a test mode : rather than launching the remote jobs and waiting for completion,
  // relastro will simply list the remote command and wait for the user to signal completion
  PARALLEL_MANUAL = FALSE;
  if ((N = get_argument (argc, argv, "-parallel-manual"))) {
    PARALLEL = TRUE; // -parallel-manual implies -parallel
    PARALLEL_MANUAL = TRUE;
    remove_argument (N, &argc, argv);
  }
  // this is a test mode : rather than launching the relastro_client jobs remotely, they are 
  // run in serial via 'system'
  PARALLEL_SERIAL = FALSE;
  if ((N = get_argument (argc, argv, "-parallel-serial"))) {
    if (PARALLEL_MANUAL) {
      fprintf (stderr, "ERROR: cannot mix -parallel-manual and -parallel-serial\n");
      exit (1);
    }
    PARALLEL = TRUE; // -parallel-serial implies -parallel
    PARALLEL_SERIAL = TRUE;
    remove_argument (N, &argc, argv);
  }

  USE_BASIC_CHECK = FALSE;
  if ((N = get_argument (argc, argv, "-basic-image-search"))) {
    remove_argument (N, &argc, argv);
    USE_BASIC_CHECK = TRUE;
  }

  MaxDensityUse = FALSE;
  if ((N = get_argument (argc, argv, "-max-density"))) {
    remove_argument (N, &argc, argv);
    MaxDensityValue = atof(argv[N]);
    remove_argument (N, &argc, argv);
    MaxDensityUse = TRUE;
  }

  APPLY_OFFSETS = FALSE;
  if ((N = get_argument (argc, argv, "-apply-offsets"))) {
    remove_argument (N, &argc, argv);
    APPLY_OFFSETS = TRUE;
  }

  /* define time */
  TimeSelect = FALSE;
  if ((N = get_argument (argc, argv, "-time"))) {
    remove_argument (N, &argc, argv);
    if (!ohana_str_to_time (argv[N], &TSTART)) { 
      fprintf (stderr, "ERROR: syntax error\n");
      return (FALSE);
    }
    remove_argument (N, &argc, argv);
    if (!ohana_str_to_dtime (argv[N], &trange)) { 
      if (!ohana_str_to_time (argv[N], &TSTOP)) { 
	fprintf (stderr, "ERROR: syntax error\n");
	return (FALSE);
      }
    } else {
      if (trange < 0) {
	trange = fabs (trange);
	TSTOP = TSTART;
	TSTART -= trange;
      } else {
	TSTOP = TSTART + trange;
      }
    }
    remove_argument (N, &argc, argv);
    TimeSelect = TRUE;
  }

  // eg g - r or r - i
  DCR_BLUE_COLOR_POS = NULL;
  DCR_BLUE_COLOR_NEG = NULL;
  if ((N = get_argument (argc, argv, "-dcr-blue-color"))) {
    remove_argument (N, &argc, argv);
    DCR_BLUE_COLOR_POS = strcreate(argv[N]);
    remove_argument (N, &argc, argv);
    DCR_BLUE_COLOR_NEG = strcreate(argv[N]);
    remove_argument (N, &argc, argv);
  }

  // eg, z - y or i - z
  DCR_RED_COLOR_POS = NULL;
  DCR_RED_COLOR_NEG = NULL;
  if ((N = get_argument (argc, argv, "-dcr-red-color"))) {
    remove_argument (N, &argc, argv);
    DCR_RED_COLOR_POS = strcreate(argv[N]);
    remove_argument (N, &argc, argv);
    DCR_RED_COLOR_NEG = strcreate(argv[N]);
    remove_argument (N, &argc, argv);
  }

  PHOTCODE_RESET_LIST = NULL;
  if ((N = get_argument (argc, argv, "-reset-to-photcode"))) {
    remove_argument (N, &argc, argv);
    PHOTCODE_RESET_LIST = strcreate(argv[N]);
    remove_argument (N, &argc, argv);
  }

  PHOTCODE_KEEP_LIST = NULL;
  if ((N = get_argument (argc, argv, "+photcode"))) {
    remove_argument (N, &argc, argv);
    PHOTCODE_KEEP_LIST = strcreate(argv[N]);
    remove_argument (N, &argc, argv);
  }

  char *SuperCOSMOS_SKIP = strcreate("SCOS.103a.E,SCOS.4414.OG590,SCOS.4415.OG590,SCOS.IIIaF.OG590,SCOS.IIIaF.RG610,SCOS.IIIaF.RG630,SCOS.IIIaJ.GG385,SCOS.IIIaJ.GG395,SCOS.IVN.RG715,SCOS.IVN.RG9");

  PHOTCODE_SKIP_LIST = NULL;
  if ((N = get_argument (argc, argv, "-photcode"))) {
    remove_argument (N, &argc, argv);
    char *RawSkip = strcreate(argv[N]);

    char *GotSkip = strstr (RawSkip, SuperCOSMOS_SKIP);
    if (!GotSkip) {
      int Ntotal = strlen(RawSkip) + strlen(SuperCOSMOS_SKIP) + 5;
      ALLOCATE (PHOTCODE_SKIP_LIST, char, Ntotal);
      snprintf (PHOTCODE_SKIP_LIST, Ntotal, "%s,%s", SuperCOSMOS_SKIP, RawSkip);
      free (RawSkip);
      free (SuperCOSMOS_SKIP);
    } else {
      PHOTCODE_SKIP_LIST = RawSkip;
    }
    remove_argument (N, &argc, argv);
  }

  VERBOSE = VERBOSE2 = FALSE;
  if ((N = get_argument (argc, argv, "-v"))) {
    VERBOSE = TRUE;
    remove_argument (N, &argc, argv);
  }
  if ((N = get_argument (argc, argv, "-vv"))) {
    VERBOSE = VERBOSE2 = TRUE;
    remove_argument (N, &argc, argv);
  }

  if ((N = get_argument (argc, argv, "-visual"))) {
    remove_argument (N, &argc, argv);
    relastroSetVisual(TRUE);
  }

  CHIPORDER = 0;
  if ((N = get_argument (argc, argv, "-chiporder"))) {
    remove_argument (N, &argc, argv);
    CHIPORDER = atoi(argv[N]);
    remove_argument (N, &argc, argv);
  }

  CHIPMAP = 0;
  if ((N = get_argument (argc, argv, "-chipmap"))) {
    remove_argument (N, &argc, argv);
    CHIPMAP = atoi(argv[N]);
    remove_argument (N, &argc, argv);

  }

  SAVEPLOT = FALSE;
  PLOTSTUFF = FALSE;
  if ((N = get_argument (argc, argv, "-plot"))) {
    PLOTSTUFF = TRUE;
    remove_argument (N, &argc, argv);
  }

  PLOTDELAY = 500000;
  if ((N = get_argument (argc, argv, "-plotdelay"))) {
    remove_argument (N, &argc, argv);
    PLOTDELAY = 1e6*atof(argv[N]);
    remove_argument (N, &argc, argv);
  }

  // by default, require > 10pts to clip
  strcpy (STATMODE, "CHI_INNER_80_WTMEAN");
  if ((N = get_argument (argc, argv, "-statmode"))) {
    remove_argument (N, &argc, argv);
    strcpy (STATMODE, argv[N]);
    remove_argument (N, &argc, argv);
  }

  RESET = FALSE;
  if ((N = get_argument (argc, argv, "-reset"))) {
    remove_argument (N, &argc, argv);
    RESET = TRUE;
  }
  RESET_BAD_IMAGES = FALSE;
  if ((N = get_argument (argc, argv, "-reset-bad-images"))) {
    remove_argument (N, &argc, argv);
    RESET_BAD_IMAGES = TRUE;
  }
  RESET_IMAGES = FALSE;
  if ((N = get_argument (argc, argv, "-reset-images"))) {
    remove_argument (N, &argc, argv);
    RESET_IMAGES = TRUE;
  }

  UPDATE = FALSE;
  if ((N = get_argument (argc, argv, "-update"))) {
    remove_argument (N, &argc, argv);
    UPDATE = TRUE;
  }

  SHOW_PARAMS = FALSE;
  if ((N = get_argument (argc, argv, "-params"))) {
    remove_argument (N, &argc, argv);
    SHOW_PARAMS = TRUE;
  }

  /* XXX update these for relevant plots */
  PlotMmin = 10.0; PlotMmax = 20.0; PlotdMmin = -1.0; PlotdMmax = 1.0;
  if ((N = get_argument (argc, argv, "-plrange"))) {
    remove_argument (N, &argc, argv);
    PlotMmin = atof (argv[N]);
    remove_argument (N, &argc, argv);
    PlotMmax = atof (argv[N]);
    remove_argument (N, &argc, argv);
    PlotdMmin = atof (argv[N]);
    remove_argument (N, &argc, argv);
    PlotdMmax = atof (argv[N]);
    remove_argument (N, &argc, argv);
  }

  /* XXX update this */
  MIN_ERROR = 0.001;
  if ((N = get_argument (argc, argv, "-minerror"))) {
    remove_argument (N, &argc, argv);
    MIN_ERROR = atof (argv[N]);
    remove_argument (N, &argc, argv);
    /* require MIN_ERROR > 0 */
  }  

  ImagSelect = FALSE;
  if ((N = get_argument (argc, argv, "-instmag"))) {
    remove_argument (N, &argc, argv);
    ImagMin = atof (argv[N]);
    remove_argument (N, &argc, argv);
    ImagMax = atof (argv[N]);
    remove_argument (N, &argc, argv);
    ImagSelect = TRUE;
  }
  
  // for now, make the default to ignore the photflags
  // XXX make it true by default instead?
  PhotFlagSelect = FALSE;
  if ((N = get_argument (argc, argv, "+photflags"))) {
    remove_argument (N, &argc, argv);
    PhotFlagSelect = TRUE;
  }

  PhotFlagBad = 0;
  if ((N = get_argument (argc, argv, "-photflagbad"))) {
    remove_argument (N, &argc, argv);
    PhotFlagBad = atoi (argv[N]);
    remove_argument (N, &argc, argv);
  }

  PhotFlagPoor = 0;
  if ((N = get_argument (argc, argv, "-photflagpoor"))) {
    remove_argument (N, &argc, argv);
    PhotFlagPoor = atoi (argv[N]);
    remove_argument (N, &argc, argv);
  }

  MinBadQF = 0.0;
  if ((N = get_argument (argc, argv, "-min-bad-psfqf"))) {
    remove_argument (N, &argc, argv);
    MinBadQF = atof (argv[N]);
    remove_argument (N, &argc, argv);
  }

  MaxMeanOffset = 10.0;
  if ((N = get_argument (argc, argv, "-max-mean-offset"))) {
    remove_argument (N, &argc, argv);
    MaxMeanOffset = atof (argv[N]);
    remove_argument (N, &argc, argv);
  }

  NLOOP = 4;
  if ((N = get_argument (argc, argv, "-nloop"))) {
    remove_argument (N, &argc, argv);
    NLOOP = atof (argv[N]);
    remove_argument (N, &argc, argv);
  }

  NTHREADS = 0;
  if ((N = get_argument (argc, argv, "-threads"))) {
    remove_argument (N, &argc, argv);
    NTHREADS = atof (argv[N]);
    remove_argument (N, &argc, argv);
  }

  if (argc != 1) usage ();
  return TRUE;
}

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

  int N;
  double trange;
  char *endptr;

  /* possible operations */
  RELASTRO_OP = TARGET_NONE;
  FIT_MODE = FIT_AVERAGE;

  // by definition, the client is not parallel 
  PARALLEL = FALSE;
  PARALLEL_MANUAL = FALSE;
  PARALLEL_SERIAL = FALSE;

  BCATALOG = NULL;

  REGION_FILE = NULL;
  REGION_HOST_ID = 0;
  IMAGE_TABLE = NULL;
  PARALLEL_REGIONS_MANUAL = FALSE;

  HOST_ID = 0;
  if ((N = get_argument (argc, argv, "-hostID"))) {
    remove_argument (N, &argc, argv);
    HOST_ID = atoi (argv[N]);
    remove_argument (N, &argc, argv);
  }
  if (!HOST_ID) usage_client();

  HOSTDIR = NULL;
  if ((N = get_argument (argc, argv, "-hostdir"))) {
    remove_argument (N, &argc, argv);
    HOSTDIR = strcreate (argv[N]);
    remove_argument (N, &argc, argv);
  }
  if (!HOSTDIR) usage_client();

  if ((N = get_argument (argc, argv, "-load-objects"))) {
    remove_argument (N, &argc, argv);
    BCATALOG = strcreate(argv[N]);
    remove_argument (N, &argc, argv);
    RELASTRO_OP = OP_LOAD_OBJECTS;
  }

  if ((N = get_argument (argc, argv, "-update-objects"))) {
    remove_argument (N, &argc, argv);
    RELASTRO_OP = OP_UPDATE_OBJECTS;
  }

  if ((N = get_argument (argc, argv, "-update-offsets"))) {
    remove_argument (N, &argc, argv);
    RELASTRO_OP = OP_UPDATE_OFFSETS;
  }

  // check for object fitting modes
  if ((N = get_argument (argc, argv, "-pm"))) {
    remove_argument (N, &argc, argv);
    FIT_MODE = FIT_PM_ONLY;
  }
  if ((N = get_argument (argc, argv, "-par"))) {
    remove_argument (N, &argc, argv);
    FIT_MODE = FIT_PAR_ONLY;
  }
  if ((N = get_argument (argc, argv, "-pmpar"))) {
    remove_argument (N, &argc, argv);
    FIT_MODE = FIT_PM_AND_PAR;
  }

  if ((N = get_argument (argc, argv, "-high-speed"))) {
    // XXX include a parallax / no-parallax option
    if (N >= argc - 5) usage_client();
    RELASTRO_OP = OP_HIGH_SPEED;
    remove_argument (N, &argc, argv);
    PHOTCODE_A_LIST = strcreate(argv[N]);
    remove_argument (N, &argc, argv);
    PHOTCODE_B_LIST = strcreate(argv[N]);
    remove_argument (N, &argc, argv);
    RADIUS = atof(argv[N]);
    remove_argument (N, &argc, argv);
    HIGH_SPEED_DIR = strcreate(argv[N]);
    remove_argument (N, &argc, argv);
  }

  if ((N = get_argument (argc, argv, "-hpm"))) {
    if (N >= argc - 3) usage();
    RELASTRO_OP = OP_HPM;
    remove_argument (N, &argc, argv);
    RADIUS = atof(argv[N]);
    remove_argument (N, &argc, argv);
    HIGH_SPEED_DIR = abspath(argv[N], DVO_MAX_PATH);
    remove_argument (N, &argc, argv);
  }

  if ((N = get_argument (argc, argv, "-testobj1"))) {
    if (N > argc - 3) usage ();
    remove_argument (N, &argc, argv);
    OBJ_ID_SRC = strtol(argv[N], &endptr, 0);
    if (*endptr) usage ();
    remove_argument (N, &argc, argv);
    CAT_ID_SRC = strtol(argv[N], &endptr, 0);
    if (*endptr) usage (); 
    remove_argument (N, &argc, argv);
  }

  if ((N = get_argument (argc, argv, "-testobj2"))) {
    if (N > argc - 3) usage ();
    remove_argument (N, &argc, argv);
    OBJ_ID_DST = strtol(argv[N], &endptr, 0);
    if (*endptr) usage ();
    remove_argument (N, &argc, argv);
    CAT_ID_DST = strtol(argv[N], &endptr, 0);
    if (*endptr) usage (); 
    remove_argument (N, &argc, argv);
  }

  FlagOutlier = FALSE;
  if ((N = get_argument (argc, argv, "-clip"))) {
    fprintf (stderr, "-clip is currently disabled\n");
    remove_argument (N, &argc, argv);
    CLIP_THRESH = atof (argv[N]);
    remove_argument (N, &argc, argv);
    FlagOutlier = TRUE;
  }

  ExcludeBogus = FALSE;
  ExcludeBogusRadius = 0.0;
  if ((N = get_argument (argc, argv, "-exclude-bogus"))) {
    remove_argument (N, &argc, argv);
    ExcludeBogusRadius = atof (argv[N]);
    remove_argument (N, &argc, argv);
    ExcludeBogus = TRUE;
  }

  if (RELASTRO_OP == OP_NONE) usage_client();

  /* specify portion of the sky : allow default of all sky? */
  UserPatch.Rmin = 0;
  UserPatch.Rmax = 360;
  UserPatch.Dmin = -90;
  UserPatch.Dmax = +90;
  if ((N = get_argument (argc, argv, "-region"))) {
    remove_argument (N, &argc, argv);
    UserPatch.Rmin = atof (argv[N]);
    remove_argument (N, &argc, argv);
    UserPatch.Rmax = atof (argv[N]);
    remove_argument (N, &argc, argv);
    UserPatch.Dmin = atof (argv[N]);
    remove_argument (N, &argc, argv);
    UserPatch.Dmax = atof (argv[N]);
    remove_argument (N, &argc, argv);
  } 
  if ((N = get_argument (argc, argv, "-catalog"))) {
    remove_argument (N, &argc, argv);
    UserPatch.Rmin = atof (argv[N]);
    UserPatch.Rmax = UserPatch.Rmin + 0.001;
    remove_argument (N, &argc, argv);
    UserPatch.Dmin = atof (argv[N]);
    UserPatch.Dmax = UserPatch.Dmin + 0.001;
    remove_argument (N, &argc, argv);
  }

  USE_BASIC_CHECK = FALSE;
  if ((N = get_argument (argc, argv, "-basic-image-search"))) {
    remove_argument (N, &argc, argv);
    USE_BASIC_CHECK = TRUE;
  }

  MaxDensityUse = FALSE;
  if ((N = get_argument (argc, argv, "-max-density"))) {
    remove_argument (N, &argc, argv);
    MaxDensityValue = atof(argv[N]);
    remove_argument (N, &argc, argv);
    MaxDensityUse = TRUE;
  }

  /* define time */
  TimeSelect = FALSE;
  if ((N = get_argument (argc, argv, "-time"))) {
    remove_argument (N, &argc, argv);
    if (!ohana_str_to_time (argv[N], &TSTART)) { 
      fprintf (stderr, "ERROR: syntax error\n");
      return (FALSE);
    }
    remove_argument (N, &argc, argv);
    if (!ohana_str_to_dtime (argv[N], &trange)) { 
      if (!ohana_str_to_time (argv[N], &TSTOP)) { 
	fprintf (stderr, "ERROR: syntax error\n");
	return (FALSE);
      }
    } else {
      if (trange < 0) {
	trange = fabs (trange);
	TSTOP = TSTART;
	TSTART -= trange;
      } else {
	TSTOP = TSTART + trange;
      }
    }
    remove_argument (N, &argc, argv);
    TimeSelect = TRUE;
  }

  DCR_BLUE_COLOR_POS = NULL;
  DCR_BLUE_COLOR_NEG = NULL;
  if ((N = get_argument (argc, argv, "-dcr-blue-color"))) {
    remove_argument (N, &argc, argv);
    DCR_BLUE_COLOR_POS = strcreate(argv[N]);
    remove_argument (N, &argc, argv);
    DCR_BLUE_COLOR_NEG = strcreate(argv[N]);
    remove_argument (N, &argc, argv);
  }
  DCR_RED_COLOR_POS = NULL;
  DCR_RED_COLOR_NEG = NULL;
  if ((N = get_argument (argc, argv, "-dcr-red-color"))) {
    remove_argument (N, &argc, argv);
    DCR_RED_COLOR_POS = strcreate(argv[N]);
    remove_argument (N, &argc, argv);
    DCR_RED_COLOR_NEG = strcreate(argv[N]);
    remove_argument (N, &argc, argv);
  }

  PHOTCODE_RESET_LIST = NULL;
  if ((N = get_argument (argc, argv, "-reset-to-photcode"))) {
    remove_argument (N, &argc, argv);
    PHOTCODE_RESET_LIST = strcreate(argv[N]);
    remove_argument (N, &argc, argv);
  }

  PHOTCODE_KEEP_LIST = NULL;
  if ((N = get_argument (argc, argv, "+photcode"))) {
    remove_argument (N, &argc, argv);
    PHOTCODE_KEEP_LIST = strcreate(argv[N]);
    remove_argument (N, &argc, argv);
  }

  PHOTCODE_SKIP_LIST = NULL;
  if ((N = get_argument (argc, argv, "-photcode"))) {
    remove_argument (N, &argc, argv);
    PHOTCODE_SKIP_LIST = strcreate(argv[N]);
    remove_argument (N, &argc, argv);
  }

  VERBOSE = VERBOSE2 = FALSE;
  if ((N = get_argument (argc, argv, "-v"))) {
    VERBOSE = TRUE;
    remove_argument (N, &argc, argv);
  }
  if ((N = get_argument (argc, argv, "-vv"))) {
    VERBOSE = VERBOSE2 = TRUE;
    remove_argument (N, &argc, argv);
  }

  // by default, require > 10pts to clip
  strcpy (STATMODE, "CHI_INNER_80_WTMEAN");
  if ((N = get_argument (argc, argv, "-statmode"))) {
    remove_argument (N, &argc, argv);
    strcpy (STATMODE, argv[N]);
    remove_argument (N, &argc, argv);
  }

  RESET = FALSE;
  if ((N = get_argument (argc, argv, "-reset"))) {
    remove_argument (N, &argc, argv);
    RESET = TRUE;
  }

  RESET_BAD_IMAGES = FALSE;
  if ((N = get_argument (argc, argv, "-reset-bad-images"))) {
    remove_argument (N, &argc, argv);
    RESET_BAD_IMAGES = TRUE;
  }

  UPDATE = FALSE;
  if ((N = get_argument (argc, argv, "-update"))) {
    remove_argument (N, &argc, argv);
    UPDATE = TRUE;
  }

  /* XXX update this */
  MIN_ERROR = 0.001;
  if ((N = get_argument (argc, argv, "-minerror"))) {
    remove_argument (N, &argc, argv);
    MIN_ERROR = atof (argv[N]);
    remove_argument (N, &argc, argv);
    /* require MIN_ERROR > 0 */
  }  

  ImagSelect = FALSE;
  if ((N = get_argument (argc, argv, "-instmag"))) {
    remove_argument (N, &argc, argv);
    ImagMin = atof (argv[N]);
    remove_argument (N, &argc, argv);
    ImagMax = atof (argv[N]);
    remove_argument (N, &argc, argv);
    ImagSelect = TRUE;
  }
  
  // for now, make the default to ignore the photflags
  // XXX make it true by default instead?
  PhotFlagSelect = FALSE;
  if ((N = get_argument (argc, argv, "+photflags"))) {
    remove_argument (N, &argc, argv);
    PhotFlagSelect = TRUE;
  }

  PhotFlagBad = 0;
  if ((N = get_argument (argc, argv, "-photflagbad"))) {
    remove_argument (N, &argc, argv);
    PhotFlagBad = atoi (argv[N]);
    remove_argument (N, &argc, argv);
  }

  PhotFlagPoor = 0;
  if ((N = get_argument (argc, argv, "-photflagpoor"))) {
    remove_argument (N, &argc, argv);
    PhotFlagPoor = atoi (argv[N]);
    remove_argument (N, &argc, argv);
  }

  MinBadQF = 0.0;
  if ((N = get_argument (argc, argv, "-min-bad-psfqf"))) {
    remove_argument (N, &argc, argv);
    MinBadQF = atof (argv[N]);
    remove_argument (N, &argc, argv);
  }

  MaxMeanOffset = 10.0;
  if ((N = get_argument (argc, argv, "-max-mean-offset"))) {
    remove_argument (N, &argc, argv);
    MaxMeanOffset = atof (argv[N]);
    remove_argument (N, &argc, argv);
  }

  if (argc != 1) usage_client ();
  return TRUE;
}

void usage () {
  fprintf (stderr, "ERROR: USAGE: relastro -images -update-simple [options]\n");
  fprintf (stderr, "       OR:    relastro -images -update-chips [options]\n");
  fprintf (stderr, "       OR:    relastro -images -update-mosaic [options]\n");
  fprintf (stderr, "       OR:    relastro -parallel-regions -update-simple [options]\n");
  fprintf (stderr, "       OR:    relastro -parallel-regions -update-chips [options]\n");
  fprintf (stderr, "       OR:    relastro -parallel-regions -update-mosaic [options]\n");
  fprintf (stderr, "       OR:    relastro -parallel-images -update-simple [options]\n");
  fprintf (stderr, "       OR:    relastro -parallel-images -update-chips [options]\n");
  fprintf (stderr, "       OR:    relastro -parallel-images -update-mosaic [options]\n");
  fprintf (stderr, "       OR:    relastro -update-objects [options]\n");
  fprintf (stderr, "       OR:    relastro -high-speed [options]\n");
  fprintf (stderr, "       OR:    relastro -hpm [options]\n");
  fprintf (stderr, "       OR:    relastro -merge-source [options]\n\n");

  fprintf (stderr, "  specify one of the following modes: \n");
  fprintf (stderr, "  -update-objects\n");
  fprintf (stderr, "    -pm\n");
  fprintf (stderr, "    -par\n");
  fprintf (stderr, "    -pmpar\n");
  fprintf (stderr, "  -update-simple\n");
  fprintf (stderr, "  -update-chips\n");
  fprintf (stderr, "  -update-mosaics\n");
  fprintf (stderr, "  -high-speed (code[,code,code]) (code[,code,code]) (radius) (output catdir)\n");
  fprintf (stderr, "  -hpm (radius) (output catdir)\n");
  fprintf (stderr, "  -chipmap (MaxOrder)\n");
  fprintf (stderr, "  -merge-source (objID) (catID) into (objID) (catID)\n\n");

  fprintf (stderr, " additional options: \n");
  fprintf (stderr, "  -region RA RA DEC DEC\n");
  fprintf (stderr, "  -catalog (ra) (dec)\n\n");
  fprintf (stderr, "  -time (start)(stop)\n");
  fprintf (stderr, "  +photcode (code)[,code,code...]\n");
  fprintf (stderr, "  -photcode (code)[,code,code...]\n");
  fprintf (stderr, "  -plot\n");
  fprintf (stderr, "  -plotdelay (seconds)\n");
  fprintf (stderr, "  -statmode (mode)\n");
  fprintf (stderr, "  -reset\n");
  fprintf (stderr, "  -reset-images\n");
  fprintf (stderr, "  -nloop (N) : number of image-fit iterations\n");
  fprintf (stderr, "  -update : apply new fit to database\n");
  fprintf (stderr, "  -params\n");
  fprintf (stderr, "  -plrange\n");
  fprintf (stderr, "  -minerror\n");
  fprintf (stderr, "  -instmag min max\n\n");
  fprintf (stderr, "  +photflags\n");
  fprintf (stderr, "  -photflagbad\n");
  fprintf (stderr, "  -photflagpoor\n");
  fprintf (stderr, "  -v\n");
  fprintf (stderr, "  \n");
  exit (2);
} 

void usage_client () {
  fprintf (stderr, "ERROR: USAGE: relastro_client -load\n");
  fprintf (stderr, "       OR:    relastro_client -update-offsets\n");
  fprintf (stderr, "       OR:    relastro_client -update-objects\n");
  fprintf (stderr, "       OR:    relastro_client -high-speed\n\n");

  fprintf (stderr, "  specify one of the following modes: \n");
  fprintf (stderr, "  -load : load the bright source detections for analysis\n");
  fprintf (stderr, "  -update-offsets : apply the updated image parameters\n");
  fprintf (stderr, "  -update-objects : calculate average astrometric properties of objects\n");
  fprintf (stderr, "  -high-speed (code[,code,code]) (code[,code,code]) (radius) (output catdir)\n");
  fprintf (stderr, "    support for the special high-speed mode\n");

  fprintf (stderr, " additional options: \n");
  fprintf (stderr, "  -pm : calculate proper motions\n");
  fprintf (stderr, "  -par : calculate parallaxes\n");
  fprintf (stderr, "  -pmpar : calculate motions and parallaxes\n");
  fprintf (stderr, "  -region Rmin Rmax Dmin Dmax");
  fprintf (stderr, "  -catalog RA DEC");
  fprintf (stderr, "  -time (start)(stop)\n");
  fprintf (stderr, "  +photcode (code)[,code,code...]\n");
  fprintf (stderr, "  -photcode (code)[,code,code...]\n");
  fprintf (stderr, "  -statmode (mode)\n");
  fprintf (stderr, "  -reset\n");
  fprintf (stderr, "  -minerror\n");
  fprintf (stderr, "  -instmag min max\n\n");
  fprintf (stderr, "  +photflags\n");
  fprintf (stderr, "  -photflagbad\n");
  fprintf (stderr, "  -photflagpoor\n");
  fprintf (stderr, "  -v\n");
  fprintf (stderr, "  \n");
  exit (2);
} 

void usage_merge_source_id (char *name) {

  fprintf (stderr, "ERROR: invalid ID %s (remember to prefix 0x to hex IDs)\n", name);
  exit (2);
}

void usage_merge_source () {
  fprintf (stderr, "ERROR: USAGE: relastro -merge-source (objID) (catID) into (objID) (catID)\n");
  exit (2);
}

int strextend (char *input, char *format,...) {

  char tmpextra[1024], tmpline[1024];
  va_list argp;

  va_start (argp, format);
  vsnprintf (tmpextra, 1024, format, argp);
  snprintf (tmpline, 1024, "%s %s", input, tmpextra);
  strcpy (input, tmpline);

  return TRUE;
}
