#include "mpi.h"
#include <stdio.h>
#include <stdlib.h>
#include <iostream>

void CHECK_ERROR(int error) {
    if (error != MPI_SUCCESS) {
        char message[1024];
        int mlength;
        MPI_Error_string(error, message, &mlength);
        std::cerr << "MPI ERROR: " << message << std::endl;
        abort();
    }
}

int main( int argc, char *argv[] )
{
    int err;
    int size, rank, *buf;
    MPI_Offset offset;
    MPI_File fh;
    MPI_Comm comm;
    MPI_Status status;
    MPI_Datatype filetype;

    MPI_Init( &argc, &argv );
    comm = MPI_COMM_WORLD;
    MPI_Comm_size( comm, &size );
    MPI_Comm_rank( comm, &rank );

    int datalen = 0;
    int blocklengths[3];
    MPI_Aint displacements[3];

#ifdef USE_ORDER

    if(rank == 0) {
        blocklengths[0] = 8;
        blocklengths[1] = 231670;
        blocklengths[2] = 116606;
        displacements[0] = 0;
        displacements[1] = 8;
        displacements[2] = 231678;
    } else {
        blocklengths[0] = 85360;
        blocklengths[1] = 64003;
        blocklengths[2] = 131973;
        displacements[0] = 348284;
        displacements[1] = 433644;
        displacements[2] = 497647;
    }

#else

    if(rank == 0) {
        blocklengths[0] = 8;
        blocklengths[1] = 116606;
        blocklengths[2] = 231670;
        displacements[0] = 0;
        displacements[1] = 231678;
        displacements[2] = 8;
    } else {
        blocklengths[0] = 64003;
        blocklengths[1] = 85360;
        blocklengths[2] = 131973;
        displacements[0] = 433644;
        displacements[1] = 348284;
        displacements[2] = 497647;
    }

#endif

    if(rank == 0) {
        datalen = 348284;
    } else {
        datalen = 281336;
    }

    char *data = (char*) calloc(1, datalen);

    if(data == NULL) {
        printf("ERROR WHILE ALLOCATION \n");
        MPI_Abort(MPI_COMM_WORLD, 111);
    }

    CHECK_ERROR (MPI_Type_create_hindexed(3, blocklengths, displacements, MPI_BYTE, &filetype) );
    CHECK_ERROR( MPI_Type_commit(&filetype) );

    CHECK_ERROR( MPI_File_open( comm, "test.bbp", MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_INFO_NULL, &fh ) );
    CHECK_ERROR( MPI_File_set_view(fh, 0, MPI_BYTE, filetype, "native", MPI_INFO_NULL) );

    //CHECK_ERROR( MPI_File_write_all(fh, data, datalen, MPI_BYTE, &status) );
    CHECK_ERROR( MPI_File_write(fh, data, datalen, MPI_BYTE, &status) );

    free(data);

    CHECK_ERROR( MPI_File_close(&fh) );
    MPI_Type_free(&filetype);
    MPI_Finalize();

    return 0;
}
