// Wertetabelle1.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <mpi.h>


const int ROOT=0;
const  int MAX=100;

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

	MPI_Status	status;
    double   x_root[MAX];
    double   y_root[MAX];
	double x=-1.0;
	double y=-1.0;

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

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

	if ( numprocs <2 ){
		puts("Bitte mit mindestens mit zwei Prozesse starten");
		MPI_Finalize();
		return 1;
	}
	if ( numprocs >MAX ){
		printf("Bitte mit maximal %d Prozessen starten",MAX);
		MPI_Finalize();
		return 1;
	}
   
	   // meine eigene ID
	if ( MPI_Comm_rank(MPI_COMM_WORLD,&Pid) !=MPI_SUCCESS) {
		printf( "MPI_Comm_rank fehlerhaft\n");
		MPI_Finalize();
		return 1;
	}
	
	int fktnr=0;
	if(Pid==ROOT) {
		fktnr=1;
		for (int i=1; i<numprocs; i++){
			retcode = MPI_Send( &fktnr, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
			if ( retcode!= MPI_SUCCESS) {
				puts("Fehler beim Aufruf von Send");
			}
		}
	}
	else {
		retcode = MPI_Recv( &fktnr, 1, MPI_INT, ROOT, 0, MPI_COMM_WORLD, &status);
		if ( retcode!= MPI_SUCCESS) {
			puts("Fehler beim Aufruf von Recv");
		}
		//printf(" Anz Task: %d  Pid:%d   FktNr: %d\n",numprocs, Pid, fktnr);
	}
	if(Pid==ROOT) {
		for (i=0; i<numprocs; i++) {
			x_root[i] = i*0.5;
		}
	}
	int client_size=1;
    // MPI_Scatter(x_root, client_size, MPI_DOUBLE, x, client_size, MPI_DOUBLE, 0, MPI_COMM_WORLD);
    retcode = MPI_Scatter(x_root, client_size, MPI_DOUBLE, &x, client_size, MPI_DOUBLE, 0, MPI_COMM_WORLD);
	if ( retcode!= MPI_SUCCESS) {
		puts("Fehler beim Aufruf von Scatter");
	}
    // printf("   Pid:%d   x: %f\n",Pid, x);

	switch (fktnr) {
		case 1: y=2*x+4;  
				break;
		case 2: y=0.5*x*x-4*x+0.5;  
				break;
		default:printf("Fehlerhafte case-Anweisung fktnr: %d\n",fktnr);
				MPI_Finalize();
				return 1;
	}
    printf("   Pid:%d   x: %f   y: %f\n",Pid, x, y);
	
	client_size=1;
	// MPI GATHER(sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, root, comm)
    retcode = MPI_Gather(&y, client_size, MPI_DOUBLE,  y_root, client_size,  MPI_DOUBLE, ROOT, MPI_COMM_WORLD);
	
	if ( retcode!= MPI_SUCCESS) {
		puts("Fehler beim Aufruf von Gather");
	}
	if(Pid==ROOT) {
		for (i=0; i<numprocs; i++) {
			printf("          i:%d   y(i): %f\n",i, y_root[i]);
		}
	}
	double ysum=-1;
	// MPI REDUCE(sendbuf, recvbuf, count, datatype, op, root, comm)
	// retcode = MPI_Reduce(&local_change, &root_change, 1, MPI_INT, MPI_SUM, ROOT, MPI_COMM_WORLD);
	retcode = MPI_Reduce(&y, &ysum, 1, MPI_DOUBLE, MPI_SUM, ROOT, MPI_COMM_WORLD);
	if(Pid==ROOT) {
		printf("          ysum: %f\n",ysum);
	}

	double ymax=-1;
	retcode = MPI_Reduce(&y, &ymax, 1, MPI_DOUBLE, MPI_MAX, ROOT, MPI_COMM_WORLD);
	if(Pid==ROOT) {
		printf("          ymax: %f\n",ymax);
	}

    MPI_Finalize();
	return 0;
}

