#include "ehdf5.h"
#include "earray.h"


estr ehdf5Type(int h5t){
  switch(h5t){
    case H5G_GROUP: return("GROUP");
    case H5G_DATASET: return("DATASET");
    case H5G_TYPE: return("TYPE");
    case H5G_LINK: return("LINK");
    case H5G_UDLINK: return("UDLINK");
  };
  return("unknown");
}

ehdf5Group::ehdf5Group(const ehdf5Group& g): _gid(g._gid) {}
ehdf5Group::ehdf5Group(hid_t gid): _gid(gid) {}
void ehdf5Group::close(){ H5Gclose(_gid); _gid=0; }

earray<ehdf5Object> ehdf5Group::ls()
{
  if (_gid<0){ lerror("non existent group"); return(earray<ehdf5Object>()); }
  H5G_info_t ginfo;
  if (H5Gget_info(_gid,&ginfo)<0) return(earray<ehdf5Object>());
  estr tmpstr;
  tmpstr.reserve(1024);
  int tmptype;
  cout << "links: " << ginfo.nlinks << endl;
  for (int i=0; i<ginfo.nlinks; ++i){
    cout << "i: " << i << endl;
    tmpstr._strlen=H5Gget_objname_by_idx(_gid,i,tmpstr._str,1024);
    tmptype=H5Gget_objtype_by_idx(_gid,i);
    cout << tmpstr << ": " << ehdf5Type(tmptype) << endl;
  }
  return(earray<ehdf5Object>());
}


ehdf5::ehdf5(): _fid(0) {}

bool ehdf5::open(const estr& fname)
{
  _fid=H5Fopen(fname._str,H5F_ACC_RDONLY,H5P_DEFAULT);
  if (_fid<0) return(false);
  return(true);
}

ehdf5Group ehdf5::openGroup(const estr& gname)
{
  hid_t hid=H5Gopen1(_fid,gname._str);
//  if (hid>=0)
    return(ehdf5Group(hid));
//  return(ehdf5Group());
}

void ehdf5::writeDataset(const estr& dname,const ebasearray& arr)
{
  hid_t       space, dset, dcpl;    /* Handles */
  herr_t      status;
  H5D_layout_t    layout;
  hsize_t     dims[2];              /* dataset dimensions */

  dims[0]=arr.size();
  dims[1]=1;

  space = H5Screate_simple (2, dims, NULL);

  /*
   * Create the dataset creation property list, set the layout to
   * compact.
   */
  dcpl = H5Pcreate (H5P_DATASET_CREATE);
  status = H5Pset_layout (dcpl, H5D_COMPACT);

  /*
   * Create the dataset.  We will use all default properties for this
   * example.
   */
  dset = H5Dcreate (_fid, dname._str, H5T_STD_I32LE, space, H5P_DEFAULT, dcpl,
              H5P_DEFAULT);

  /*
   * Write the data to the dataset.
   */
//  status = H5Dwrite (dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT,
//              &arr[0]);

  /*
   * Close and release resources.
   */
  status = H5Pclose (dcpl);
  status = H5Dclose (dset);
  status = H5Sclose (space);
}

ebasearray* ehdf5::readDataset(const estr& dname)
{
  hid_t       dataspace, dtype, dataset, dcpl;    /* Handles */
  herr_t      status;
  H5D_layout_t    layout;

  dataset = H5Dopen (_fid, dname._str, H5P_DEFAULT);

  /*
   * Retrieve the dataset creation property list, and print the
   * storage layout.
   */
  dcpl = H5Dget_create_plist (dataset);

  dataspace = H5Dget_space (dataset);    /* dataspace handle */
  dtype = H5Dget_type(dataset);
//  printf("datatype: %i\n");
  hsize_t rank      = H5Sget_simple_extent_ndims (dataspace);
  hsize_t dims[rank];              /* dataset dimensions */  
  status  = H5Sget_simple_extent_dims (dataspace, dims, NULL);
  printf("Rank: %d\n",rank);
  for (int i=0; i<rank; ++i)
    printf("%lu\n", (unsigned long)(dims[i]));


  switch (H5Tget_class(dtype)) {
       case H5T_INTEGER:{
  	H5T_order_t ord = H5Tget_order(dtype);
  	H5T_sign_t sgn = H5Tget_sign(dtype);
  	printf("Integer ByteOrder= ");
  	switch (ord) {
  	case H5T_ORDER_LE:
  	    printf("LE");
  	    break;
  	case H5T_ORDER_BE:
  	    printf("BE");
  	    break;
  	}
  	printf(" Sign= ");
  	switch (sgn) {
  	case H5T_SGN_NONE:
  	    printf("false");
  	    break;
  	case H5T_SGN_2:
  	    printf("true");
  	    break;
  	}
  	printf(" Size= ");
  	size_t sz = H5Tget_size(dtype);
  	printf("%d", sz);
  	printf("\n");
    eintarray *iarr=new eintarray();
    iarr->reserve(dims[0]);
    for (int i=0; i<dims[0]; ++i) iarr->add(0.0);
    status = H5Dread (dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT,&(*iarr)[0]);
  status = H5Tclose (dtype);
  status = H5Pclose (dcpl);
  status = H5Dclose (dataset);
    return(iarr);
  	break;
    }
    case H5T_FLOAT:{
      printf("FLOAT!\n");
  	printf(" Size= ");
  	size_t sz = H5Tget_size(dtype);
  	printf("%d", sz);
  	printf("\n");
    efloatarray *farr=new efloatarray();
    farr->reserve(dims[0]);
    for (int i=0; i<dims[0]; ++i) farr->add(0.0);
    status = H5Dread (dataset, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT,&(*farr)[0]);
  status = H5Tclose (dtype);
  status = H5Pclose (dcpl);
  status = H5Dclose (dataset);
    return(farr);
     break;
     }
    case H5T_STRING:{
      printf("STRING!\n");
  	printf(" Size= ");
  	size_t sz = H5Tget_size(dtype);
  	printf("%d", sz);
  	printf("\n");
    earray<estr> *sarr=new earray<estr>();
    sarr->reserve(dims[0]);
    ldieif(!H5Tis_variable_str(dtype),"non variable sized strings not supported");

//    hid_t memtype = H5Tcopy (H5T_C_S1);
//    status = H5Tset_size (memtype, H5T_VARIABLE);
    char **rdata = (char **) malloc (dims[0] * sizeof (char *));
    /*
     * Read the data.
     */
    cout << "Reading data" << endl;
//    status = H5Dread (dataset, memtype, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata);
    status = H5Dread (dataset, dtype, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata);

    cout << "Loading string array" << endl;
    /*
     * Output the data to the screen.
     */
    for (int i=0; i<dims[0]; i++)
      sarr->add(rdata[i]);
//        printf ("%s[%d]: %s\n", DATASET, i, rdata[i]);
//    status = H5Dread (dset, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT,(*sarr)[0]);
    cout << "Freeing up results" << endl;

  status = H5Dvlen_reclaim (dtype, dataspace, H5P_DEFAULT, rdata);
  free(rdata);
//  status = H5Tclose (memtype);
  status = H5Tclose (dtype);
  status = H5Pclose (dcpl);
  status = H5Dclose (dataset);
    return(sarr);
    break;
    }
/* The datatype class: H5T_INTEGER, H5T_FLOAT, H5T_TIME, H5T_STRING, or H5T_BITFIELD, H5T_OPAQUE, H5T_COMPOUND, H5T_REFERENCE, H5T_ENUM, H5T_VLEN, H5T_ARRAY */
  }
  fflush(stdout);

  layout = H5Pget_layout (dcpl);
  printf ("Storage layout for %s is: ", dname._str);
  switch (layout) {
      case H5D_COMPACT:
          printf ("H5D_COMPACT\n");
          break;
      case H5D_CONTIGUOUS:
          printf ("H5D_CONTIGUOUS\n");
          break;
      case H5D_CHUNKED:
          printf ("H5D_CHUNKED\n");
  }

  /*
   * Read the data using the default properties.
   */
//  status = H5Dread (dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT,
//              rdata[0]);


/*
//     * Define hyperslab in the dataset. 
    offset[0] = 1;
    offset[1] = 2;
    count[0]  = NX_SUB;
    count[1]  = NY_SUB;
    status = H5Sselect_hyperslab (dataspace, H5S_SELECT_SET, offset, NULL, 
                                  count, NULL);

//     * Define the memory dataspace.
    dimsm[0] = NX;
    dimsm[1] = NY;
    dimsm[2] = NZ;
    memspace = H5Screate_simple (RANK_OUT, dimsm, NULL);   

//     * Define memory hyperslab. 
    offset_out[0] = 3;
    offset_out[1] = 0;
    offset_out[2] = 0;
    count_out[0]  = NX_SUB;
    count_out[1]  = NY_SUB;
    count_out[2]  = 1;
    status = H5Sselect_hyperslab (memspace, H5S_SELECT_SET, offset_out, NULL, 
                                  count_out, NULL);

//     * Read data from hyperslab in the file into the hyperslab in 
//     * memory and display.
    status = H5Dread (dataset, H5T_NATIVE_INT, memspace, dataspace,
                      H5P_DEFAULT, data_out);

*/


  status = H5Tclose (dtype);
  status = H5Pclose (dcpl);
  status = H5Dclose (dataset);
  return(0x00);
}

bool ehdf5::create(const estr& fname)
{
  _fid=H5Fcreate(fname._str,H5F_ACC_TRUNC,H5P_DEFAULT,H5P_DEFAULT);
}

void ehdf5::createdspace()
{
  hsize_t dims[2];
  dims[0]=4,dims[1]=6;
//  dspaceid=H5Screate_simple(2,dims,NULL);
}

void ehdf5::writedspace()
{
  int dset_data[4][6];

//  status = H5Dwrite(dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT,dset_data);
//  status = H5Dread(dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, dset_data);
}

bool ehdf5::createdset(const estr& dsname)
{
//  dsid=H5Screate2(_fid,dsname._str,H5T_STD_i32BE,dsid,H5P_DEFAULT,H5P_DEFAULT,H5P_DEFAULT);
//  HD5Dclose(dsid);
}

void ehdf5::close()
{
  H5Fclose(_fid);
  _fid=0;
}


