/* ///////////////////////////////////////////////////////////////////// */
/*!
 \file
 \brief Data communication in a ring.
 
 For each processor, define a unique string defining the process
 color and perform n cyclic permutations by transferring the color
 name to the process to the right.
 Three versions are provided:
 
 i)   using MPI_Send / Recv()   (select VERSION == 0);
 ii)  using MPI_Sendrecv()      (select VERSION == 1);
 iii) using MPI_Isend / Irecv() (select VERSION == 2).
 
 \author A. Mignone (mignone@to.infn.it)
 \date   March 10, 2020
 */
/* ///////////////////////////////////////////////////////////////////// */


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

#define STR_LENGTH 32
#define VERSION 1

int main(int argc, char ** argv)
{
    int rank, size;
    int dstL, dstR;
    char recv_buf[STR_LENGTH];
    char send_buf[STR_LENGTH];
    MPI_Request req;
    
    /* -- 1. Initialize the MPI execution environment -- */
    
    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    
    /* -- 2. Define color -- */
    
    if (rank == 0) sprintf (send_buf, "red");
    if (rank == 1) sprintf (send_buf, "blue");
    if (rank == 2) sprintf (send_buf, "green");
    if (rank == 3) sprintf (send_buf, "black");
    if (rank == 4) sprintf (send_buf, "orange");
    if (rank == 5) sprintf (send_buf, "yellow");
    
    if (size > 6){
        if (rank == 0) printf ("! Cannot execute with more than six processes\n");
        MPI_Finalize();
        return 0;
    }
    
    /* -- 3. Determine neighbour processors -- */
    
    dstL  = rank - 1;
    dstR  = rank + 1;
    if (dstL < 0)     dstL = size-1;
    if (dstR >= size) dstR = 0;
    
    int n;
    for (n = 0; n < size; n++){
#if VERSION == 1
        MPI_Send(send_buf, STR_LENGTH, MPI_CHAR, dstR, 0, MPI_COMM_WORLD);
        MPI_Recv(recv_buf, STR_LENGTH, MPI_CHAR, dstL, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
#elif VERSION == 2
        MPI_Sendrecv(send_buf, STR_LENGTH, MPI_CHAR, dstR, 0,
                     recv_buf, STR_LENGTH, MPI_CHAR, dstL, 0, MPI_COMM_WORLD,
                     MPI_STATUS_IGNORE);
#elif VERSION == 3
        MPI_Isend(send_buf, STR_LENGTH, MPI_CHAR, dstR, 0, MPI_COMM_WORLD, &req);
        MPI_Irecv(recv_buf, STR_LENGTH, MPI_CHAR, dstL, 0, MPI_COMM_WORLD, &req);
        MPI_Wait (&req, MPI_STATUS_IGNORE);
#endif
        
        /* -- Replace color -- */
        
        sprintf (send_buf,"%s",recv_buf);
        if (rank == 0){
            printf ("Proc #%d, I've changed my color is %s\n", rank, send_buf);
        }
    }
    
    MPI_Finalize();
    return 0;
}
