/*
 * exph5_entity_reference
 * This example creates four EXPRESS entity instances of one entity type using an HDF5 Compound Datatype
 * and creates two EXPRESS entity instances of another entity type that refer to the instances of the first.
 * line.start_point and line.end_point -> point instances.
 */


#include "hdf5.h"
#include "hdf5_hl.h"

int
main(void)
{
    hid_t    file, pop1_group, schema_group;
    hid_t    point_group, point_space, point_dataset;
    hid_t    line_group, line_space, line_dataset;

    hid_t    spacer_id, dsetr_id;
    hdset_reg_ref_t ref[1];

    herr_t    status;
    int rank, i;
    int num_points = 1;
    hsize_t    dim[] = {1};   /* Dataspace dimensions */
    hsize_t coord[2][1] = {0, 0};

/* C struct for instances of entity type point; x, y, z = REAL; */
    typedef struct point_t {
	float  x;
	float  y;
	float z;
    } point_t;
/* C array that can contain 4 (same as dim value for dataspace) instances of the point entity type*/
    point_t       point[4];
    hid_t      point_tid;     /* File datatype identifier */

/* C struct for instances of entity type line; start_point, end_point = point; */
    typedef struct line_t {
	hdset_reg_ref_t  start_point;
	hdset_reg_ref_t end_point;
    } line_t;
/* C array that can contain 2 (same as dim value for dataspace) instances of the line entity type*/
    line_t       line[2];
    hid_t      line_tid;     /* File datatype identifier */

    /*
     * Create a new HDF5 file.
     */
    file = H5Fcreate("exph5_entity_reference.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
    /*
     * Create a data and schema group in the file and set required attributes and a decription.
     */
    pop1_group = H5Gcreate(file, "/Pop1", 0);
    schema_group = H5Gcreate(file, "/geometry_encoding1", 0);
    status =  H5LTset_attribute_string( pop1_group, "/Pop1", "iso_10303_26_data", "geometry" );
    status =  H5LTset_attribute_string( schema_group, "/geometry_encoding1", "iso_10303_26_schema", "geometry" );
    status =  H5LTset_attribute_string( schema_group, "/geometry_encoding1", "iso_10303_26_description", 
              "Contains example entity instances of entity type point and entity type line that refer to point instances." );

 /* Add HDF5 Compound Datatype for EXPRESS Entity Type line. */
    line_tid = H5Tcreate (H5T_COMPOUND, sizeof(line_t));
    H5Tinsert(line_tid, "start_point", HOFFSET(line_t, start_point), H5T_STD_REF_DSETREG);
    H5Tinsert(line_tid, "end_point", HOFFSET(line_t, end_point), H5T_STD_REF_DSETREG);
    status = H5Tcommit (schema_group, "line", line_tid);

/* Add HDF5 Compound Datatype for EXPRESS Entity Type line. */
    point_tid = H5Tcreate (H5T_COMPOUND, sizeof(point_t));
    H5Tinsert(point_tid, "x", HOFFSET(point_t, x), H5T_NATIVE_FLOAT);
    H5Tinsert(point_tid, "y", HOFFSET(point_t, y), H5T_NATIVE_FLOAT);
    H5Tinsert(point_tid, "z", HOFFSET(point_t, z), H5T_NATIVE_FLOAT);
    status = H5Tcommit (schema_group, "point", point_tid);

    /* Create an HDF5 Group for the objects related to the entity type point */
    point_group = H5Gcreate(file, "/Pop1/point-objects", 0);
    /* Create dataspace of rank 1 and dimension 4 to hold the four instance of entity type point */
    rank = 1;
    dim[0] = 4;
    point_space = H5Screate_simple(rank, dim, NULL);
    /* Create dataset to hold instances of entity type point */
    point_dataset = H5Dcreate(point_group, "Instances", point_tid, point_space, H5P_DEFAULT);

    /* Set values for the instances of entity type point */
    for (i = 0; i< 4; i++) {
        point[i].x = (i+1)*1.33;
        point[i].y = (i+1)*2.66;
        point[i].z = (i+1)*3.99;
}

     /* Wtite instances entity type point to the dataset  */
    status = H5Dwrite(point_dataset, point_tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, point);

    /* Create an HDF5 Group for the objects related to the entity type line */
    line_group = H5Gcreate(file, "/Pop1/line-objects", 0);
    /* Create dataspace of rank 1 and dimension 2 to hold the two instance of entity type line */
    rank = 1;
    dim[0] = 2;
    line_space = H5Screate_simple(rank, dim, NULL);
    /* Create dataset to hold instances of entity type line */
    line_dataset = H5Dcreate(line_group, "Instances", line_tid, line_space, H5P_DEFAULT);
    /*
     * Create a reference to elements selection.
     */
    status = H5Sselect_none(point_space);
    status = H5Sselect_elements(point_space, H5S_SELECT_SET,num_points,
                                (const hsize_t **)coord);
    status = H5Rcreate(&line[0].start_point, line_group, "Instances", H5R_DATASET_REGION, point_space);

    /* Set coord to select the second array element (index 1) from the 1D array of point instances ()*/
    coord[0][0] = 1;
    status = H5Sselect_none(point_space);
    status = H5Sselect_elements(point_space, H5S_SELECT_SET,num_points,
                                (const hsize_t **)coord);
    status = H5Rcreate(&line[0].end_point, line_group, "Instances", H5R_DATASET_REGION, point_space);
    status = H5Rcreate(&line[1].start_point, line_group, "Instances", H5R_DATASET_REGION, point_space);

/* Set coord to select the third array element (index 2) from the 1D array of point instances ()*/
    coord[0][0] = 2;
    status = H5Sselect_none(point_space);
    status = H5Sselect_elements(point_space, H5S_SELECT_SET,num_points,
                                (const hsize_t **)coord);
    status = H5Rcreate(&line[1].end_point, line_group, "Instances", H5R_DATASET_REGION, point_space);

     /* Wtite instances entity type line to the dataset  */
    status = H5Dwrite(line_dataset, line_tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, line);

    H5Tclose(point_tid);
    H5Sclose(point_space);
    H5Dclose(point_dataset);
    H5Gclose(point_group);
    H5Tclose(line_tid);
    H5Sclose(line_space);
    H5Dclose(line_dataset);
    H5Gclose(line_group);
    H5Gclose(pop1_group);
    H5Gclose(schema_group);
    H5Fclose(file);

}

