# include "dvomerge.h"

void sort_IDmap (IDmapType *IDmap);

// merge db2 into db1
int dvo_image_merge_dbs (IDmapType *IDmap, FITS_DB *out, FITS_DB *in) {

  Image *images;
  off_t Nimages;
  off_t Nout;
  off_t i, IDstart;
  int status;
 
  images = gfits_table_get_Image (&in[0].ftable, &Nimages, &in[0].swapped);
  ALLOCATE (IDmap->old, off_t, Nimages);
  ALLOCATE (IDmap->new, off_t, Nimages);
  IDmap->Nmap = Nimages;

 /* adjust header */
  Nout = 0;
  gfits_scan (&out[0].header, "NIMAGES", OFF_T_FMT, 1,  &Nout);
  status = gfits_scan (&out[0].header, "IMAGEID", OFF_T_FMT, 1,  &IDstart);
  if (!status) {
    IDstart = 1;
  }

  for (i = 0; i < Nimages; i++) {
    IDmap[0].old[i] = images[i].imageID;
    images[i].imageID = i + IDstart;
    IDmap[0].new[i] = images[i].imageID;
  }

  // sort IDmap->old,new on the basis of IDmap->old:
  sort_IDmap (IDmap);

  if (!out[0].swapped) {
    gfits_convert_Image ((Image *) out[0].ftable.buffer, sizeof(Image), Nout);
    out[0].swapped = TRUE;
  }

  Nout += Nimages;
  IDstart += Nimages;
  gfits_modify (&out[0].header, "NIMAGES", OFF_T_FMT, 1,  Nout);
  gfits_modify (&out[0].header, "IMAGEID", OFF_T_FMT, 1,  IDstart);

  gfits_add_rows (&out[0].ftable, (char *) images, Nimages, sizeof(Image));
  return TRUE;
}

// XXX isn't the map just ID_new = ID_old + offset ??
off_t dvo_map_image_ID (IDmapType *IDmap, off_t oldID) {

  // off_t i;
  // 
  // for (i = 0; i < IDmap->Nmap; i++) {
  //   if (IDmap->old[i] != oldID) continue;
  //   return (IDmap->new[i]);
  // }

  off_t Nlo, Nhi, N;

  // find the a close entry below desired ID
  Nlo = 0; Nhi = IDmap->Nmap;
  while (Nhi - Nlo > 10) {
    N = 0.5*(Nlo + Nhi);
    if (IDmap->old[N] < oldID) {
      Nlo = MAX(N, 0);
    } else {
      Nhi = MIN(N + 1, IDmap->Nmap);
    }
  }

  // search for the desired ID starting from Nlo, give up at Nhi
  for (N = Nlo; N < Nhi; N++) { 
    if (IDmap->old[N] < oldID) continue;
    if (IDmap->old[N] > oldID) return 0;
    return (IDmap->new[N]);
  }
  return 0;
}

int dvo_update_image_IDs (IDmapType *IDmap, Catalog *catalog) {

  off_t i, oldID, newID;

  for (i = 0; i < catalog[0].Nmeasure; i++) {
    oldID = catalog[0].measure[i].imageID;
    if (oldID == 0) continue;

    newID = dvo_map_image_ID (IDmap, oldID);
    if (newID == 0) {
      fprintf (stderr, "cannot find image ID "OFF_T_FMT"\n",  oldID);
      exit (2);
    }
    catalog[0].measure[i].imageID = newID;
  }
  return TRUE;
}

// sort two times vectors and an index by first time vector
void sort_IDmap (IDmapType *IDmap) {

# define SWAPFUNC(A,B){ off_t tmp_old, tmp_new;	   \
  tmp_old = IDmap->old[A]; IDmap->old[A] = IDmap->old[B]; IDmap->old[B] = tmp_old; \
  tmp_new = IDmap->new[A]; IDmap->new[A] = IDmap->new[B]; IDmap->new[B] = tmp_new; \
}
# define COMPARE(A,B)(IDmap->old[A] < IDmap->old[B])

  OHANA_SORT (IDmap->Nmap, COMPARE, SWAPFUNC);

# undef SWAPFUNC
# undef COMPARE

}

