// Routines for handling tables

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hdf5.h"
#include "hdf5_hl.h"

#define CSIZE 1024

//--------------------------------------------------------------

// Make a table
// Would like to make chunk-size optional, but C does not allow it.

int mt_tmake(hid_t gid, const char *name,
	     hsize_t nfields, const char *field_names[], const char *field_types,
	     hsize_t nrecords, hsize_t chunksize, void *table) {

  int compress=0; // Don't compress
  int *fill=NULL; // Don't fill entries that aren't supplied with data

  int ier;
  int ifield;
  hid_t sCSIZE_t;   // character string of length CSIZE
  hid_t *types; 
  size_t *offsets;
  hsize_t rowsize;

  // Sets a string typ econtaining CSIZE characters
  sCSIZE_t=H5Tcopy(H5T_C_S1);
  ier=(int)H5Tset_size (sCSIZE_t,(size_t)CSIZE);

  // Set types, field offsets and row-size
  rowsize=0;
  types=(hid_t *)calloc(nfields,sizeof(types));
  offsets=(size_t *)calloc(nfields,sizeof(offsets));
  for (ifield=0;ifield<nfields;ifield++) {
    offsets[ifield]=rowsize;
    if (field_types[ifield]=='i') {
      types[ifield]=H5T_INTEL_I32;
      rowsize+=4;
    }
    else if (field_types[ifield]=='l') {
      types[ifield]=H5T_INTEL_I64;
      rowsize+=8;
    }
    else if (field_types[ifield]=='f') {
      types[ifield]=H5T_INTEL_F32;
      rowsize+=4;
    }
    else if (field_types[ifield]=='d') {
      types[ifield]=H5T_INTEL_F64;
      rowsize+=8;
    }
    else if (field_types[ifield]=='s') {
      types[ifield]=sCSIZE_t;
      rowsize+=CSIZE;
    }
    else {
      printf("***mt_tmake: undefined datatype %c***\n",field_types[ifield]);
      return -1;
    }
  }

  ier=(int)H5TBmake_table(name, gid, name, nfields, nrecords, rowsize, 
			  field_names, offsets, types, (hsize_t)chunksize,
			     fill, compress, table);

  ier=(int)H5Tclose(sCSIZE_t);
  free(types);
  free(offsets);
  return ier;

}

//--------------------------------------------------------------

// Read a table

int mt_tread(hid_t gid, const char *name,
	     hsize_t nfields, const char *field_names, const char *field_types,
	     hsize_t nrecords, void *table) {

  /* Inputs:
     gid - HDF5 group identifier
     name - name of table to read
     nfields - number of fields that you wish to read
     field_names - comma separated list of the names of the fields to read from the HDF5 table
     field_types - types of the fields (in the output structure
                 - must match in type but can differ in size from HDF5 structure)
     Outputs:
     table - pointer to table
  */
  int ier;
  int ifield;
  size_t *offsets, *sizes;
  hsize_t rowsize;
  hsize_t start=0;

//--------------------------------------------------------------

// Set types, field offsets and row-size
  rowsize=0;
  sizes=(size_t *)calloc(nfields,sizeof(sizes));
  offsets=(size_t *)calloc(nfields,sizeof(offsets));
  for (ifield=0;ifield<nfields;ifield++) {
    offsets[ifield]=rowsize;
    if (field_types[ifield]=='i') {
      sizes[ifield]=4;
      rowsize+=4;
    }
    else if (field_types[ifield]=='l') {
      sizes[ifield]=8;
      rowsize+=8;
    }
    else if (field_types[ifield]=='f') {
      sizes[ifield]=4;
      rowsize+=4;
    }
    else if (field_types[ifield]=='d') {
      sizes[ifield]=8;
      rowsize+=8;
    }
    else if (field_types[ifield]=='s') {
      sizes[ifield]=CSIZE;
      rowsize+=CSIZE;
    }
    else {
      printf("***mt_tread: undefined datatype %c***\n",field_types[ifield]);
      return -1;
    }
  }

  ier=(int)H5TBread_fields_name(gid, name, field_names, start, nrecords, rowsize, offsets, sizes, table);

  free(offsets);
  free(sizes);
  return ier;

}

//--------------------------------------------------------------

// Read table info

hsize_t mt_treadinfo(hid_t gid, const char *name, hsize_t *nfields) {

  int ier;
  hsize_t nrecords;

  ier=(int)H5TBget_table_info(gid,name,nfields,&nrecords);
  if (ier < 0) {
    printf("***mt_table: table %s does not exist***\n",name);
    return -1;
  }

  return nrecords;

}

