# include "dvoshell.h"

int mextract (int argc, char **argv) {
  
  int i, j, k, m, n, N, N1, Npts, NPTS, last, Nfields, Nreturn, Ncstack, Nstack;
  int Nsecfilt, VERBOSE, loadImages, mosaicMode;
  char *RegionName, *RegionList, *p;
  double *M1;
  char **cstack, name[1024];
  float *values;
  void *Signal;

  Catalog catalog;
  SkyList *skylist;
  PhotCode *code;
  Vector **vec;
  dbField *fields;
  dbStack *stack;

  /* defaults */
  skylist = NULL;
  RegionName = NULL;
  RegionList = NULL;
  code = NULL;
  fields = NULL;
  stack = NULL;

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

  dvo_catalog_init (&catalog, TRUE);

  /* load photcode information */
  if (!InitPhotcodes ()) goto escape;
  Nsecfilt = GetPhotcodeNsecfilt ();
  
  // init locally static variables (time refs)
  dbExtractMeasuresInit();

  // remove skyregion options
  // XXX this needs to explicitly handle -qregion and -skyregion
  if (!SetRegionSelection (&argc, argv, &RegionName, &RegionList)) goto escape;

  // command-line is of the form: avextract field,field, field [where (field op value)...]

  // parse the fields to be extracted and returned
  fields = dbCmdlineFields (argc, argv, DVO_TABLE_MEASURE, &last, &Nfields);
  if (fields == NULL) return (FALSE);

  // parse the remainder of the line as a boolean math expression
  cstack = isolate_elements (argc-last, &argv[last], &Ncstack);
  
  // construct the db Boolean math stack (frees cstack)
  stack = dbRPN (Ncstack, cstack, &Nstack);
  if ((Ncstack > 0) && (Nstack < 1)) {
    print_error ();
    goto escape;
  }

  Nreturn = Nfields; 
  dbCheckStack (stack, Nstack, DVO_TABLE_MEASURE, &fields, &Nfields);
  // XXX handle errors

  /* load region corresponding to selection above */
  if ((skylist = SelectRegions (RegionName, RegionList)) == NULL) goto escape;

  // XXX is this still needed?
  loadImages = FALSE;
  mosaicMode = FALSE;
  for (i = 0; !loadImages && (i < Nfields); i++) {
    if (fields[i].ID == MEAS_XCCD) loadImages = TRUE;
    if (fields[i].ID == MEAS_YCCD) loadImages = TRUE;
    if (fields[i].ID == MEAS_XMOSAIC) loadImages = mosaicMode = TRUE;
    if (fields[i].ID == MEAS_YMOSAIC) loadImages = mosaicMode = TRUE;
  }
  if (loadImages && !SetImageSelection (mosaicMode, ((RegionName == NULL) && (RegionList == NULL)))) goto escape;

  /* create storage vector */
  ALLOCATE (values, float, Nfields);
  ALLOCATE (vec, Vector *, Nreturn);
  for (i = 0; i < Nreturn; i++) {
    if (ISNUM(fields[i].name[0])) {
      sprintf (name, "v_%s", fields[i].name);
    } else {
      sprintf (name, "%s", fields[i].name);
    }
    if ((vec[i] = SelectVector (name, ANYVECTOR, TRUE)) == NULL) goto escape;
  }

  Npts = 0;
  NPTS = 1;

  // grab data from all selected sky regions
  Signal = signal (SIGINT, handle_interrupt);
  interrupt = FALSE;
  for (i = 0; (i < skylist[0].Nregions) && !interrupt; i++) {
    /* lock, load, unlock catalog */
    catalog.filename = skylist[0].filename[i];
    catalog.catflags = LOAD_AVES | LOAD_MEAS | LOAD_SECF;
    catalog.Nsecfilt = Nsecfilt;

    if (VERBOSE) gprint (GP_ERR, "trying %s (%d of %d)\n", catalog.filename, i, skylist[0].Nregions);
      
    // an error exit status here is a significant error
    if (!dvo_catalog_open (&catalog, NULL, FALSE, "r")) {
      gprint (GP_ERR, "ERROR: failure to open catalog file %s\n", catalog.filename);
      exit (2);
    }
    dvo_catalog_unlock (&catalog);

    /* XXX need to call dvo_catalog_chipcoords here passing the loaded images */

    for (j = 0; (j < catalog.Naverage) && !interrupt; j++) {
      m = catalog.average[j].offset;
      for (k = 0; (k < catalog.average[j].Nm); k++, m++) {

	// extract the relevant values for this measurement
	for (n = 0; n < Nfields; n++) {
	  values[n] = dbExtractMeasures (&catalog.average[j], &catalog.secfilt[j*Nsecfilt], &catalog.measure[m], &fields[n]);
	}
	// fprintf (stderr, "object: ave: %f, cat: %f, averef %d\n", fields[n].name, values[2], values[3], catalog.measure[m].averef);
	
	// test the conditional statement
	if (!dbBooleanCond (stack, Nstack, values)) continue;
	for (n = 0; n < Nreturn; n++) {
	  vec[n][0].elements[Npts] = values[n];
	  // fprintf (stderr, "keep : field: %s, value: %f\n", fields[n].name, values[n]);
	}
	Npts++;
	if (Npts >= NPTS) {
	  NPTS += 2000;
	  for (n = 0; n < Nreturn; n++) {
	    REALLOCATE (vec[n][0].elements, float, NPTS);
	  }
	}
      }
    }
    dvo_catalog_free (&catalog);
  }
  signal (SIGINT, Signal);
  interrupt = FALSE;

  for (n = 0; n < Nreturn; n++) {
    vec[n][0].Nelements = Npts;
    REALLOCATE (vec[n][0].elements, float, MAX(1,Npts));
  }
  dbFreeFields (fields, Nfields);
  dbFreeStack (stack, Nstack);

  FreeImageSelection ();
  SkyListFree (skylist, ((RegionName != NULL) || (RegionList != NULL)));

  if (RegionName != NULL) free (RegionName);
  if (RegionList != NULL) free (RegionList);
  return (TRUE);

usage:
  gprint (GP_ERR, "USAGE: mextract (value) [options]\n");
  gprint (GP_ERR, "  value: measure.parameter or photcode\n");
  return (FALSE);

escape:
  dbFreeFields (fields, Nfields);
  dbFreeStack (stack, Nstack);
  FreeImageSelection ();
  SkyListFree (skylist, ((RegionName != NULL) || (RegionList != NULL)));
  dvo_catalog_free (&catalog);
  if (RegionName != NULL) free (RegionName);
  if (RegionList != NULL) free (RegionList);
  return (FALSE);
}
