// Betriebssysteme1 - Uebung 11, Matthias Jauernig, 2005
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdbool.h>
#include <string.h>

int main(void){
	int fd1[2], fd2[2], rc, l;
	pid_t pid1, pid2;
	bool ende1, ende2;
	char ea1[100], ea2[100], *ret1, *ret2;
	
	// erste Pipe öffnen
	if((rc=pipe(fd1)) < 0){
		perror("Fehler beim Oeffnen von Pipe1");
		return 1;
	}
	
	// ersten Child erzeugen
	if((pid1=fork()) == -1){
		perror("Fehler beim Erzeugen von Child1");
		return 2;
	}
	
	switch(pid1){
		case 0: // im Child1
			if(close(fd1[0]) < 0){ // schließe die eine Pipe-Seite
				perror("Konnte Pipe1-Seite in Child1 nicht schließen");
				return 3;
			}
			// lese Daten, bis EOF
			do{
				// empfange "Arbeitserlaubnis" vom Parent
				if((l=read(fd1[1], ea1, sizeof(ea1))) < 0){
					perror("Initialer Read im Child1");
					return 13;
				}
				// lese Daten von stdin
				fflush(stdin);
				printf("Child1: Dateneingabe: ");
				ret1 = fgets(ea1, sizeof(ea1), stdin);
				// Daten an Parent senden
				if(ret1){
					if((l=write(fd1[1], ea1, sizeof(ea1))) < 0){
						perror("Fehler beim Senden der Daten von Child1 zum Parent");
						return 14;
					}
				}
			}while(ret1);
			// bei Fehler oder EOF Pipe schließen, Child verlassen
			if(close(fd1[1]) < 0){ // schließe die letzte offene Pipe-Seite
				perror("Konnte Pipe in Child1 nicht endgueltig schließen");
				return 15;
			}
			break;
		default:// im Parent
			if(close(fd1[1]) < 0){ // schließe die andere Pipe-Seite
				perror("Konnte Pipe1-Seite in Parent nicht schließen");
				return 4;
			}
			// zweite Pipe öffnen
			if((rc=pipe(fd2)) < 0){
				perror("Fehler beim Oeffnen von Pipe2");
				return 5;
			}
			// zweiten Child erzeugen
			if((pid2=fork()) == -1){
				perror("Fehler beim Erzeugen von Child2");
				return 6;
			}
			
			switch(pid2){
				case 0:	// im Child2
					if(close(fd2[0]) < 0){ // schließe die eine Pipe-Seite
						perror("Konnte Pipe2-Seite in Child2 nicht schließen");
						return 7;
					}
					// lese Daten, bis EOF
					do{
						// empfange "Arbeitserlaubnis" vom Parent
						if((l=read(fd2[1], ea2, sizeof(ea2))) < 0){
							perror("Initialer Read im Child2");
							return 16;
						}
						// lese Daten von stdin
						fflush(stdin);
						printf("Child2: Dateneingabe: ");
						ret2 = fgets(ea2, sizeof(ea2), stdin);
						// Daten an Parent senden
						if(ret2){
							if((l=write(fd2[1], ea2, sizeof(ea2))) < 0){
								perror("Fehler beim Senden der Daten von Child2 zum Parent");
								return 17;
							}
						}
					}while(ret2);
					// bei Fehler oder EOF Pipe schließen, Child verlassen
					if(close(fd2[1]) < 0){ // schließe die letzte offene Pipe-Seite
						perror("Konnte Pipe in Child2 nicht endgueltig schließen");
						return 18;
					}
					break;
				default:// im Parent
					if(close(fd2[1]) < 0){ // schließe die andere Pipe-Seite
						perror("Konnte Pipe2-Seite in Parent nicht schließen");
						return 8;
					}
					
					// Kommunikation mit Childs
					ende1 = false;
					ende2 = false;
					do{
						// Kommunikation mit Child1
						if(!ende1){
							strncpy(ea1,"1", 2);
							// Child1 soll Daten lesen und senden
							if((l=write(fd1[0], ea1, sizeof(ea1))) < 0){
								perror("Fehler beim initialen Senden zu Child1");
								return 9;
							}
							// empfange Daten von Child1
							if((l=read(fd1[0], ea1, sizeof(ea1))) < 0){
								perror("Fehler beim Daten-Empfang von Child1");
								return 10;
							}else{
								if(l==0){
									printf("Parent: Child1 beendet\n");
									ende1 = true;
									if(close(fd1[0]) < 0){
										perror("Konnte Pipe1 in Parent nicht endgueltig schließen");
										return 19;
									}
								}else
									printf("Parent: Von Child1 empfangen: %s\n", ea1);
							}
						}
						
						// Kommunikation mit Child2
						if(!ende2){
							strncpy(ea2,"2", 2);
							// Child2 soll Daten lesen und senden
							if((l=write(fd2[0], ea2, sizeof(ea2))) < 0){
								perror("Fehler beim initialen Senden zu Child2");
								return 11;
							}
							// empfange Daten von Child2
							if((l=read(fd2[0], ea2, sizeof(ea2))) < 0){
								perror("Fehler beim Daten-Empfang von Child2");
								return 12;
							}else{
								if(l==0){
									printf("Parent: Child2 beendet\n");
									ende2 = true;
									if(close(fd2[0]) < 0){
										perror("Konnte Pipe2 in Parent nicht endgueltig schließen");
										return 20;
									}
								}else
									printf("Parent: Von Child2 empfangen: %s\n", ea2);
							}
						}
					
					}while(!ende1 || !ende2);
					printf("Parent: Beide Childs beendet...\n");
					
					break;
			}
			
			break;
	}
	
	return 0;
}

