# include "dvomerge.h"

/* build the initial links assuming the table is sorted, 
   not partial, and has a correct set of average[].measureOffset,Nmeasure values */
off_t *init_measure_links (Average *average, off_t Naverage, Measure *measure, off_t Nmeasure) {

  off_t i, j, N;
  off_t *next;

  N = 0;

  ALLOCATE (next, off_t, Nmeasure);
  for (i = 0; i < Naverage; i++, N++) {
    for (j = 0; j < average[i].Nmeasure - 1; j++, N++) {
      next[N] = N + 1;
      if (N >= Nmeasure) {
	fprintf (stderr, "WARNING: N out of bounds (1)\n");
      }
    }
    next[N] = -1;
    if (N >= Nmeasure) {
      fprintf (stderr, "WARNING: N out of bounds (2)\n");
    }

    if (N >= Nmeasure) {
      fprintf (stderr, "overflow in init_measure_links\n");
      abort ();
    }
  }
  return (next);
}

/* average[].measureOffset, average[].Nmeasure are valid within an addstar run */
int add_meas_link (Average *average, off_t *next, off_t Nmeasure, off_t NMEASURE) {

  off_t k, m;

  /* if we have trouble, check validity of next[m] : m < Nmeasure */
  m = average[0].measureOffset;  

  for (k = 0; k < average[0].Nmeasure - 1; k++)  {
    m = next[m];
    if (m >= NMEASURE) {
      fprintf (stderr, "WARNING: m out of bounds (3)\n");
    }
  }

  /* set up references */
  next[Nmeasure] = -1;
  if (Nmeasure >= NMEASURE) {
    fprintf (stderr, "WARNING: Nmeasure out of bounds (1)\n");
  }

  if (m == -1) {
    average[0].measureOffset = Nmeasure;
  } else {
    next[m] = Nmeasure;
    if (m >= NMEASURE) {
      fprintf (stderr, "WARNING: m out of bounds (4)\n");
    }
  }

  return (TRUE);
}

Measure *sort_measure (Average *average, off_t Naverage, Measure *measure, off_t Nmeasure, off_t *next) {

  off_t i, k, n, N;
  Measure *tmpmeasure;

  /* fix order of Measure (memory intensive, but fast) */
  N = 0; 
  ALLOCATE (tmpmeasure, Measure, Nmeasure);
  for (i = 0; i < Naverage; i++) {
    n = average[i].measureOffset;
    average[i].measureOffset = N;
    for (k = 0; k < average[i].Nmeasure; k++, N++) {
      tmpmeasure[N] = measure[n]; 
      tmpmeasure[N].averef = i;
      n = next[n];
    }
  }
  free (measure);
  return (tmpmeasure);
}

/* construct measure links which are valid FOR THIS LOAD
 * - if we have a full load, we will get links which can
 *   be used by other programs (eg, relphot, etc)
 * - if we have a partial load, the links are only valid
 *   for that partial load
 */ 

off_t *build_measure_links (Average *average, off_t Naverage, Measure *measure, off_t Nmeasure) {

  off_t i, m, k, Nm, averef;
  off_t *next;

  ALLOCATE (next, off_t, Nmeasure);

  /* reset the Nm, offset values for average */
  for (i = 0; i < Naverage; i++) {
    average[i].measureOffset = -1;
    average[i].Nmeasure     =  0;
  }

  for (Nm = 0; Nm < Nmeasure; Nm++) {
    averef = measure[Nm].averef;
    m = average[averef].measureOffset;  
    next[Nm] = -1;

    if (m == -1) { /* no links yet for source */
      average[averef].measureOffset = Nm;
      average[averef].Nmeasure     = 1;
      continue;
    }

    for (k = 0; next[m] != -1; k++) {
      m = next[m];
      if (m >= Nmeasure) {
	fprintf (stderr, "WARNING: m out of bounds (1)\n");
      }
    }

    average[averef].Nmeasure = k + 2;
    next[m] = Nm;
    if (m >= Nmeasure) {
      fprintf (stderr, "WARNING: m out of bounds (2)\n");
    }
  }
  return (next);
}

/* build the initial links assuming the table is sorted */
off_t *init_missing_links (Average *average, off_t Naverage, Missing *missing, off_t Nmissing) {

  off_t i, j, N;
  off_t *next;

  N = 0;

  ALLOCATE (next, off_t, Nmissing);
  for (i = 0; i < Naverage; i++) {
    for (j = 0; j < average[i].Nmissing - 1; j++, N++) {
      next[N] = N + 1;
    }
    if (average[i].Nmissing > 0) {
      next[N] = -1;
      if (N >= Nmissing) {
	fprintf (stderr, "overflow in init_missing_links");
	abort ();
      }
      N++;
    }

  }
  return (next);
}

int add_miss_link (Average *average, off_t *next, off_t Nmissing) {

  off_t k, m;

  /* there may be 0 Nmiss; this is not true for Nmeas */
  if (average[0].Nmissing < 1) {
    average[0].missingOffset = Nmissing;
    next[Nmissing] = -1;
    return (TRUE);
  }

  m = average[0].missingOffset;  
  for (k = 0; k < average[0].Nmissing - 1; k++) m = next[m];
  /* set up references */
  next[Nmissing] = -1;
  next[m] = Nmissing;
  return (TRUE);
}

/* Missing does not carry enough information to reconstruct the links
   we must always save the missing table, if it exists */

Missing *sort_missing (Average *average, off_t Naverage, Missing *missing, off_t Nmissing, off_t *next) {

  off_t i, k, n, N;
  Missing *tmpmissing;

  /* fix order of Missing (memory intensive, but fast) */
  N = 0; 
  ALLOCATE (tmpmissing, Missing, Nmissing);
  for (i = 0; i < Naverage; i++) {
    n = average[i].missingOffset;
    average[i].missingOffset = N;
    for (k = 0; k < average[i].Nmissing; k++, N++) {
      tmpmissing[N] = missing[n]; 
      n = next[n];
    }
  }
  free (missing);
  return (tmpmissing);
}
