# include <dvo.h>

/* read data from raw-style catalog file; set data format values based on file */

int dvo_catalog_load_raw (Catalog *catalog, int VERBOSE) {
  
  int Nitems, nitems;
  int i, Nmeas, Nmiss, size;
  int NewMeasure, Nskip;
  int AverageSize, MeasureSize, MissingSize, SecFiltSize;
  FILE *f;
  struct stat filestatus;
  char format[80], telescope[80];

  f = catalog[0].f;

  /* move pointer past header -- must be already read (load_catalog) */
  fseek (f, catalog[0].header.size, SEEK_SET);

  /* get the components from the header */
  catalog[0].Naverage = catalog[0].Nmeasure = catalog[0].Nmissing = catalog[0].Nsecfilt = 0;
  if (!gfits_scan (&catalog[0].header, "NSTARS",   "%d", 1, &catalog[0].Naverage)) return (FALSE);
  if (!gfits_scan (&catalog[0].header, "NMEAS",    "%d", 1, &catalog[0].Nmeasure)) return (FALSE);
  if (!gfits_scan (&catalog[0].header, "NMISS",    "%d", 1, &catalog[0].Nmissing)) return (FALSE);
  if (!gfits_scan (&catalog[0].header, "NSECFILT", "%d", 1, &catalog[0].Nsecfilt)) catalog[0].Nsecfilt = 0;

  /* determine catalog format */
  catalog[0].catformat = DVO_FORMAT_UNDEF;
  if (gfits_scan (&catalog[0].header, "FORMAT",  "%s", 1, format)) {
    if (!strcmp (format, "INTERNAL")) catalog[0].catformat = DVO_FORMAT_INTERNAL;
    if (!strcmp (format, "LONEOS")) catalog[0].catformat = DVO_FORMAT_LONEOS;
    if (!strcmp (format, "ELIXIR")) catalog[0].catformat = DVO_FORMAT_ELIXIR;
    if (!strcmp (format, "PANSTARRS")) catalog[0].catformat = DVO_FORMAT_PANSTARRS;
    if (!strcmp (format, "PMTEST")) catalog[0].catformat = DVO_FORMAT_PMTEST;
    if (catalog[0].catformat != DVO_FORMAT_UNDEF) goto got_format;
  }
  /* special cases: old versions of the DB tables which were poorly identified */
  if (gfits_scan (&catalog[0].header, "NEWMEAS",  "%t", 1, &NewMeasure)) {
    catalog[0].catformat = DVO_FORMAT_ELIXIR;
    goto got_format;
  }
  if (gfits_scan (&catalog[0].header, "TELESCOP",  "%s", 1, telescope)) {
    if (!strncmp (telescope, "LONEOS", strlen("LONEOS"))) {
      catalog[0].catformat = DVO_FORMAT_LONEOS;
      goto got_format;
    }
    if (!strncmp (telescope, "1.3m McGraw-Hill", strlen("1.3m McGraw-Hill"))) {
      catalog[0].catformat = DVO_FORMAT_ELIXIR;
      goto got_format;
    }
  }
  if (VERBOSE) fprintf (stderr, "cannot determine catalog format\n");
  return (FALSE);

got_format:
  /* determine datatype sizes */
  switch (catalog[0].catformat) {
    case DVO_FORMAT_INTERNAL:
      AverageSize = sizeof(Average);
      MeasureSize = sizeof(Measure);
      SecFiltSize = sizeof (SecFilt);
      break;
    case DVO_FORMAT_LONEOS:
      AverageSize = sizeof(AverageLoneos);
      MeasureSize = sizeof(MeasureLoneos);
      SecFiltSize = sizeof (SecFiltLoneos);
      break;
    case DVO_FORMAT_ELIXIR:
      AverageSize = sizeof(AverageElixir);
      MeasureSize = sizeof(MeasureElixir);
      SecFiltSize = sizeof (SecFiltElixir);
      break;
    case DVO_FORMAT_PANSTARRS:
      AverageSize = sizeof(AveragePanstarrs);
      MeasureSize = sizeof(MeasurePanstarrs);
      SecFiltSize = sizeof (SecFiltPanstarrs);
      break;
    case DVO_FORMAT_PMTEST:
      AverageSize = sizeof(AveragePMtest);
      MeasureSize = sizeof(MeasurePanstarrs);
      SecFiltSize = sizeof (SecFiltPanstarrs);
      break;
    default:
      fprintf (stderr, "programming error in phot_catalog_raw\n");
      exit (2);
  }
  MissingSize = sizeof (Missing);

  /* predicted file size - for double checking data validity */
  size = catalog[0].header.size;
  size += AverageSize * catalog[0].Naverage;
  size += MeasureSize * catalog[0].Nmeasure;
  size += MissingSize * catalog[0].Nmissing;
  size += SecFiltSize * catalog[0].Nsecfilt * catalog[0].Naverage;

  /* check that file size makes sense */
  if (stat (catalog[0].filename, &filestatus) == -1) {
    if (VERBOSE) fprintf (stderr, "failed to get status of catalog\n");
    return (FALSE);
  }
  if (size > filestatus.st_size) {
    if (VERBOSE) {
      fprintf (stderr, "star catalog has inconsistent size\n");
      fprintf (stderr, "average: %d = %d bytes\n", catalog[0].Naverage, catalog[0].Naverage*AverageSize);
      fprintf (stderr, "measure: %d = %d bytes\n", catalog[0].Nmeasure, catalog[0].Nmeasure*MeasureSize);
      fprintf (stderr, "missing: %d = %d bytes\n", catalog[0].Nmissing, catalog[0].Nmissing*MissingSize);
      fprintf (stderr, "secfilt: %d = %d bytes\n", catalog[0].Nsecfilt, catalog[0].Nsecfilt*SecFiltSize*catalog[0].Naverage);
      fprintf (stderr, "expect: %d, found: %d\n", size, (int)filestatus.st_size);
    }
    return (FALSE);
  } 
  if (size < filestatus.st_size) {
    if (VERBOSE) fprintf (stderr, "warning: file larger than expected\n");
  } 

  if (catalog[0].Naverage == 0) {
    if (VERBOSE) fprintf (stderr, "no stars yet in catalog %s\n", catalog[0].filename);
    return (TRUE);
  }

  /* read and convert the averages (use a macro to clean this up?) */
  if (catalog[0].catflags & LOAD_AVES) {
    catalog[0].average = ReadRawAverage (catalog[0].f, catalog[0].Naverage, catalog[0].catformat);
  } else {
    /* skip over averages */
    Nskip = catalog[0].Naverage * AverageSize;
    fseek (f, Nskip, SEEK_CUR); 
  }    
  
  /* read and convert the measures (use a macro to clean this up?) */
  if (catalog[0].catflags & LOAD_MEAS) {
    catalog[0].measure = ReadRawMeasure (catalog[0].f, catalog[0].Nmeasure, catalog[0].catformat);
  } else {
    /* skip over measures */
    Nskip = catalog[0].Nmeasure * MeasureSize;
    fseek (f, Nskip, SEEK_CUR); 
  }    

  /* read and convert missing */
  if (catalog[0].catflags & LOAD_MISS) {
    ALLOCATE (catalog[0].missing, Missing, MAX (catalog[0].Nmissing, 1));
    Nitems = catalog[0].Nmissing;
    nitems = fread (catalog[0].missing, MissingSize, Nitems, f);
    if (nitems != Nitems) {
      if (VERBOSE) fprintf (stderr, "failed to read missing from catalog file %s (%d vs %d)\n", catalog[0].filename, nitems, Nitems);
      return (FALSE);
    }
    gfits_convert_Missing (catalog[0].missing, MissingSize, Nitems);
  } else {
    /* skip over missings */
    Nskip = catalog[0].Nmissing * MissingSize;
    fseek (f, Nskip, SEEK_CUR); 
  }
  
  /* read and convert secfilt */
  if (catalog[0].catflags & LOAD_SECF) {
    Nitems = catalog[0].Naverage * catalog[0].Nsecfilt;
    catalog[0].secfilt = ReadRawSecFilt (catalog[0].f, Nitems, catalog[0].catformat);
  } else {
    /* skip over secfilts */
    Nskip = catalog[0].Nsecfilt * catalog[0].Naverage * SecFiltSize;
    fseek (f, Nskip, SEEK_CUR); 
  }

  if (VERBOSE) fprintf (stderr, "read %d stars from catalog file %s (%d measurements, %d missing, %d secondary filters)\n", 
			catalog[0].Naverage, catalog[0].filename, catalog[0].Nmeasure, catalog[0].Nmissing, catalog[0].Nsecfilt);

  /* check data integrity */
  if (catalog[0].catflags & LOAD_AVES) {
    for (i = Nmeas = Nmiss = 0; i < catalog[0].Naverage; i++) {
      Nmeas += catalog[0].average[i].Nm; 
      Nmiss += catalog[0].average[i].Nn; 
    }
    if ((Nmeas != catalog[0].Nmeasure) || (Nmiss != catalog[0].Nmissing)) {
      if (VERBOSE) {
	fprintf (stderr, "****** data in catalog %s is corrupt, sums don't check\n", catalog[0].filename);
	fprintf (stderr, "****** Nmeas: %d, %d\n", Nmeas, catalog[0].Nmeasure);
	fprintf (stderr, "****** Nmiss: %d, %d\n", Nmiss, catalog[0].Nmissing);
      }
      return (FALSE);
    }
  }

  /* save the current number so we can do partial updates */
  catalog[0].Nave_disk  = catalog[0].Naverage;
  catalog[0].Nmeas_disk = catalog[0].Nmeasure;
  catalog[0].Nmiss_disk = catalog[0].Nmissing;

  return (TRUE);
}

int dvo_catalog_save_raw (Catalog *catalog, char VERBOSE) {

  int Nitems, nitems;
  FILE *f;

  if (catalog[0].Naverage == 0) {
    if (VERBOSE) fprintf (stderr, "no stars in catalog, skipping\n");
    return (TRUE);
  }

  /* make sure header is consistent with data */
  gfits_modify (&catalog[0].header, "NSTARS",   "%d", 1, catalog[0].Naverage);
  gfits_modify (&catalog[0].header, "NMEAS",    "%d", 1, catalog[0].Nmeasure);
  gfits_modify (&catalog[0].header, "NMISS",    "%d", 1, catalog[0].Nmissing);
  gfits_modify (&catalog[0].header, "NSECFILT", "%d", 1, catalog[0].Nsecfilt);

  /* specify the appropriate data format */
  if (catalog[0].catformat == DVO_FORMAT_INTERNAL)  gfits_modify (&catalog[0].header, "FORMAT", "%s", 1, "INTERNAL");
  if (catalog[0].catformat == DVO_FORMAT_LONEOS)    gfits_modify (&catalog[0].header, "FORMAT", "%s", 1, "LONEOS");
  if (catalog[0].catformat == DVO_FORMAT_ELIXIR)    gfits_modify (&catalog[0].header, "FORMAT", "%s", 1, "ELIXIR");
  if (catalog[0].catformat == DVO_FORMAT_PANSTARRS) gfits_modify (&catalog[0].header, "FORMAT", "%s", 1, "PANSTARRS");
  if (catalog[0].catformat == DVO_FORMAT_PMTEST)    gfits_modify (&catalog[0].header, "FORMAT", "%s", 1, "PMTEST");

  /* rewind file pointers and truncate file */
  f = catalog[0].f;
  fseek (f, 0, SEEK_SET);
  ftruncate (fileno (catalog[0].f), 0);

  /* write header data (use gfits_write_header?) */
  nitems = fwrite (catalog[0].header.buffer, 1, catalog[0].header.size, f);
  if (nitems != catalog[0].header.size) {
    if (VERBOSE) fprintf (stderr, "failed to write header\n");
    return (FALSE);
  }

  /* write averages and measures */
  WriteRawAverage (f, catalog[0].average, catalog[0].Naverage, catalog[0].catformat);
  WriteRawMeasure (f, catalog[0].measure, catalog[0].Nmeasure, catalog[0].catformat);

  /* write missing data */
  Nitems = catalog[0].Nmissing;
  gfits_convert_Missing (catalog[0].missing, sizeof(Missing), Nitems);
  nitems = fwrite (catalog[0].missing, sizeof(Missing), Nitems, f);
  if (nitems != Nitems) {
    if (VERBOSE) fprintf (stderr, "failed to write catalog file missing %s\n", catalog[0].filename);
    return (FALSE);
  }

  Nitems = catalog[0].Naverage * catalog[0].Nsecfilt;
  WriteRawSecFilt (f, catalog[0].secfilt, Nitems, catalog[0].catformat);
  return (TRUE);
}

/*** 
     some warnings:
     - need to be wary of exit condition errors
***/

/** Average / Raw Table conversions **/

Average *ReadRawAverage (FILE *f, int Naverage, int format) {

  int nitems;
  Average *average;
  AverageElixir *tmpAverageElixir;
  AverageLoneos *tmpAverageLoneos;
  AveragePanstarrs *tmpAveragePanstarrs;
  AveragePMtest *tmpAveragePMtest;

  switch (format) {
    case DVO_FORMAT_INTERNAL:
      ALLOCATE (average, Average, MAX (Naverage, 1));
      nitems = fread (average, sizeof(Average), Naverage, f);
      if (nitems != Naverage) {
	fprintf (stderr, "failed to read averages (%d vs %d)\n", nitems, Naverage);
	return (NULL);
      }
      gfits_convert_Average (average, sizeof(Average), Naverage);
      break;
    case DVO_FORMAT_ELIXIR:
      ALLOCATE (tmpAverageElixir, AverageElixir, MAX (Naverage, 1));
      nitems = fread (tmpAverageElixir, sizeof(AverageElixir), Naverage, f);
      if (nitems != Naverage) {
	fprintf (stderr, "failed to read averages (%d vs %d)\n", nitems, Naverage);
	return (NULL);
      }
      gfits_convert_AverageElixir (tmpAverageElixir, sizeof(AverageElixir), Naverage);
      average = AverageElixirToInternal (tmpAverageElixir, Naverage);
      free (tmpAverageElixir);
      break;
    case DVO_FORMAT_LONEOS:
      ALLOCATE (tmpAverageLoneos, AverageLoneos, MAX (Naverage, 1));
      nitems = fread (tmpAverageLoneos, sizeof(AverageLoneos), Naverage, f);
      if (nitems != Naverage) {
	fprintf (stderr, "failed to read averages (%d vs %d)\n", nitems, Naverage);
	return (NULL);
      }
      gfits_convert_AverageLoneos (tmpAverageLoneos, sizeof(AverageLoneos), Naverage);
      average = AverageLoneosToInternal (tmpAverageLoneos, Naverage);
      free (tmpAverageLoneos);
      break;
    case DVO_FORMAT_PANSTARRS:
      ALLOCATE (tmpAveragePanstarrs, AveragePanstarrs, MAX (Naverage, 1));
      nitems = fread (tmpAveragePanstarrs, sizeof(AveragePanstarrs), Naverage, f);
      if (nitems != Naverage) {
	fprintf (stderr, "failed to read averages (%d vs %d)\n", nitems, Naverage);
	return (NULL);
      }
      gfits_convert_AveragePanstarrs (tmpAveragePanstarrs, sizeof(AveragePanstarrs), Naverage);
      average = AveragePanstarrsToInternal (tmpAveragePanstarrs, Naverage);
      free (tmpAveragePanstarrs);
      break;
    case DVO_FORMAT_PMTEST:
      ALLOCATE (tmpAveragePMtest, AveragePMtest, MAX (Naverage, 1));
      nitems = fread (tmpAveragePMtest, sizeof(AveragePMtest), Naverage, f);
      if (nitems != Naverage) {
	fprintf (stderr, "failed to read averages (%d vs %d)\n", nitems, Naverage);
	return (NULL);
      }
      gfits_convert_AveragePMtest (tmpAveragePMtest, sizeof(AveragePMtest), Naverage);
      average = AveragePMtestToInternal (tmpAveragePMtest, Naverage);
      free (tmpAveragePMtest);
      break;
    default:
      fprintf (stderr, "error reading measures\n");
      return (NULL);
  }
  return (average);
}

/* accepts and converts internal average formats and outputs 
   raw data in the specified format */
int WriteRawAverage (FILE *f, Average *average, int Naverage, int format) {

  int nitems;
  AverageElixir *tmpAverageElixir;
  AverageLoneos *tmpAverageLoneos;
  AveragePanstarrs *tmpAveragePanstarrs;
  AveragePMtest *tmpAveragePMtest;

  switch (format) {
    case DVO_FORMAT_INTERNAL:
      gfits_convert_Average (average, sizeof(Average), Naverage);
      nitems = fwrite (average, sizeof(Average), Naverage, f);
      if (nitems != Naverage) {
	fprintf (stderr, "failed to write averages (%d vs %d)\n", nitems, Naverage);
	return (FALSE);
      }
      break;
    case DVO_FORMAT_ELIXIR:
      tmpAverageElixir = AverageInternalToElixir (average, Naverage);
      gfits_convert_AverageElixir (tmpAverageElixir, sizeof(AverageElixir), Naverage);
      nitems = fwrite (tmpAverageElixir, sizeof(AverageElixir), Naverage, f);
      free (tmpAverageElixir);
      if (nitems != Naverage) {
	fprintf (stderr, "failed to write averages (%d vs %d)\n", nitems, Naverage);
	return (FALSE);
      }
      break;
    case DVO_FORMAT_LONEOS:
      tmpAverageLoneos = AverageInternalToLoneos (average, Naverage);
      gfits_convert_AverageLoneos (tmpAverageLoneos, sizeof(AverageLoneos), Naverage);
      nitems = fwrite (tmpAverageLoneos, sizeof(AverageLoneos), Naverage, f);
      free (tmpAverageLoneos);
      if (nitems != Naverage) {
	fprintf (stderr, "failed to write averages (%d vs %d)\n", nitems, Naverage);
	return (FALSE);
      }
      break;
    case DVO_FORMAT_PANSTARRS:
      tmpAveragePanstarrs = AverageInternalToPanstarrs (average, Naverage);
      gfits_convert_AveragePanstarrs (tmpAveragePanstarrs, sizeof(AveragePanstarrs), Naverage);
      nitems = fwrite (tmpAveragePanstarrs, sizeof(AveragePanstarrs), Naverage, f);
      free (tmpAveragePanstarrs);
      if (nitems != Naverage) {
	fprintf (stderr, "failed to write averages (%d vs %d)\n", nitems, Naverage);
	return (FALSE);
      }
      break;
    case DVO_FORMAT_PMTEST:
      tmpAveragePMtest = AverageInternalToPMtest (average, Naverage);
      gfits_convert_AveragePMtest (tmpAveragePMtest, sizeof(AveragePMtest), Naverage);
      nitems = fwrite (tmpAveragePMtest, sizeof(AveragePMtest), Naverage, f);
      free (tmpAveragePMtest);
      if (nitems != Naverage) {
	fprintf (stderr, "failed to write averages (%d vs %d)\n", nitems, Naverage);
	return (FALSE);
      }
      break;
    default:
      fprintf (stderr, "error writing averages\n");
      return (FALSE);
  }
  return (TRUE);
}

/** Average / Raw Table conversions **/

Measure *ReadRawMeasure (FILE *f, int Nmeasure, int format) {

  int nitems;
  Measure *measure;
  MeasureElixir *tmpMeasureElixir;
  MeasureLoneos *tmpMeasureLoneos;
  MeasurePanstarrs *tmpMeasurePanstarrs;

  switch (format) {
    case DVO_FORMAT_INTERNAL:
      ALLOCATE (measure, Measure, MAX (Nmeasure, 1));
      nitems = fread (measure, sizeof(Measure), Nmeasure, f);
      if (nitems != Nmeasure) {
	fprintf (stderr, "failed to read measures (%d vs %d)\n", nitems, Nmeasure);
	return (NULL);
      }
      gfits_convert_Measure (measure, sizeof(Measure), Nmeasure);
      break;
    case DVO_FORMAT_ELIXIR:
      ALLOCATE (tmpMeasureElixir, MeasureElixir, MAX (Nmeasure, 1));
      nitems = fread (tmpMeasureElixir, sizeof(MeasureElixir), Nmeasure, f);
      if (nitems != Nmeasure) {
	fprintf (stderr, "failed to read measures (%d vs %d)\n", nitems, Nmeasure);
	return (NULL);
      }
      gfits_convert_MeasureElixir (tmpMeasureElixir, sizeof(MeasureElixir), Nmeasure);
      measure = MeasureElixirToInternal (tmpMeasureElixir, Nmeasure);
      free (tmpMeasureElixir);
      break;
    case DVO_FORMAT_LONEOS:
      ALLOCATE (tmpMeasureLoneos, MeasureLoneos, MAX (Nmeasure, 1));
      nitems = fread (tmpMeasureLoneos, sizeof(MeasureLoneos), Nmeasure, f);
      if (nitems != Nmeasure) {
	fprintf (stderr, "failed to read measures (%d vs %d)\n", nitems, Nmeasure);
	return (NULL);
      }
      gfits_convert_MeasureLoneos (tmpMeasureLoneos, sizeof(MeasureLoneos), Nmeasure);
      measure = MeasureLoneosToInternal (tmpMeasureLoneos, Nmeasure);
      free (tmpMeasureLoneos);
      break;
    case DVO_FORMAT_PANSTARRS:
    case DVO_FORMAT_PMTEST:
      ALLOCATE (tmpMeasurePanstarrs, MeasurePanstarrs, MAX (Nmeasure, 1));
      nitems = fread (tmpMeasurePanstarrs, sizeof(MeasurePanstarrs), Nmeasure, f);
      if (nitems != Nmeasure) {
	fprintf (stderr, "failed to read measures (%d vs %d)\n", nitems, Nmeasure);
	return (NULL);
      }
      gfits_convert_MeasurePanstarrs (tmpMeasurePanstarrs, sizeof(MeasurePanstarrs), Nmeasure);
      measure = MeasurePanstarrsToInternal (tmpMeasurePanstarrs, Nmeasure);
      free (tmpMeasurePanstarrs);
      break;
    default:
      fprintf (stderr, "error reading measures\n");
      return (NULL);
  }
  return (measure);
}

/* accepts and converts internal measure formats and outputs 
   raw data in the specified format */
int WriteRawMeasure (FILE *f, Measure *measure, int Nmeasure, int format) {

  int nitems;
  MeasureElixir *tmpMeasureElixir;
  MeasureLoneos *tmpMeasureLoneos;
  MeasurePanstarrs *tmpMeasurePanstarrs;

  switch (format) {
    case DVO_FORMAT_INTERNAL:
      gfits_convert_Measure (measure, sizeof(Measure), Nmeasure);
      nitems = fwrite (measure, sizeof(Measure), Nmeasure, f);
      if (nitems != Nmeasure) {
	fprintf (stderr, "failed to write measures (%d vs %d)\n", nitems, Nmeasure);
	return (FALSE);
      }
      break;
    case DVO_FORMAT_ELIXIR:
      tmpMeasureElixir = MeasureInternalToElixir (measure, Nmeasure);
      gfits_convert_MeasureElixir (tmpMeasureElixir, sizeof(MeasureElixir), Nmeasure);
      nitems = fwrite (tmpMeasureElixir, sizeof(MeasureElixir), Nmeasure, f);
      free (tmpMeasureElixir);
      if (nitems != Nmeasure) {
	fprintf (stderr, "failed to write measures (%d vs %d)\n", nitems, Nmeasure);
	return (FALSE);
      }
      break;
    case DVO_FORMAT_LONEOS:
      tmpMeasureLoneos = MeasureInternalToLoneos (measure, Nmeasure);
      gfits_convert_MeasureLoneos (tmpMeasureLoneos, sizeof(MeasureLoneos), Nmeasure);
      nitems = fwrite (tmpMeasureLoneos, sizeof(MeasureLoneos), Nmeasure, f);
      free (tmpMeasureLoneos);
      if (nitems != Nmeasure) {
	fprintf (stderr, "failed to write measures (%d vs %d)\n", nitems, Nmeasure);
	return (FALSE);
      }
      break;
    case DVO_FORMAT_PANSTARRS:
    case DVO_FORMAT_PMTEST:
      tmpMeasurePanstarrs = MeasureInternalToPanstarrs (measure, Nmeasure);
      gfits_convert_MeasurePanstarrs (tmpMeasurePanstarrs, sizeof(MeasurePanstarrs), Nmeasure);
      nitems = fwrite (tmpMeasurePanstarrs, sizeof(MeasurePanstarrs), Nmeasure, f);
      free (tmpMeasurePanstarrs);
      if (nitems != Nmeasure) {
	fprintf (stderr, "failed to write measures (%d vs %d)\n", nitems, Nmeasure);
	return (FALSE);
      }
      break;
    default:
      fprintf (stderr, "error writing measures\n");
      return (FALSE);
  }
  return (TRUE);
}

/** SecFilt / Raw Table conversions **/

SecFilt *ReadRawSecFilt (FILE *f, int Nsecfilt, int format) {

  int nitems;
  SecFilt *secfilt;
  SecFiltElixir *tmpSecFiltElixir;
  SecFiltLoneos *tmpSecFiltLoneos;
  SecFiltPanstarrs *tmpSecFiltPanstarrs;

  switch (format) {
    case DVO_FORMAT_INTERNAL:
      ALLOCATE (secfilt, SecFilt, MAX (Nsecfilt, 1));
      nitems = fread (secfilt, sizeof(SecFilt), Nsecfilt, f);
      if (nitems != Nsecfilt) {
	fprintf (stderr, "failed to read secfilts (%d vs %d)\n", nitems, Nsecfilt);
	return (NULL);
      }
      gfits_convert_SecFilt (secfilt, sizeof(SecFilt), Nsecfilt);
      break;
    case DVO_FORMAT_ELIXIR:
      ALLOCATE (tmpSecFiltElixir, SecFiltElixir, MAX (Nsecfilt, 1));
      nitems = fread (tmpSecFiltElixir, sizeof(SecFiltElixir), Nsecfilt, f);
      if (nitems != Nsecfilt) {
	fprintf (stderr, "failed to read secfilts (%d vs %d)\n", nitems, Nsecfilt);
	return (NULL);
      }
      gfits_convert_SecFiltElixir (tmpSecFiltElixir, sizeof(SecFiltElixir), Nsecfilt);
      secfilt = SecFiltElixirToInternal (tmpSecFiltElixir, Nsecfilt);
      free (tmpSecFiltElixir);
      break;
    case DVO_FORMAT_LONEOS:
      ALLOCATE (tmpSecFiltLoneos, SecFiltLoneos, MAX (Nsecfilt, 1));
      nitems = fread (tmpSecFiltLoneos, sizeof(SecFiltLoneos), Nsecfilt, f);
      if (nitems != Nsecfilt) {
	fprintf (stderr, "failed to read secfilts (%d vs %d)\n", nitems, Nsecfilt);
	return (NULL);
      }
      gfits_convert_SecFiltLoneos (tmpSecFiltLoneos, sizeof(SecFiltLoneos), Nsecfilt);
      secfilt = SecFiltLoneosToInternal (tmpSecFiltLoneos, Nsecfilt);
      free (tmpSecFiltLoneos);
      break;
    case DVO_FORMAT_PANSTARRS:
    case DVO_FORMAT_PMTEST:
      ALLOCATE (tmpSecFiltPanstarrs, SecFiltPanstarrs, MAX (Nsecfilt, 1));
      nitems = fread (tmpSecFiltPanstarrs, sizeof(SecFiltPanstarrs), Nsecfilt, f);
      if (nitems != Nsecfilt) {
	fprintf (stderr, "failed to read secfilts (%d vs %d)\n", nitems, Nsecfilt);
	return (NULL);
      }
      gfits_convert_SecFiltPanstarrs (tmpSecFiltPanstarrs, sizeof(SecFiltPanstarrs), Nsecfilt);
      secfilt = SecFiltPanstarrsToInternal (tmpSecFiltPanstarrs, Nsecfilt);
      free (tmpSecFiltPanstarrs);
      break;
    default:
      fprintf (stderr, "error reading measures\n");
      return (NULL);
  }
  return (secfilt);
}

/* accepts and converts internal secfilt formats and outputs 
   raw data in the specified format */
int WriteRawSecFilt (FILE *f, SecFilt *secfilt, int Nsecfilt, int format) {

  int nitems;
  SecFiltElixir *tmpSecFiltElixir;
  SecFiltLoneos *tmpSecFiltLoneos;
  SecFiltPanstarrs *tmpSecFiltPanstarrs;

  switch (format) {
    case DVO_FORMAT_INTERNAL:
      gfits_convert_SecFilt (secfilt, sizeof(SecFilt), Nsecfilt);
      nitems = fwrite (secfilt, sizeof(SecFilt), Nsecfilt, f);
      if (nitems != Nsecfilt) {
	fprintf (stderr, "failed to write secfilts (%d vs %d)\n", nitems, Nsecfilt);
	return (FALSE);
      }
      break;
    case DVO_FORMAT_ELIXIR:
      tmpSecFiltElixir = SecFiltInternalToElixir (secfilt, Nsecfilt);
      gfits_convert_SecFiltElixir (tmpSecFiltElixir, sizeof(SecFiltElixir), Nsecfilt);
      nitems = fwrite (tmpSecFiltElixir, sizeof(SecFiltElixir), Nsecfilt, f);
      free (tmpSecFiltElixir);
      if (nitems != Nsecfilt) {
	fprintf (stderr, "failed to write secfilts (%d vs %d)\n", nitems, Nsecfilt);
	return (FALSE);
      }
      break;
    case DVO_FORMAT_LONEOS:
      tmpSecFiltLoneos = SecFiltInternalToLoneos (secfilt, Nsecfilt);
      gfits_convert_SecFiltLoneos (tmpSecFiltLoneos, sizeof(SecFiltLoneos), Nsecfilt);
      nitems = fwrite (tmpSecFiltLoneos, sizeof(SecFiltLoneos), Nsecfilt, f);
      free (tmpSecFiltLoneos);
      if (nitems != Nsecfilt) {
	fprintf (stderr, "failed to write secfilts (%d vs %d)\n", nitems, Nsecfilt);
	return (FALSE);
      }
      break;
    case DVO_FORMAT_PANSTARRS:
    case DVO_FORMAT_PMTEST:
      tmpSecFiltPanstarrs = SecFiltInternalToPanstarrs (secfilt, Nsecfilt);
      gfits_convert_SecFiltPanstarrs (tmpSecFiltPanstarrs, sizeof(SecFiltPanstarrs), Nsecfilt);
      nitems = fwrite (tmpSecFiltPanstarrs, sizeof(SecFiltPanstarrs), Nsecfilt, f);
      free (tmpSecFiltPanstarrs);
      if (nitems != Nsecfilt) {
	fprintf (stderr, "failed to write secfilts (%d vs %d)\n", nitems, Nsecfilt);
	return (FALSE);
      }
      break;
    default:
      fprintf (stderr, "error writing secfilts\n");
      return (FALSE);
  }
  return (TRUE);
}

