# include "relphot.h"

// apply the current calibration values to the measurements to determine the average
// magnitudes, applying the desired clipping analysis.  Note that this does not depend on
// the form of the image zero point measurement.  If there is a grid or map term, and this
// has been correctly propagated to the measurement, the average will respect that value.

int relphot_objects_parallel (SkyList *sky);

int relphot_objects (int hostID, char *hostpath) {

  off_t i, j, k;
  int Nsecfilt;

  SkyTable *sky = NULL;
  SkyList *skylist = NULL;
  Catalog catalog;

  // load the current sky table (layout of all SkyRegions) 
  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, TRUE, SKY_DEPTH, VERBOSE);
  SkyTableSetFilenames (sky, CATDIR, "cpt");
  
  // determine the populated SkyRegions overlapping the requested area (default depth)
  skylist = SkyListByPatch (sky, -1, &UserPatch);

  // XXX need to decide how to determine PARALLEL mode...
  if (PARALLEL && !hostID) {
    relphot_objects_parallel (skylist);
    return TRUE;
  }

  // load data from each region file, only use bright stars
  for (i = 0; i < skylist[0].Nregions; i++) {

    // does this host ID match the desired location for the table?
    if (!HostTableTestHost(skylist[0].regions[i], hostID)) continue;

    // set up the basic catalog info
    char hostfile[1024];
    snprintf (hostfile, 1024, "%s/%s.cpt", hostpath, skylist[0].regions[i]->name);
    catalog.filename  = hostID ? hostfile : skylist[0].filename[i];
    catalog.catformat = dvo_catalog_catformat (CATFORMAT);    // set the default catformat from config data
    catalog.catmode   = dvo_catalog_catmode (CATMODE);        // set the default catmode from config data
    catalog.catflags  = LOAD_AVES | LOAD_MEAS | LOAD_MISS | LOAD_SECF;
    catalog.Nsecfilt  = GetPhotcodeNsecfilt ();

    if (!dvo_catalog_open (&catalog, skylist[0].regions[i], VERBOSE, "w")) {
      fprintf (stderr, "ERROR: failure reading catalog %s\n", catalog.filename);
      exit (1);
    }
    if (!catalog.Naves_disk) {
      if (VERBOSE) fprintf (stderr, "no data in %s, skipping\n", catalog.filename);
      dvo_catalog_unlock (&catalog);
      dvo_catalog_free (&catalog);
      continue;
    }

    // reset the calculated average magnitudes (does not affect ubercal-tied measurements or images)
    if (RESET) {
      Nsecfilt = catalog.Nsecfilt;
      DVOSecfiltFlags secfiltBits = 
	ID_SECF_STAR_FEW    | 
	ID_SECF_STAR_POOR   | 
	ID_PHOTOM_PASS_0    | 
	ID_PHOTOM_PASS_1    | 
	ID_PHOTOM_PASS_2    | 
	ID_PHOTOM_PASS_3    | 
	ID_PHOTOM_PASS_4    |
	ID_SECF_USE_SYNTH   |
	ID_SECF_USE_UBERCAL |
	ID_SECF_HAS_STACK   |
	ID_SECF_HAS_PS1     |
	ID_SECF_OBJ_EXT     ;
      
      DVOAverageFlags astromBits = 
	ID_STAR_FIT_AVE   | 
	ID_STAR_FIT_PM    | 
	ID_STAR_FIT_PAR   | 
	ID_STAR_USE_AVE   | 
	ID_STAR_USE_PM    | 
	ID_STAR_USE_PAR   |
	ID_STAR_NO_ASTROM ; 
      
      for (j = 0; j < catalog.Naverage; j++) {
	catalog.average[j].flags &= astromBits; // reset all except astrometry bits
	catalog.average[j].psfQF     = NAN;     // reset (will be re-calculated here)
	catalog.average[j].psfQFperf = NAN;	// reset (will be re-calculated here)
	catalog.average[j].stargal   = NAN;	// reset (will be re-calculated here)
	for (k = 0; k < Nsecfilt; k++) {
	  dvo_secfilt_init (&catalog.secfilt[j*Nsecfilt + k]);
	  catalog.secfilt[j*Nsecfilt + k].flags &= ~secfiltBits; // XXX: only reset photom bits: 
	}
      }
    }

    populate_tiny_values(&catalog, DVO_TV_MEASURE | DVO_TV_AVERAGE);

    initMrel (&catalog, 1);
    setMrelFinal (&catalog, NULL, TRUE);

    if (!UPDATE) {
      dvo_catalog_unlock (&catalog);
      free_tiny_values(&catalog);
      dvo_catalog_free (&catalog);
      continue;
    }
    
    if (VERBOSE) fprintf (stderr, "saving catalog %s\n", catalog.filename);
    
    // we can optionally convert output format here
    // but it would be better to define a dvo crawler program to do this
    // catalog.catformat = DVO_FORMAT_PS1_V1;  
    dvo_catalog_save (&catalog, VERBOSE); 
    dvo_catalog_unlock (&catalog);
    free_tiny_values(&catalog);
    dvo_catalog_free (&catalog);
  }
  
  return (TRUE);
}

// CATDIR is supplied globally
# define DEBUG 1
int relphot_objects_parallel (SkyList *sky) {

  // launch the setphot_client jobs to the parallel hosts

  // load the list of hosts
  HostTable *table = HostTableLoad (CATDIR, sky->hosts);
  if (!table) {
    fprintf (stderr, "ERROR: failure reading Host Table %s for database %s\n", sky->hosts, CATDIR);
    exit (1);
  }    

  int i;
  for (i = 0; i < table->Nhosts; i++) {

    // ensure that the paths are absolute path names
    char *tmppath = abspath (table->hosts[i].pathname, DVO_MAX_PATH);
    free (table->hosts[i].pathname);
    table->hosts[i].pathname = tmppath;

    // options / arguments that can affect relphot_client -update-objects:
    // VERBOSE, VERBOSE2
    // KEEP_UBERCAL
    // RESET (-reset)
    // TimeSelect -time
    // DophotSelect
    // (note that psfQF is applied rigidly at 0.85, as is the galaxy test)
    // MAG_LIM
    // SIGMA_LIM
    // ImagSelect, ImagMin, ImagMax
    // MaxDensityUse, MaxDensityValue

    char command[1024];
    snprintf (command, 1024, "relphot_client -update-objects -hostID %d -D CATDIR %s -hostdir %s -region %f %f %f %f -statmode %s -D CAMERA %s -D STAR_TOOFEW %d -minerror %f", 
	      table->hosts[i].hostID, CATDIR, table->hosts[i].pathname, UserPatch.Rmin, UserPatch.Rmax, UserPatch.Dmin, UserPatch.Dmax, STATMODE, CAMERA, STAR_TOOFEW, MIN_ERROR);

    char tmpline[1024];
    if (VERBOSE)       { snprintf (tmpline, 1024, "%s -v",              command);                    strcpy (command, tmpline); }
    if (VERBOSE2)      { snprintf (tmpline, 1024, "%s -vv",             command); 		     strcpy (command, tmpline); }
    if (RESET)         { snprintf (tmpline, 1024, "%s -reset",          command); 		     strcpy (command, tmpline); }
    if (RESET_ZEROPTS) { snprintf (tmpline, 1024, "%s -reset-zpts",     command); 		     strcpy (command, tmpline); }
    if (UPDATE)        { snprintf (tmpline, 1024, "%s -update",         command); 		     strcpy (command, tmpline); }
    if (!KEEP_UBERCAL) { snprintf (tmpline, 1024, "%s -reset-ubercal",  command); 		     strcpy (command, tmpline); }
    if (SET_MREL_VERSION != 1) { snprintf (tmpline, 1024, "%s -set-mrel-version %d", command, SET_MREL_VERSION); strcpy (command, tmpline); }

    fprintf (stderr, "command: %s\n", command);

    if (PARALLEL_MANUAL) continue;

    if (PARALLEL_SERIAL) {
      int status = system (command);
      if (status) {
	fprintf (stderr, "ERROR running relphot_client\n");
	exit (2);
      }
    } else {
      // launch the job on the remote machine (no handshake)
      int errorInfo = 0;
      int pid = rconnect ("ssh", table->hosts[i].hostname, command, table->hosts[i].stdio, &errorInfo, FALSE);
      if (!pid) {
	if (DEBUG) fprintf (stderr, "failure to start %s (error %d)\n", table->hosts[i].hostname, errorInfo);
	exit (1);
      }
      table->hosts[i].pid = pid; // save for future reference
    }
  }

  if (PARALLEL_MANUAL) {
    fprintf (stderr, "run the relphot_client commands above.  when these are done, hit return\n");
    getchar();
  }
  if (!PARALLEL_MANUAL && !PARALLEL_SERIAL) {
    HostTableWaitJobsGetIO (table, __FILE__, __LINE__, VERBOSE);
  }

  return TRUE;
}      
