package openMPITest;

import java.util.Arrays;
import java.util.Random;

import mpi.*;


public class MPICommTest {
	
	public static boolean allFalse(boolean[] a){
		boolean f = true;
		for (int i = 1; i < a.length; i++){
			f = f & !a[i];
		}
		return f;
	}

	public static void main(String[] args) throws MPIException {
		MPI.Init(args);
		int myrank = MPI.COMM_WORLD.getRank();
		int all = MPI.COMM_WORLD.getSize();
		int[] buff = new int[4];
		
		if (myrank == 0){
			buff[0] = 200; //length
			buff[1] = 1000; //repeat
			MPI.COMM_WORLD.bcast(buff, 4, MPI.INT, 0);
			System.out.printf("rank %d send out bcast. value = (%d, %d).\n", myrank, buff[0], buff[1]);
			
			//simulate sending data
			final int totalWork = 1000;
			int sendTo = 1;
			boolean[] status = new boolean[all];
			Arrays.fill(status, true);
			status[0] = false;
			int currentWork = 0;
			int[] result = new int[totalWork];
			
			while (currentWork < totalWork){
				if (status[sendTo]){
					buff[0] = 0; //code, whether to run
					buff[1] = sendTo; //process ID
					buff[2] = currentWork; //data ID
					buff[3] = 1; //data
					MPI.COMM_WORLD.send(buff, 4, MPI.INT, sendTo, 0);
					status[sendTo] = false;
					currentWork++;
				}
				sendTo = (sendTo + 1) % (all - 1) + 1;// change value every loop
				if (allFalse(status)){
					MPI.COMM_WORLD.recv(buff, 4, MPI.INT, MPI.ANY_SOURCE, 0);
					status[buff[1]] = true;
					result[buff[2]] = buff[3];
				}
			}
			buff[0] = 1;//stop code;
			for (int i = 1; i < all; i++){
				MPI.COMM_WORLD.send(buff, 4, MPI.INT, i, 0);
			}
			
		}else{
			int k = 0;
			MPI.COMM_WORLD.bcast(buff, 4, MPI.INT, 0);
			System.out.printf("rank %d recieved bcast. value = (%d, %d).\n", myrank, buff[0], buff[1]);
			Random r = new Random();
			while (true){
				MPI.COMM_WORLD.recv(buff, 4, MPI.INT, 0, 0);
				System.out.printf("(rank %d) received ID=%d\n", myrank, buff[2]);
				if (buff[0] == 1){
					System.out.printf("(rank %d) processed %d\n", myrank, k);
					break;
				}else{
					k++;
					buff[3] = buff[2] + 100000*buff[1] + 10000000 * (r.nextInt(98) + 1);
					try {
						Thread.sleep(r.nextInt(200));
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					MPI.COMM_WORLD.send(buff, 4, MPI.INT, 0, 0);
				}
			}
		}
		
		
		
		MPI.Finalize();
	}

}
