# include "relastro.h"

int bcatalog (Catalog *subcatalog, Catalog *catalog) {
  
  int i, j, k, offset, found;
  int NAVERAGE, NMEASURE, Naverage, Nmeasure, Nm, Nsecfilt;
  float mag;
  int mask;
  PhotCode *code;

  // XXX in the future, use catalog[0].Nsecfilt only?  allow catalogs to have variable Nsecfilt?
  Nsecfilt = GetPhotcodeNsecfilt ();
  assert (catalog[0].Nsecfilt == Nsecfilt);

  /* we are moving only the subset of measurements from catalog[0] to subcatalog[0] */
  NAVERAGE = 50;
  NMEASURE = 1000;
  ALLOCATE (subcatalog[0].average, Average, NAVERAGE);
  ALLOCATE (subcatalog[0].secfilt, SecFilt, NAVERAGE*Nsecfilt);
  ALLOCATE (subcatalog[0].measure, Measure, NMEASURE);
  Nmeasure = Naverage = 0;

  /* exclude stars not in range or with too few measurements */
  for (i = 0; i < catalog[0].Naverage; i++) {
    if (catalog[0].average[i].Nmeasure < 2) continue; 

    /* start with all stars good */
    subcatalog[0].average[Naverage] = catalog[0].average[i];
    subcatalog[0].average[Naverage].measureOffset = Nmeasure;
    for (j = 0; j < Nsecfilt; j++) {
      subcatalog[0].secfilt[Nsecfilt*Naverage+j] = catalog[0].secfilt[Nsecfilt*i+j];
    }

    if (RESET) {
      // XXX reset the ra,dec coords?
      // XXX define astrometry vs photometry average.dbFlags
      // XXX put photometry flags in secfilt (ie, per average mag?)
      subcatalog[0].average[Naverage].code &= ~ID_STAR_FEW;
      subcatalog[0].average[Naverage].code &= ~ID_STAR_POOR;
    }

    Nm = 0;
    for (j = 0; j < catalog[0].average[i].Nmeasure; j++) {

      offset = catalog[0].average[i].measureOffset + j;

      /* select measurements by photcode, or equiv photcode, if specified */
      if (NphotcodesKeep > 0) {
	found = FALSE;
	for (k = 0; (k < NphotcodesKeep) && !found; k++) {
	  if (photcodesKeep[k][0].code == catalog[0].measure[offset].photcode) found = TRUE;
	  if (photcodesKeep[k][0].code == GetPhotcodeEquivCodebyCode(catalog[0].measure[offset].photcode)) found = TRUE;
	}
	if (!found) continue;
      }
      if (NphotcodesSkip > 0) {
	found = FALSE;
	for (k = 0; (k < NphotcodesSkip) && !found; k++) {
	  if (photcodesSkip[k][0].code == catalog[0].measure[offset].photcode) found = TRUE;
	  if (photcodesSkip[k][0].code == GetPhotcodeEquivCodebyCode(catalog[0].measure[offset].photcode)) found = TRUE;
	}
	if (found) continue;
      }

      /* select measurements by time */
      if (TimeSelect) {
	if (catalog[0].measure[offset].t < TSTART) continue;
	if (catalog[0].measure[offset].t > TSTOP) continue;
      }

      /* select measurements by quality */
      if (DophotSelect && (catalog[0].measure[offset].dophot != DophotValue)) continue;

      /* select measurements by quality */
      if (PhotFlagSelect) {
	if (PhotFlagBad) {
	  mask = PhotFlagBad;
	} else {
	  code = GetPhotcodebyCode (catalog[0].measure[offset].photcode);
	  mask = code[0].astromBadMask;
	}
	if (mask & catalog[0].measure[offset].photFlags) continue;
      }

      /* select measurements by measurement error */
      if ((SIGMA_LIM > 0) && (catalog[0].measure[offset].dM > SIGMA_LIM)) continue;

      /* select measurements by mag limit */
      if (ImagSelect) {
	mag = PhotInst (&catalog[0].measure[offset]);
	if (mag < ImagMin) continue;
	if (mag > ImagMax) continue;
      }

      // re-assess on each run of relastro if a measurement should be used

      // NOCAL : this flag is used to mark measurements which must be ignored for this
      // analysis.  an example would be time ranges or photcodes which are ignored.  NOCAL
      // is internal only; it is not written out.

      // SKIP : this flag is used to mark measurements currently ignored, but may be
      // allowed before the analysis is complete.  for example, a star with measurements
      // only near the edge of images will have this flag set for most of the analysis,
      // but before the final average properties are calculated, these measurements may be
      // allowed.

      subcatalog[0].measure[Nmeasure].dbFlags &= ~ID_MEAS_SKIP_ASTROM;
      subcatalog[0].measure[Nmeasure].dbFlags &= ~ID_MEAS_NOCAL;
      subcatalog[0].measure[Nmeasure]          = catalog[0].measure[offset];
      subcatalog[0].measure[Nmeasure].averef   = Naverage;
      if (RESET) { 
	subcatalog[0].measure[Nmeasure].dbFlags &= ~ID_MEAS_POOR_ASTROM;
	subcatalog[0].measure[Nmeasure].dbFlags &= ~ID_MEAS_AREA;
      }
      Nmeasure ++;
      Nm ++;
      if (Nmeasure == NMEASURE) {
	NMEASURE += 1000;
	REALLOCATE (subcatalog[0].measure, Measure, NMEASURE);
      }
    }
    subcatalog[0].average[Naverage].Nmeasure = Nm;
    Naverage ++;
    if (Naverage == NAVERAGE) {
      NAVERAGE += 50;
      REALLOCATE (subcatalog[0].average, Average, NAVERAGE);
      REALLOCATE (subcatalog[0].secfilt, SecFilt, NAVERAGE*Nsecfilt);
    }
  }
  REALLOCATE (subcatalog[0].average, Average, MAX (Naverage, 1));
  REALLOCATE (subcatalog[0].measure, Measure, MAX (Nmeasure, 1));
  REALLOCATE (subcatalog[0].secfilt, SecFilt, Nsecfilt*MAX (Naverage, 1));
  subcatalog[0].Naverage = Naverage;
  subcatalog[0].Nmeasure = Nmeasure;
  subcatalog[0].Nsecfilt = catalog[0].Nsecfilt;
  subcatalog[0].Nsecf_mem = Naverage * Nsecfilt;
  assert (Nsecfilt == catalog[0].Nsecfilt);

  if (VERBOSE) {
    fprintf (stderr, "%d: using %d stars (%d measures) for catalog\n", i, 
	     subcatalog[0].Naverage, subcatalog[0].Nmeasure);
   }
  return (TRUE);
}
