//Script de l'exécutable MAITRE qui reçoit en argument le nombre d'ouvrier

#include "fichier_entete.h"

int main(int argc, char* argv[]){
const int taille_tableau = 100;

  // ************************Table des nombres premiers********************************
  int table_premiers[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,56,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541};
  
  int nbre_ouvriers = atoi(argv[1]); //le nombre d'ouvriers
  int tableau_pid[nbre_ouvriers][2]; //Tableau qui contiendra les pid des ouvriers
  message_2 mess_nombre_premier;     // Structure des messages pour l'initialisation des nombres premiers
  message_1 mess_facteur;            // Structure des messages d'un facteur premier
  message_1 mess_pid;                //structure des messages des pid récupérés
  int quotient=  div(taille_tableau, nbre_ouvriers).quot; //le quotient de la division euclidienne de la taille du tableau des pid par le nombre d'ouvriers  
  int fd;                            //un descripteur
  int nombre;                        //nombre à décomposer
  int nvNombreADecomposer;
  int nombre_ouvriers_fini=0;       //le nombre d'ouvriers qui ont fini
  int cpt=0;
  
  // Création du tube canal, s'il existe déjà, on le supprime
  unlink("tmp/canal");      
  if (mkfifo("tmp/canal",0666)<0){
    perror("Erreur de création du tube canal");
    exit(1);
  }
  
  //********************Envoi des nombres premiers aux ouvriers**********************
  for(int j=0; j<nbre_ouvriers-1; j++){  //pour les n-1 premiers ouvriers
    mess_nombre_premier.fin=false;
    for(int k=0; k<quotient-1; k++){
      mess_nombre_premier.nombre=table_premiers[cpt];
      if (write(j+3, &mess_nombre_premier, sizeof(message_2))<0){
	perror("Erreur d'ecriture du struct pour l'envoi des nombres premiers aux ouvriers");
	exit(2);
      }
      cpt++;
    }
        
    // Pour le dernier nombre premier à envoyer à un ouvrier
    mess_nombre_premier.nombre=table_premiers[cpt++];
    mess_nombre_premier.fin=true;
    if (write(j+3, &mess_nombre_premier, sizeof(message_2))<0){
      perror("Erreur d'écriture du dernier nombre premier");
      exit(3);
    }
  }

  //pour le dernier ouvrier
  mess_nombre_premier.fin=false;
  while(cpt<taille_tableau-1){
    mess_nombre_premier.nombre=table_premiers[cpt++];
    if (write(nbre_ouvriers+2, &mess_nombre_premier, sizeof(message_2))<0){
      perror("Erreur d'ecriture des nombres premiers du dernier ouvrier");
      exit(4);
    }
  }
  //pour le dernier nombre premier du dernier ouvrier
  mess_nombre_premier.nombre=table_premiers[taille_tableau-1];
  mess_nombre_premier.fin=true;
  if (write(nbre_ouvriers+2, &mess_nombre_premier, sizeof(message_2))<0){
    perror("Erreur d'ecriture du dernier nombre du dernier ouvrier");
    exit(5);
  }
  //*****************fin transmission des nombres premiers*******************************

  // Ouverture du tube nommé en lecture seule
  fd=open("tmp/canal",O_RDONLY);
  if(fd<0){
    perror("Erreur d'ouverture du tube canal en lecture seule");
    exit(6);
  }
  // lecture des pid des ouvriers pour les stocker dans la table de pid
  cpt=0;
  for(int n=0; n<nbre_ouvriers; n++){
    if(read(fd,&mess_pid,sizeof(message_1))<0){ 
      perror("Erreur de lecture des pid dans le tube canal");
      exit(7);
    }
    tableau_pid[n][0]=mess_pid.pid;
  }
  
  
  cout<<endl;
  cout<<" __________________________________________________________"<<endl;
  cout<<"|Logiciel de décomposition d'un nombre en facteurs premiers|"<<endl;
  cout<<" -----------Julien VAN DEN BOSSCHE/Benoît MOULIN----------- "<<endl; 
  cout<<endl<<endl;


  //boucle principale
  while(1){//do{
    for(int i=0; i<nbre_ouvriers; i++){
      tableau_pid[i][1]=0;        //initialisation du signal de fin de tâche des ouvriers à 0
      // cout<<tableau_pid[i][0]<<" "<<tableau_pid[i][1]<<" ";
    }
    cout<<"Entrez le nombre à décomposer (0 pour terminer)"<<endl;
    cout<<"Attente d'un nombre> "; 
    cin>>nombre;
    cout<<endl;
    if(nombre == 0){  //si l'utilisateur quitte le programme
      cout<<" ______________________________________________ "<<endl;
      cout<<"|     Merci d'avoir utilisé notre logiciel     |"<<endl;
      cout<<" ---------------------------------------------- "<<endl;
      exit(0);
    }
    cout<<"Les facteurs premiers sont :\n";
    //On communique le nombre à tous les ouvriers
    mess_nombre_premier.nombre=nombre;
    for(int i=0; i<nbre_ouvriers; i++){
      if(write(i+3, &mess_nombre_premier, sizeof(message_2))<0){
	perror("Erreur d'écriture du nombre à décomposer aux fils");
	exit(8);
      }
    }
    //****************On se met à l'écoute du tube nommé**********************************
    nvNombreADecomposer=nombre;
    while(nvNombreADecomposer!=1){
      if(read(fd,&mess_facteur,sizeof(message_1))<0){
	perror("Erreur de lecture de la structure");
	exit(9);
      }
      
      if (mess_facteur.facteur!=0){ // Si l'ouvrier n'a pas fini sa tache
	nvNombreADecomposer=nvNombreADecomposer/mess_facteur.facteur;
	cout<< mess_facteur.facteur<<endl;
	mess_facteur.facteur=0;
      }
      else{ // Sinon on indique qu'il a terminé dans le tableau des pid
	cpt=0;
	while(tableau_pid[cpt++][0]!=mess_pid.pid){
	  tableau_pid[cpt][1]=1;
	  nombre_ouvriers_fini++;
	}
      }
      
      if (nombre_ouvriers_fini==nbre_ouvriers){
	cout<<nvNombreADecomposer<<endl;
	nvNombreADecomposer=1;
      }
    }
    
    //affichage des pid des ouvriers et de leurs états  
    for(int i=0; i<nbre_ouvriers; i++){
      cout<<tableau_pid[i][0]<<"\t"<<tableau_pid[i][1]<<endl;
    }
    // On envoie un signal à tous les ouvriers n'ayant pas terminés leurs tâches
    for(int i=0; i<nbre_ouvriers; i++){
      if (tableau_pid[i][1]==0){ 
	kill(tableau_pid[i][0],SIGUSR1);
      }
    }
  }
  

  // Si on arrête l'exécution
  if (close(fd)<0){ //on ferme le tube nommé 
    perror("Erreur de fermeture du tube canal");
    exit(10);
  }
  
  // On supprime le tube canal
  if(unlink("/tmp/canal")<0){ 
    perror("Erreur de unlink de canal");
    exit(11);
  }
 
  // On ferme les tubes ordinaires
  for(int i=0; i<nbre_ouvriers; i++){
    if (close(i+3)<0){
      perror("Erreur de fermeture du tube ordinaire");
       exit(12);
    }
  }
  
  //  On supprime les processus ouvriers
  for(int i=0; i<nbre_ouvriers; i++){
    kill(tableau_pid[i][0],SIGKILL);
  }
  return(1);
}

