/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright by The HDF Group.                                               *
 * All rights reserved.                                                      *
 *                                                                           *
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
 * terms governing use, modification, and redistribution, is contained in    *
 * the COPYING file, which can be found at the root of the source code       *
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
 * If you do not have access to either file, you may request a copy from     *
 * help@hdfgroup.org.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/*
 *  This example illustrates how to create a dataset that is a 4 x 6
 *  array. It is used in the HDF5 Tutorial.
 */

#include <iostream>
using std::cout;
using std::endl;

#include <string>
#include "H5Cpp.h"
using namespace H5;

const H5std_string FILE_NAME("h5tutr_extend.h5");
const H5std_string DATASETNAME("ExtendibleArray");

int
main(void)
{
    hsize_t dims[2]       = {3, 3}; // dataset dimensions at creation
    hsize_t maxdims[2]    = {H5S_UNLIMITED, H5S_UNLIMITED};
    hsize_t chunk_dims[2] = {2, 5};
    int     data[3][3]    = {{1, 1, 1}, // data to write
                      {1, 1, 1},
                      {1, 1, 1}};

    // Variables used in extending and writing to the extended portion of dataset

    hsize_t size[2];
    hsize_t offset[2];
    hsize_t dimsext[2]    = {7, 3}; // extend dimensions
    int     dataext[7][3] = {{2, 3, 4}, {2, 3, 4}, {2, 3, 4}, {2, 3, 4}, {2, 3, 4}, {2, 3, 4}, {2, 3, 4}};

    // Try block to detect exceptions raised by any of the calls inside it
    try {
        // Turn off the auto-printing when failure occurs so that we can
        // handle the errors appropriately
        Exception::dontPrint();

        // Create a new file using the default property lists.
        H5File file(FILE_NAME, H5F_ACC_TRUNC);

        // Create the data space for the dataset.  Note the use of pointer
        // for the instance 'dataspace'.  It can be deleted and used again
        // later for another dataspace.  An HDF5 identifier can be closed
        // by the destructor or the method 'close()'.
        DataSpace *dataspace = new DataSpace(2, dims, maxdims);

        // Modify dataset creation property to enable chunking
        DSetCreatPropList prop;
        prop.setChunk(2, chunk_dims);

        // Create the chunked dataset.  Note the use of pointer.
        DataSet *dataset =
            new DataSet(file.createDataSet(DATASETNAME, PredType::STD_I32BE, *dataspace, prop));

        // Write data to dataset.
        dataset->write(data, PredType::NATIVE_INT);

        // Extend the dataset. Dataset becomes 10 x 3.
        size[0] = dims[0] + dimsext[0];
        size[1] = dims[1];
        dataset->extend(size);

        // Select a hyperslab in extended portion of the dataset.
        DataSpace *filespace = new DataSpace(dataset->getSpace());
        offset[0]            = 3;
        offset[1]            = 0;
        filespace->selectHyperslab(H5S_SELECT_SET, dimsext, offset);

        // Define memory space.
        DataSpace *memspace = new DataSpace(2, dimsext, NULL);

        // Write data to the extended portion of the dataset.
        dataset->write(dataext, PredType::NATIVE_INT, *memspace, *filespace);

        // Close all objects and file.
        prop.close();
        delete filespace;
        delete memspace;
        delete dataspace;
        delete dataset;
        file.close();

        // ---------------------------------------
        // Re-open the file and read the data back
        // ---------------------------------------

        int     rdata[10][3];
        int     i, j, rank;
        hsize_t chunk_dimsr[2], dimsr[2];

        // Open the file and dataset.
        file.openFile(FILE_NAME, H5F_ACC_RDONLY);
        dataset = new DataSet(file.openDataSet(DATASETNAME));

        // Get the dataset's dataspace and creation property list.
        filespace = new DataSpace(dataset->getSpace());
        prop      = dataset->getCreatePlist();

        // Get information to obtain memory dataspace.
        rank = filespace->getSimpleExtentNdims();
        (void)filespace->getSimpleExtentDims(dimsr);

        if (H5D_CHUNKED == prop.getLayout()) {
            int rank_chunk = prop.getChunk(rank, chunk_dimsr);
            cout << "rank chunk = " << rank_chunk << endl;
        }

        memspace = new DataSpace(rank, dimsr, NULL);
        dataset->read(rdata, PredType::NATIVE_INT, *memspace, *filespace);

        cout << endl;
        for (j = 0; j < dimsr[0]; j++) {
            for (i = 0; i < dimsr[1]; i++)
                cout << " " << rdata[j][i];
            cout << endl;
        }

        // Close all objects and file.
        prop.close();
        delete filespace;
        delete memspace;
        delete dataset;
        file.close();

    } // end of try block

    // catch failure caused by the H5File operations
    catch (FileIException error) {
        error.printErrorStack();
        return -1;
    }

    // catch failure caused by the DataSet operations
    catch (DataSetIException error) {
        error.printErrorStack();
        return -1;
    }

    // catch failure caused by the DataSpace operations
    catch (DataSpaceIException error) {
        error.printErrorStack();
        return -1;
    }

    return 0; // successfully terminated
}
