#include <hdf5.h>
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>

#define CHECK(x) do { if ((x) < 0) MPI_Abort(MPI_COMM_WORLD, 1); } while (0)

int main(int argc, char **argv)
{
    int rank, size, value, result = -1;
    hid_t access, file, space, dataset, memory, transfer;
    hsize_t count[1] = {1}, offset[1], dimensions[1];
    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    dimensions[0] = (hsize_t)size;
    offset[0] = (hsize_t)rank;
    value = rank + 10;

    CHECK(access = H5Pcreate(H5P_FILE_ACCESS));
    CHECK(H5Pset_fapl_mpio(access, MPI_COMM_WORLD, MPI_INFO_NULL));
    CHECK(file = H5Fcreate("example.h5", H5F_ACC_TRUNC, H5P_DEFAULT, access));
    CHECK(space = H5Screate_simple(1, dimensions, NULL));
    CHECK(dataset = H5Dcreate2(file, "values", H5T_NATIVE_INT, space,
                             H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT));
    CHECK(memory = H5Screate_simple(1, count, NULL));
    CHECK(H5Sselect_hyperslab(space, H5S_SELECT_SET, offset, NULL, count, NULL));
    CHECK(transfer = H5Pcreate(H5P_DATASET_XFER));
    CHECK(H5Pset_dxpl_mpio(transfer, H5FD_MPIO_COLLECTIVE));
    CHECK(H5Dwrite(dataset, H5T_NATIVE_INT, memory, space, transfer, &value));
    CHECK(H5Dclose(dataset));
    CHECK(H5Fclose(file));

    CHECK(file = H5Fopen("example.h5", H5F_ACC_RDONLY, access));
    CHECK(dataset = H5Dopen2(file, "values", H5P_DEFAULT));
    CHECK(H5Dread(dataset, H5T_NATIVE_INT, memory, space, transfer, &result));
    if (result != value) MPI_Abort(MPI_COMM_WORLD, 2);
    CHECK(H5Dclose(dataset));
    CHECK(H5Fclose(file));
    CHECK(H5Pclose(transfer));
    CHECK(H5Sclose(memory));
    CHECK(H5Sclose(space));
    CHECK(H5Pclose(access));
    if (rank == 0) printf("PASS: %d processes wrote and read back their values\n", size);
    MPI_Finalize();
    return EXIT_SUCCESS;
}
