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

double data[1] = {.0};

void initialize_ring(int tasks) {
    double received;
    MPI_Status status;

    printf("Sending first data...");
    MPI_Send(data, 1, MPI_DOUBLE, 1, 0, MPI_COMM_WORLD);
    puts("sent");
    MPI_Recv(&received, 1, MPI_DOUBLE, tasks - 1, MPI_ANY_TAG, MPI_COMM_WORLD,
            &status);

    if( received != *data )
        printf("Received data does not match (sent: %f, received: %f)\n",
                *data, received);
    else
        puts("Data received succesfully");
}

void pass_data(int tasks, int rank) {
    double received;
    MPI_Status status;
    int target = (rank + 1) % tasks, source = (rank - 1 + tasks) % tasks;

    MPI_Recv(&received, 1, MPI_DOUBLE, source, MPI_ANY_TAG, MPI_COMM_WORLD,
            &status);
    printf("Task %d received data from %d, sending to %d...", rank, source,
            target);
    MPI_Send(data, 1, MPI_DOUBLE, target, 0, MPI_COMM_WORLD);
    puts("sent");
}

int main(int argc, char **argv) {
    int tasks, rank, error;

    if( (error = MPI_Init(&argc, &argv)) != MPI_SUCCESS ) {
        printf("MPI_init failed (error %d)\n", error);
        MPI_Abort(MPI_COMM_WORLD, error);
        return EXIT_FAILURE;
    }

    MPI_Comm_size(MPI_COMM_WORLD, &tasks);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    if( !rank )
        initialize_ring(tasks);
    else
        pass_data(tasks, rank);

    MPI_Finalize();

    return EXIT_SUCCESS;
}
