# include "dvomerge.h"

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

  int depth;
  off_t i, j, Ns, Ne;
  SkyTable *outsky, *insky;
  SkyList *inlist;
  Catalog incatalog, outcatalog;
  char filename[256], *input, *output;
  IDmapType IDmap;

  if (strcasecmp (argv[2], "into")) dvomerge_usage();

  input  = argv[1];
  output = argv[3];

  // since we are merging the input db into the output db, the output defines the photcode
  // table & db layout but, this requires the output to exist.  if it does not, instead use the
  // input.
  sprintf (filename, "%s/Photcodes.dat", output);
  if (!LoadPhotcodes (filename, NULL, FALSE)) {
    sprintf (filename, "%s/Photcodes.dat", input);
    if (!LoadPhotcodes (filename, NULL, FALSE)) {
      fprintf (stderr, "error loading photcode table: tried %s/Photcodes.dat and %s/Photcodes.dat\n", output, input);
      exit (1);
    }
    if (!check_dir_access (output, VERBOSE)) {
      fprintf (stderr, "error creating output database directory %s\n", output);
      exit (1);
    }	
    sprintf (filename, "%s/Photcodes.dat", output);
    if (!SavePhotcodesFITS (filename)) {
      fprintf (stderr, "error saving photcode table in %s/Photcodes.dat\n", output);
      exit (1);
    }	
  }

  dvomergeImagesUpdate (&IDmap, input, output);

  // load the sky table for the existing database
  insky = SkyTableLoadOptimal (input, NULL, NULL, FALSE, SKY_DEPTH_HST, VERBOSE);
  if (!insky) {
      Shutdown ("can't read SkyTable for %s", input);
  }
  SkyTableSetFilenames (insky, input, "cpt");

  // generate an output table populated at the desired depth
  outsky = SkyTableLoadOptimal (output, NULL, GSCFILE, TRUE, SKY_DEPTH, VERBOSE);
  if (!outsky) {
      Shutdown ("can't read or create SkyTable for %s", output);
  }
  SkyTableSetFilenames (outsky, output, "cpt");

  // loop over the populatable output tables; check for data in input in the corresponding regions

  SkyTablePopulatedRange (&Ns, &Ne, insky, 0);
  depth = insky[0].regions[Ns].depth;
  
  // loop over the populatable output regions
  for (i = 0; i < outsky[0].Nregions; i++) {
    if (!outsky[0].regions[i].table) continue;
    if (VERBOSE) fprintf (stderr, "output: %s\n", outsky[0].regions[i].name);

    // load / create output catalog (if catalog does not exist, it will be created)
    LoadCatalog (&outcatalog, &outsky[0].regions[i], outsky[0].filename[i], "w");

    // combine only tables at equal or larger depth
      
    // load in all of the tables from input for this region
    // SkyListByBounds will return neighbor catalogs if the boundaries exactly match (due to rounding).  Since the regions are not infinitely small, 
    // compare to a slightly reduced footprint
    float dPos = 2.0/3600.0;
    inlist = SkyListByBounds (insky, depth, outsky[0].regions[i].Rmin + dPos, outsky[0].regions[i].Rmax - dPos, outsky[0].regions[i].Dmin + dPos, outsky[0].regions[i].Dmax - dPos);
    for (j = 0; j < inlist[0].Nregions; j++) {
      if (VERBOSE) fprintf (stderr, "input : %s\n", inlist[0].regions[j][0].name);

      // load input catalog
      LoadCatalog (&incatalog, inlist[0].regions[j], inlist[0].filename[j], "r");

      // skip empty input catalogs
      if (!incatalog.Naves_disk) {
	dvo_catalog_unlock (&incatalog);
	dvo_catalog_free (&incatalog);
	continue;
      }
      dvo_update_image_IDs (&IDmap, &incatalog);
      merge_catalogs_old (&outsky[0].regions[i], &outcatalog, &incatalog, RADIUS);
      dvo_catalog_unlock (&incatalog);
      dvo_catalog_free (&incatalog);

      fprintf (stderr, "merged %s into %s\n", outsky[0].regions[i].name, inlist[0].regions[j][0].name);
    }
    SkyListFree (inlist);

    outcatalog.catflags = LOAD_AVES | LOAD_MEAS | LOAD_MISS | LOAD_SECF;
    dvo_catalog_save (&outcatalog, VERBOSE);
    dvo_catalog_unlock (&outcatalog);
    dvo_catalog_free (&outcatalog);
  }

  // save the output sky table copy
  sprintf (filename, "%s/SkyTable.fits", output);
  check_file_access (filename, TRUE, TRUE, VERBOSE);
  if (!SkyTableSave (outsky, filename)) {
    fprintf (stderr, "ERROR: failed to save sky table for %s\n", output);
    exit (1);
  }

  exit (0);
}

/*** update the image table ***/
int dvomergeImagesUpdate (IDmapType *IDmap, char *input, char *output) { 

  FITS_DB inDB;
  FITS_DB outDB;
  int    status;

  /*** load input1/Images.dat ***/
  sprintf (ImageCat, "%s/Images.dat", input);
  inDB.mode   = dvo_catalog_catmode (CATMODE);
  inDB.format = dvo_catalog_catformat (CATFORMAT);
  status       = dvo_image_lock (&inDB, ImageCat, 3600.0, LCK_XCLD);  // shorter timeout?
  if (!status) Shutdown ("ERROR: failure to lock image catalog %s", inDB.filename);

  // load the image table 
  if (inDB.dbstate == LCK_EMPTY) {
    Shutdown ("can't find input image catalog %s", inDB.filename);
  }
  if (!dvo_image_load (&inDB, VERBOSE, TRUE)) {
    Shutdown ("can't read input image catalog %s", inDB.filename);
  }

  /*** load output/Images.dat ***/
  sprintf (ImageCat, "%s/Images.dat", output);
  outDB.mode   = dvo_catalog_catmode (CATMODE);
  outDB.format = dvo_catalog_catformat (CATFORMAT);
  status       = dvo_image_lock (&outDB, ImageCat, 3600.0, LCK_XCLD);  // shorter timeout?
  if (!status) Shutdown ("ERROR: failure to lock image catalog %s", outDB.filename);

  /* load the image table */
  if (outDB.dbstate == LCK_EMPTY) {
    dvo_image_create (&outDB, GetZeroPoint());
  } else {
    if (!dvo_image_load (&outDB, VERBOSE, TRUE)) {
      Shutdown ("can't read output image catalog %s", outDB.filename);
    }
  }

  // convert database table to internal structure & add to output image db
  dvo_image_merge_dbs(IDmap, &outDB, &inDB);
  dvo_image_unlock (&inDB); // unlock input

  SetProtect (TRUE);
  dvo_image_save (&outDB, VERBOSE);
  SetProtect (FALSE);
  dvo_image_unlock (&outDB); // unlock output

  return TRUE;
}
