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

/*
 Version 2 
 Aufteilen von 1 bis n auf     m Workers 
 Falls ein Rest vorhanden ist, wird die Aufteilung  client_size um eins erhöht 
 geht die Aufteilung nicht auf, ist es schwierig die 
     Anzahl der übermittelten daten zu bestimmen

 Nach der Übermittlung wird eine Funktion ausgeführt, add um 2
 und dann werden mittels der Gather-Anweisung die Daten wieder gesammelt
*/


const int C_MAX = 12;


int main(int argc, char *argv[]) {
	int     root = 0;
    int     numprocs, Pid, i;
    int     x_root[C_MAX];
    int     y_root[C_MAX];
	int     client_size;
    div_t   part;
//	MPI_Status status;

	int retcode;
    
	int     x[C_MAX];
    int     y[C_MAX];

    if (MPI_Init(&argc,&argv)!=MPI_SUCCESS) {
		printf("MPI_Init failed.\n");
		return -1;
    }

    MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
    MPI_Comm_rank(MPI_COMM_WORLD, &Pid);

    printf("Proc %d: I live.\n", Pid, numprocs);

    if (Pid==0) {
		  // Daten im Master erzeugen
		for (i=0; i<C_MAX; i++) {
			x_root[i] = i+1;
		}
		puts("  ");
    }
    
	  // zur Kontrolle auf Null gesetzt
	for (i=0; i<C_MAX; i++) {
		x[i] = 0;
	}

	
	part=div(C_MAX,numprocs);
	if (part.rem!=0) 
		client_size=part.quot+1;        
	else 
		client_size=part.quot;	


	printf("client_size %d\n",client_size);

	

/*
Der Sendepuffer (seine Größe sei n Elemente) wird in Teile der Länge n / Gruppengröße 
	geteilt und mit Prozess 0 beginnend verteilt. Sollte die Division nicht aufgehen, 
	erhalten die ersten Prozesse um 1 größere Teile und der Prozeß 
	mit der höchsten ID den Rest.
*/
    retcode = MPI_Scatter(x_root, client_size, MPI_INT, x, client_size, MPI_INT, 0, MPI_COMM_WORLD);
	if ( retcode!= MPI_SUCCESS) {
		puts("Fehler beim Aufruf von Scatter");
	}

/*
MPI_SUCCESS
    - No error; MPI routine completed successfully. 
MPI_ERR_COMM
    - Invalid communicator. A common error is to use a null communicator in a call (not even allowed in MPI_Comm_rank ). 
MPI_ERR_COUNT
    - Invalid count argument. Count arguments must be non-negative; a count of zero is often valid. 
MPI_ERR_TYPE
    - Invalid datatype argument. May be an uncommitted MPI_Datatype (see MPI_Type_commit ). 
MPI_ERR_BUFFER
    - Invalid buffer pointer. 
*/

 //   MPI_Get_count(&status, MPI_INT, &client_size);
			

    
	printf("Alle Clients  client_size %d\n",client_size);

	  // zur Kontrolle auf Null gesetzt und zur Sicherheit um 2 erhöht
	for (i=0; i<client_size+2; i++) {
		printf("Pid %d  i:  %d  x[i]: %d\n",Pid, i, x[i]);		
	}
		puts("  ");
		puts("  ");
	for (i=0; i<client_size+2; i++) {
		y[i] = x[i] + 2;
	}

    

    retcode = MPI_Gather(y, client_size, MPI_INT, y_root, 
		client_size, MPI_INT, 0, MPI_COMM_WORLD);    
	if ( retcode!= MPI_SUCCESS) {
		puts("Fehler beim Aufruf von Gather");
	}


	if (Pid == 0 ) {
		for (i=0; i<C_MAX; i++) {
			printf("Pid %d  i:  %d  y[i]: %d\n",Pid, i, y_root[i]);
		}
		puts("  ");
		puts("  ");
	}


    MPI_Finalize();
	return 0;
}  // main



