// Melita Mihaljevic 0036411392
// Neimenovani cjevovodi

//Napisati program za provjeru znanja aritmetickih operacija. Program može citati pripremljene zadatke iz neke datoteke ili ih generirati nekim postupkom. 
//Zadatak ispisuje na standardni izlaz, dohvaca odgovor sa standardnog ulaza i usporeduje ga sa ispravnim odgovorom. Broj postavljenih zadataka treba biti ogranicen.
//Ispravan odgovor treba tražiti koristeci program bc (aritmeticki jezicni procesor).
//Program treba pokrenuti bc i pomocu dva cjevovoda se povezati s njegovim standardnim ulazom i izlazom. Zatim svaki izraz koji treba izracunati šalje se na ulaz bc koji ce 
//dati neki rezultat na izlaz (cjevovodi povezani na standardni ulaz i izlaz programa bc). Taj rezultat treba analizirati i usporediti sa brojem koji je unijet sa tipkovnice ako je
//numericki podatak. Inace treba pretpostaviti da je u izrazu bilo grešaka i ispisati odgovarajucu poruku. Ako je unijeta tocna vrijednost ispisati ISPRAVNO, inace 
//NEISPRAVNO, tocan odgovor je [tocan odgovor].

#include <time.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

#define DULJINA_SPREMNIKA 10   // zadan aduljina spremnika

// glavni program

int main (int argc, char **argv)
{
	pid_t pid; // proces id
	char spremnik[DULJINA_SPREMNIKA];
	int o1, o2, operacija, br_zadataka, tmp, fds_in[2], fds_out[2]; // cjevovodi
	int tocno, odgovor;
// čitanje parametara programa	
	if (argc != 2) {
		fprintf (stderr, "Krivo zadani parametri programu a.out broj_upita\n");
		exit (EXIT_SUCCESS);
	}
// koliko je broj zadataka zadan 
	if (sscanf (argv[1], "%d", &br_zadataka) != 1) {
		fprintf (stderr, "Sintaksa: a.out broj_upita\n");
		exit (EXIT_FAILURE);
	}
// dio s generiranjem zadataka, otvaranjem cjevovoda

	while (br_zadataka--) {	
		srand ((unsigned) time (NULL));
// cjevovodi se kreiraju sa pipe  i vraca vec gotovu gresku sa perror

		if (pipe (fds_in) == -1 || pipe (fds_out) == -1) {
			perror ("pipe");
			exit (EXIT_FAILURE);
		}
// forkam proces kojem prensem opisnik i od cjevovoda

		if ((pid = fork ()) == -1 ) {
			perror ("fork");
			exit (EXIT_FAILURE);
		}
// zatvorim cjevovod prvi za pisanje , a drugi za citanje	
		if (pid == 0) {
			close (fds_in[1]);
			close (fds_out[0]);
			
			// duplicira opinike datoeka  na STDIN I STDOUT ako je bio zauzet onda se prethodno zatvara
			dup2 (fds_in[0], STDIN_FILENO);
			dup2 (fds_out[1], STDOUT_FILENO);
			
			// prepisujem forkano dijete i pokrecem bc, javlja gresku ako nije uspio
			if (execlp ("bc", "bc", NULL) == -1) {
				perror ("bc");
				exit (EXIT_FAILURE);
			}
		
			close (fds_out[1]); // zatvaram cjevovd i time se ubija i bc
		} else {
			close (fds_in[0]); // zatvaram cjevovde
			close (fds_out[1]);

			o1 = rand () % 99 + 1; // random generiranje operanda 1
			o2 = rand () % 99 + 1; // random generiranje operanda 2
			operacija = rand () % 4; // random generiranje operacije
	
			switch (operacija) { // u ovisnosti o operaciji ima +,-,* /
				case 0:
					sprintf (spremnik, "%d+%d\n", o1, o2);
					break;
			
				case 1:
					sprintf (spremnik, "%d-%d\n", o1, o2);
					break;
			
				case 2:
					sprintf (spremnik, "%d*%d\n", o1, o2);
					break;

				case 3:
					sprintf (spremnik, "%d/%d\n", o1, o2);
					break;
			}

			write (STDOUT_FILENO, spremnik, strlen (spremnik) - 1);
	
			printf (" = ");
			fflush (stdout); // cisti standardni output (oslobadja ga)
			scanf ("%d", &odgovor);
		
			write (fds_in[1], spremnik, strlen (spremnik));
			close (fds_in[1]);

			wait (NULL);
	
			tmp = read (fds_out[0], spremnik, DULJINA_SPREMNIKA);
			spremnik[tmp] = '\0';

			sscanf (spremnik, "%d", &tocno);

			if (tocno == odgovor)
				printf ("TOCNO\n\n");
			else
				printf ("NETOCNO [Tocan odgovor = %d]\n\n", tocno); // ispsisuje da li je dobro napisano.
		}
	}
		
	return EXIT_SUCCESS;
}

