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


const int MAX =4;

// Maximum  wird SPALTENWEISE  gebildet  !!!!
// Also n-Loesungen

// Bitte geben Sie IMMER vier Task an
// Bestimme pro Client das jeweilige Maximum

// Struktur für die Information beider Werte
// Value UND Pid
struct MPIStruct {
	double value;
	int Pid;
};


void main(int argc, char *argv[])
{
	int Pid, i;
	int root = 0;
	int numprocs;

	// Jeder Prozess hat n-Werte  Eingangswerte
	// Es gibt k-Prozesse x n-Werte
	double dX[MAX]; // Eingangswerte
	double dY[MAX]; // "Berechnete Ausgangswerte"

	// wird nur vom Root verwendet
	// Ziel pro Index den Maximalwert, in dMax
	int index[MAX];
	double dMax[MAX];           

	// Variablen für die Reduce-Anweisung
	struct MPIStruct local_in[MAX];
	struct MPIStruct g_out[MAX];


	MPI_Init(&argc,&argv);

	// Anzahl der Prozesse
	MPI_Comm_size(MPI_COMM_WORLD,&numprocs);

	if ( numprocs != MAX ){
		printf("Bitte genau %d Prozesse starten\n", MAX);
		MPI_Finalize();
		return;
	}

	// meine eigene ID
	MPI_Comm_rank(MPI_COMM_WORLD,&Pid);

	// init
	for (i=0; i<MAX; i++) {
		dX[i] = 0;
		dY[i] = 0;
	}

	// Hier sollte aus einer Datei gelesen werden, pro Pid !
	switch (Pid) {
	case 0:
		dX[0] = 1;
		dX[1] = 2;
		dX[2] = 3;
		dX[3] = 33;
		break;
	case 1:
		dX[0] = 114;
		dX[1] = 0;
		dX[2] = -1;
		dX[3] = 1;
		break;
	case 2:
		dX[0] = 23;
		dX[1] = 1;
		dX[2] = 11;
		dX[3] = 14;
		break;
	case 3:
		dX[0] = 1;
		dX[1] = -2;
		dX[2] = 12;
		dX[3] = -7;
		break;
	}

	// Berechnung dy = f(dx)
	for (i=0; i<MAX; i++) {
		dY[i] = dX[i] +1;
	}

	// speichern in das lokale Feld local_in
	for (i=0; i<MAX; i++) {
		local_in[i].value = dY[i];
		local_in[i].Pid = Pid;
		printf("   Pid: %d   index: %d    Y: %f\n", Pid, i, dY[i]);			
	}


	// Aufruf der reduce-Anweisung
	/*MPI_Reduce(local_in, g_out, MAX, MPI_DOUBLE_INT,
	MPI_MAXLOC, root, MPI_COMM_WORLD);*/
	MPI_Allreduce(local_in, g_out, MAX, MPI_DOUBLE_INT,
		MPI_MAXLOC, MPI_COMM_WORLD);

	if (Pid  ==  root) {
		for (i=0; i<MAX; i++) {
			dMax[i] = g_out[i].value;
			index[i] = g_out[i].Pid;
			printf("Index: %d   Pid: %d   Maxwert: %f\n", i, index[i], dMax[i]);			
		} // for

	}  // if
	else {
		for (i=0; i<MAX; i++) {
			dMax[i] = g_out[i].value;
			index[i] = g_out[i].Pid;
			printf("Client Index: %d   Pid: %d   Maxwert: %f\n", i, index[i], dMax[i]);			
		} // for
	}



	MPI_Finalize();
}

/*
Ergebnisse:

Index: 0   Pid: 1   Maxwert: 5.000000
Index: 1   Pid: 2   Maxwert: 7.000000
Index: 2   Pid: 0   Maxwert: 4.000000


*/
