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

/***********************/
int gfits_bintable_format (char *format, char *type, int *Nval, int *Nbytes) {

  char *Lchar, *Fchar;
  int Nv;

  if (format == (char *) NULL) return (FALSE);
  if (format[0] == 0) return (FALSE);
  Lchar = &format[strlen(format) - 1];

  Nv = strtol (format, &Fchar, 10);
  if (Fchar != Lchar) return (FALSE);
  if ((Nv == 0) && (Fchar == format)) Nv = 1;

  *Nbytes = 0;
  if (*Fchar == 'X') { *Nbytes = 1;  strcpy (type, "char");   *Nval = 1 + (int) Nv / 8; }
  if (*Fchar == 'L') { *Nbytes = 1;  strcpy (type, "char");   *Nval = Nv;               }
  if (*Fchar == 'A') { *Nbytes = 1;  strcpy (type, "char");   *Nval = Nv;               }
  if (*Fchar == 'B') { *Nbytes = 1;  strcpy (type, "char");   *Nval = Nv;               }
  if (*Fchar == 'I') { *Nbytes = 2;  strcpy (type, "short");  *Nval = Nv;               }
  if (*Fchar == 'J') { *Nbytes = 4;  strcpy (type, "int");    *Nval = Nv;               }
  if (*Fchar == 'E') { *Nbytes = 4;  strcpy (type, "float");  *Nval = Nv;               }
  if (*Fchar == 'D') { *Nbytes = 8;  strcpy (type, "double"); *Nval = Nv;               }
  if (*Fchar == 'P') { *Nbytes = 8;  strcpy (type, "float");  *Nval = 2*Nv;             }
  if (*Fchar == 'C') { *Nbytes = 8;  strcpy (type, "float");  *Nval = 2*Nv;             }
  if (*Fchar == 'M') { *Nbytes = 16; strcpy (type, "double"); *Nval = 2*Nv;             }
  if (!*Nbytes) { return (FALSE); }

  return (TRUE);
}

/* 
   valid BINTABLE column formats:
   L - logical
   X - bit
   I - 16 bit int
   J - 32 bit int
   A - char
   E - float 
   D - double
   B - unsigned bytes
   C - complex float
   M - complex double
   P - var length array descrpt (64 bit)
   
   all can be preceeded by integer N which specified number
   of entries in array
   
*/

/***********************/
int gfits_table_format (char *format, char *type, int *Nval, int *Nbytes) {

  char Fchar, Size[80], Type;
  int Nv;

  if (format == (char *) NULL) return (FALSE);
  if (format[0] == 0) return (FALSE);
  Fchar = format[0];

  Nv = strtol (&format[1], (char **) NULL, 10);
  if (Nv == 0) { 
    Nv = 1;
    strcpy (Size, "1");
  } else {
    strcpy (Size, &format[1]);
  }
  
  Type = 'x';
  if (Fchar == 'F') { *Nbytes = 1;  strcpy (type, "float");  Type = 'f'; *Nval = Nv; }
  if (Fchar == 'I') { *Nbytes = 1;  strcpy (type, "int");    Type = 'd'; *Nval = Nv; }
  if (Fchar == 'A') { *Nbytes = 1;  strcpy (type, "char");   Type = 's'; *Nval = Nv; }
  if (!*Nbytes) { return (FALSE); }
  
  sprintf (format, "%%-%s%c", Size, Type);

  return (TRUE);
}

/*
  valid TABLE column formats:
  FN.N  - floating point
  INN   - integer
  ANN   - NN char string
  
*/

/** extract a table subset to a vtable ***/
int gfits_table_to_vtable (FTable *ftable, VTable *vtable, int start, int Nkeep) {

  /* gfits_table_to_vtable (f, v, 0, Ny - 1) - keep all of table
     gfits_table_to_vtable (f, v, 0, 0)      - keep none of table 
  */  

  int i, Nx, Ny;

  gfits_scan (ftable[0].header, "NAXIS1", "%d", 1, &Nx);
  gfits_scan (ftable[0].header, "NAXIS2", "%d", 1, &Ny);
  
  if (start + Nkeep > Ny) return (FALSE);
  if (start < 0) return (FALSE);
  if (Nkeep < 0) return (FALSE);

  ALLOCATE (vtable[0].row, int, MAX (1, Nkeep));
  ALLOCATE (vtable[0].buffer, char *, MAX (1, Nkeep));
  for (i = 0; i < Nkeep; i++) {
    ALLOCATE (vtable[0].buffer[i], char, MAX (1, Nx));
    memcpy (vtable[0].buffer[i], &ftable[0].buffer[(i+start)*Nx], Nx);
    vtable[0].row[i] = i + start;
  }
  
  vtable[0].header = ftable[0].header;
  vtable[0].size = ftable[0].size;
  vtable[0].Nrow = Nkeep;
  vtable[0].pad = vtable[0].size - Nx*Ny;

  return (TRUE);
}

/** convert specified rows to vtable */
int gfits_vtable_from_ftable (FTable *ftable, VTable *vtable, int *row, int Nrow) {

  int i, N, Nx, Ny;

  gfits_scan (ftable[0].header, "NAXIS1", "%d", 1, &Nx);
  gfits_scan (ftable[0].header, "NAXIS2", "%d", 1, &Ny);

  /* make empty vtable from table */
  vtable[0].header = ftable[0].header;  /* make this a copy? */
  vtable[0].size   = ftable[0].size;
  vtable[0].pad    = vtable[0].size - Nx*Ny;
  vtable[0].Nrow   = Ny;

  /* insert selected rows in vtable (mask rows marked with -1) */ 
  ALLOCATE (vtable[0].row, int, Nrow);
  ALLOCATE (vtable[0].buffer, char *, Nrow);
  for (N = i = 0; i < Nrow; i++) {
    if (row[i] == -1) continue;
    vtable[0].row[N] = row[i];
    ALLOCATE (vtable[0].buffer[N], char, Nx);
    memcpy (vtable[0].buffer[N], &ftable[0].buffer[Nx*row[i]], Nx);
    N++;
  }
  vtable[0].Nrow = N;
  return (TRUE);
}

/* use table def to format a complete string */
char *gfits_table_print (FTable *table,...) { 
  
  int i, Nx, Nfields;
  int off, Nchar, Nval, Nbytes;
  char *line, format[64], field[16], type[16];
  va_list argp;
  
  va_start (argp, table);

  gfits_scan (table[0].header, "NAXIS1",  "%d", 1, &Nx);
  gfits_scan (table[0].header, "TFIELDS", "%d", 1, &Nfields);

  ALLOCATE (line, char, Nx + 1);
  
  off = 0;
  for (i = 1; i <= Nfields; i++) {

    sprintf (field, "TFORM%d", i);
    gfits_scan (table[0].header, field, "%s", 1, format);       /* get field format */
    gfits_table_format (format, type, &Nval, &Nbytes); /* convert to c-style */
    Nchar = Nval * Nbytes;
    if (!strcmp (type, "int"))   { 
      /* d = va_arg (argp, int); */
      snprintf (&line[off], Nchar + 1, format, va_arg (argp, int)); 
    }
    if (!strcmp (type, "float")) { 
      /* f = va_arg (argp, double); */
      snprintf (&line[off], Nchar + 1, format, va_arg (argp, double)); 
    }
    if (!strcmp (type, "char"))  { 
      /* c = va_arg (argp, char *); */
      snprintf (&line[off], Nchar + 1, format, va_arg (argp, char *));
    }
    off += Nchar;
  }
  va_end (argp);
  return (line);
}

    /* vsnprintf (&line[off], Nchar + 1, format, argp); */
