# include "autocode.h"

int gfits_convert_$STRUCT ($STRUCT *data, off_t size, off_t nitems) {

  off_t i;
  unsigned char *byte, tmp;

  if (size != $SIZE) { 
    fprintf (stderr, "WARNING: mismatch in data types $STRUCT: %lld vs %lld\n", (long long) size, (long long) $SIZE);
    return (FALSE);
  }

  /* provide initial values to avoid compiler warnings for non-BYTE_SWAP arch */
  i = tmp = 0;
  byte = NULL;

# ifdef BYTE_SWAP
  byte = (unsigned char *) data;
  for (i = 0; i < nitems; i++, byte += $SIZE) {
    /** BYTE SWAP **/
  }
# endif  

  return (TRUE);
} 

$STRUCT *gfits_downsize_and_convert_$STRUCT ($STRUCT *data, off_t size, off_t nitems) {

  off_t i;
  unsigned char *byte, tmp;
  $STRUCT *output;

  if ($SIZE > size) { 
    fprintf (stderr, "ERROR: uncorrectable mismatch in data types $STRUCT: %lld vs %lld\n", (long long) size, (long long) $SIZE);
    exit (1);
  }

  // allocate a new array 
  ALLOCATE (output, $STRUCT, nitems);
  for (i = 0; i < nitems; i++) {
    memcpy (&output[i], &data[i], $SIZE);
  }

  /* provide initial values to avoid compiler warnings for non-BYTE_SWAP arch */
  i = tmp = 0;
  byte = NULL;

# ifdef BYTE_SWAP
  byte = (unsigned char *) output;
  for (i = 0; i < nitems; i++, byte += size) {
    /** BYTE SWAP **/
  }
# endif  

  return (output);
} 

/*** add test of EXTNAME and header-defined columns? ***/
/* return internal structure representation */
$STRUCT *gfits_table_get_$STRUCT (FTable *ftable, off_t *Ndata, char *swapped) {

  $STRUCT *data, *output;

  *Ndata = ftable[0].header[0].Naxis[1];
  data = ($STRUCT *) ftable[0].buffer;
  if ((swapped == NULL) || (*swapped == FALSE)) {
    if (!gfits_convert_$STRUCT (data, sizeof ($STRUCT), *Ndata)) {
      output = gfits_downsize_and_convert_$STRUCT (data, sizeof ($STRUCT), *Ndata);
      free (ftable[0].buffer);
      ftable[0].buffer = (char *) output;
      // XXX do I need to change NX?
    }
    gfits_table_scale_data (ftable);
    if (swapped != NULL) *swapped = TRUE;
  }
  return (data);
}

int gfits_table_set_$STRUCT (FTable *ftable, $STRUCT *data, off_t Ndata) {

  Header *header;

  header = ftable[0].header;

  /* create table header */
  gfits_create_table_header (header, "$TYPE", "$EXTNAME");

  /* define table layout */
  /** TABLE DEFINITION **/

  /* create table */
  gfits_create_table (header, ftable);

  /* add data values */
  gfits_table_scale_data (ftable);
  gfits_convert_$STRUCT (data, sizeof ($STRUCT), Ndata);
  gfits_add_rows (ftable, (char *) data, Ndata, sizeof ($STRUCT));

  return (TRUE);
}

int gfits_table_mkheader_$STRUCT (Header *header) {

  /* create table header */
  gfits_create_table_header (header, "$TYPE", "$EXTNAME");

  /* define table layout */
  /** TABLE DEFINITION **/

  return (TRUE);
}

int Send_$STRUCT (int device, $STRUCT *data, int Ndata, int copy) {

  int Nbytes;
  $STRUCT *tmpdata;

  Nbytes = Ndata * sizeof ($STRUCT);

  if (copy) {
    ALLOCATE (tmpdata, $STRUCT, Ndata);
    memcpy (tmpdata, data, Nbytes);
  } else {
    tmpdata = data;
  }

  gfits_convert_$STRUCT (tmpdata, sizeof ($STRUCT), Ndata);

  SendCommand (device, 16, "NVALUE: %6d", Ndata);
  SendCommand (device, 16, "NBYTES: %6d", Nbytes);
  write (device, tmpdata, Nbytes);
  
  /* perform handshaking? */

  return (TRUE);
}

int Recv_$STRUCT (int device, $STRUCT **data, int *Ndata) {

  int ndata;
  IOBuffer message;
  $STRUCT *tmpdata;

  ExpectCommand (device, 16, 1.0, &message);
  sscanf (message.buffer, "%*s %d", &ndata);
  FreeIOBuffer (&message);
  
  /* what is reasonable for timeout? */
  ExpectMessage (device, 1.0, &message);
  
  tmpdata = ($STRUCT *) message.buffer;
  gfits_convert_$STRUCT (tmpdata, sizeof ($STRUCT), ndata);

  /* double-check data length? */
  /* perform handshaking? */

  *Ndata = ndata;
  *data = tmpdata;

  return (TRUE);
}
