#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include "mpi.h"

#define maxn 5

int main(int argc, char *argv[]) {
	int rank, size, i, j, prtsz;
	MPI_Status status;
	double x[maxn][maxn];
	double recvbuf[maxn];
	int row,col;
	char *getit, app[10];
	MPI_Datatype Col;

	MPI_Init(&argc, &argv);

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

	if (maxn % (size-1) != 0) {
		if (rank==0) fprintf(stderr, "np-1 must divide into %d\n", maxn);
		MPI_Abort(MPI_COMM_WORLD, 1);
	}

	srand(time(0));
	if (rank == 0) {
		for (i = 0; i < maxn; i++)
			for (j = 0; j < maxn; j++)
				x[i][j] = rand() % 10;

		/* Print matrix from root process */
		printf("Matrix X:\n");
		for (i = 0; i < maxn; i++) {
			for (j = 0; j < maxn; j++)
				printf("%4.1f", x[i][j]);
			printf("\n");
		}
		
		/* Send each row of matrix X to a seperate process */
		for (i = 0; i < maxn; i++)
			MPI_Send(&x[i], maxn, MPI_DOUBLE, i + 1, 0, MPI_COMM_WORLD);
		/* Print each row from each process */
		for (i = 1; i <= maxn; i++) {
			MPI_Recv(&prtsz, 1, MPI_INT, i, 1, MPI_COMM_WORLD, &status);
			getit = malloc(prtsz * sizeof(char));
			MPI_Recv(getit, prtsz, MPI_CHAR, i, 2, MPI_COMM_WORLD, &status);
			printf("%s\n", getit);
			free(getit);
		}
	}

	if (rank > 0) {
		prtsz = 160;
		getit = malloc(prtsz * sizeof(char));
		sprintf(getit, "Process: %d, RECVBUF: ", rank);
		MPI_Recv(recvbuf, maxn, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &status);
		/* Print out each row from a different process */
		for (i = 0; i < maxn; i++) {
			sprintf(app, "%4.1f", recvbuf[i]);
			strcat(getit, app);
		}
		prtsz = strlen(getit);
		MPI_Send(&prtsz, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
		MPI_Send(getit, prtsz, MPI_CHAR, 0, 2, MPI_COMM_WORLD);
		free(getit);
	}
	
	MPI_Finalize();
	return 0;
}
