# include <ohana.h>
# include <gfitsio.h>

/*********************** fits read table ***********************************/
int gfits_read_ftable (char *filename, FTable *table, char *extname) {

  int status;
  FILE *f;

  f = fopen (filename, "r");
  if (f == NULL) return (FALSE);

  status = gfits_fread_ftable (f, table, extname);
  fclose (f);
  return (status);
}	

/*********************** fits read table ***********************************/
int gfits_fread_ftable (FILE *f, FTable *table, char *extname) {

  int j, found, Nbytes;
  Header *header;
  char tname[80];

  header = table[0].header;
  fseek (f, 0, SEEK_SET);

  found = FALSE;
  for (j = -1; !found; j++) {
    /* load data for this header */
    if (!gfits_load_header (f, header)) return (FALSE);

    /* check if this is the correct extension or not */
    bzero (tname, 80);
    gfits_scan (header, "EXTNAME", "%s", 1, tname);
    if (!strcmp (tname, extname)) {
      if (gfits_fread_ftable_data (f, table)) return (TRUE);
      gfits_free_header (header);
      return (FALSE);
    }

    /* skip to next header */
    Nbytes = gfits_matrix_size (header);
    fseek (f, Nbytes, SEEK_CUR);
    gfits_free_header (header);
  }
  return (TRUE);
}	

/*********************** fits read ftable data ***********************************/
int gfits_fread_ftable_data (FILE *f, FTable *table) {

  int Nbytes, Nread;

  /* find buffer size */
  Nbytes = gfits_matrix_size (table[0].header);
  ALLOCATE (table[0].buffer, char, Nbytes);

  Nread = fread (table[0].buffer, sizeof (char), Nbytes, f);
  if (Nread != Nbytes) {
    gfits_free_table  (table);
    return (FALSE);
  }
  table[0].size = Nbytes;
  return (TRUE);
}	

/*********************** fits read ftable data ***********************************/
int gfits_fread_vtable_range (FILE *f, VTable *table, int start, int Nrows) {

  int i, Nbytes, Nread, Nskip, Nx, Ny;
  char *buffer;

  /* find buffer size */
  Nx = table[0].header[0].Naxis[0];
  Ny = table[0].header[0].Naxis[1];
  table[0].size = gfits_matrix_size (table[0].header);
  table[0].pad = table[0].size - Nx*Ny;

  if (start < 0) return (FALSE);
  if (start + Nrows >= Ny) return (FALSE);
  
  Nskip = start * Nx;
  Nbytes = Nrows * Nx;
  ALLOCATE (buffer, char, MAX (Nbytes, 1));

  fseek (f, Nskip, SEEK_CUR);
  Nread = fread (buffer, sizeof (char), Nbytes, f);
  if (Nread != Nbytes) {
    free (buffer);
    return (FALSE);
  }

  ALLOCATE (table[0].row, int, MAX (Nrows, 1));
  ALLOCATE (table[0].buffer, char *, MAX (Nrows, 1));
  for (i = 0; i < Nrows; i++) {
    ALLOCATE (table[0].buffer[i], char, MAX (Nx, 1));
    memcpy (table[0].buffer[i], &buffer[i*Nx], Nx);
    table[0].row[i] = start + i;
  }
  free (buffer);

  return (TRUE);
}	

/*********************** fits read virtual table ***********************************/
int gfits_fread_vtable (FILE *f, VTable *table, char *extname, int Nrow, int *row) {

  int i, j, Nbytes, Nread;
  int start, Nx, Ny, offset;
  Header *header;
  char tname[80];

  header = table[0].header;
  fseek (f, 0, SEEK_SET);

  for (j = -1; TRUE; j++) {
    /* load data for this header */
    if (!gfits_load_header (f, header)) return (FALSE);

    /* find buffer size */
    Nbytes = gfits_matrix_size (header);

    /* check if this is the correct extension or not */
    bzero (tname, 80);
    gfits_scan (header, "EXTNAME", "%s", 1, tname);
    if (strcmp (tname, extname)) {
      /* skip to next header */
      fseek (f, Nbytes, SEEK_CUR);
      gfits_free_header (header);
      continue;
    }

    /* file pointer is at beginning of desired table data */
    start = ftell (f);
    gfits_scan (header, "NAXIS1", "%d", 1, &Nx);
    gfits_scan (header, "NAXIS2", "%d", 1, &Ny);
    for (i = 0; i < Nrow; i++) {
      if (row[i] > Ny) { return (FALSE); }
    }

    ALLOCATE (table[0].buffer, char *, MAX (1, Nrow));
    for (i = 0; i < Nrow; i++) {
      ALLOCATE (table[0].buffer[i], char, MAX (1, Nx));
      offset = start + Nx*row[i];
      fseek (f, offset, SEEK_SET);
      Nread = fread (table[0].buffer[i], sizeof (char), Nx, f);
      if (Nread != Nx) { return (FALSE); }
    }

    table[0].Nrow  = Nrow;
    ALLOCATE (table[0].row, int, MAX (1, Nrow));    
    for (i = 0; i < Nrow; i++) table[0].row[i] = row[i];
    table[0].size   = gfits_matrix_size (table[0].header);
    table[0].pad    = table[0].size - Nx*Ny;
    return (TRUE);
  }
}	

# if (0)
/*********************** fits read table ***********************************/
/* a poor function: read only the first table, regardless of name */
/* keep until we are sure ohana code does not use it  */
int gfits_read_table (char *filename, FTable *table) {

  FILE *f;
  Header header;
  int status, i, nbytes, Nbytes, matrix_size;

  if (!gfits_read_header (filename, &header)) {
    fprintf (stderr, "error reading header of FITS file %s\n", filename);
    return (FALSE);
  }

  if (!gfits_read_Theader (filename, &table[0].header)) {
    fprintf (stderr, "error reading Theader of FITS file %s\n", filename);
    return (FALSE);
  }

  if ((f = fopen (filename, "r")) == NULL) {
    gfits_free_header (&header);
    gfits_free_header (&table[0].header);
    return (FALSE);
  }

  matrix_size = gfits_matrix_size (&header);

  Nbytes = header.size + matrix_size + table[0].header.size;
  fseek (f, Nbytes, 0);
  gfits_free_header (&header);
 
  gfits_scan (&table[0].header, "TFIELDS", "%d", 1, &table[0].Nfields);

  /* place the field sizes in the structure? */
  table[0].bitpix = table[0].header.bitpix;
  table[0].Naxes  = table[0].header.Naxes;
  for (i = 0; i < FT_MAX_NAXES; i++)
    table[0].Naxis[i] = table[0].header.Naxis[i];

  Nbytes = gfits_matrix_size (&table[0].header);
  ALLOCATE (table[0].buffer, char, Nbytes);
  nbytes = fread (table[0].buffer, sizeof(char), Nbytes, f);
  if (nbytes != Nbytes) {
    fprintf (stderr, "error reading in table data from FITS file %s\n", filename);
    fclose (f);
    return (FALSE);
  }
  table[0].size = Nbytes;
  fclose (f);
  return (TRUE);
}
# endif


int gfits_fread_header_extname (FILE *f, Header *header, char *extname) {

  int Nbytes;
  char current[80];

  fseek (f, 0, SEEK_SET);
  gfits_fread_header (f, header);

  if (!strcasecmp (extname, "PHU")) return (TRUE);

  Nbytes = gfits_matrix_size (header);
  fseek (f, Nbytes, SEEK_CUR);

  while (gfits_fread_header (f, header)) {
    gfits_scan (header, "EXTNAME", "%s", 1, current);
    if (!strcmp (current, extname)) return (TRUE);
    Nbytes = gfits_matrix_size (header);
    fseek (f, Nbytes, SEEK_CUR);
  }
  return (FALSE);
}
