#include "Beloeil-Charbonnel-Dinh-automate.h"


using namespace std;

bool Automate::readFile(string mon_fichier) {
  string tmp;
  bool valid = true;            // valid controle le chargement de l'automate, 
  unsigned int i = 0, k = 0;    // itérateur simple

  // On fait le menage en avance au cas ou on recharge un automate
  ef.clear();
  ei.clear();
  alphabet.clear();
  a_trans.clear();
  Etat.clear();

  ifstream VeriFile;            // sert juste a verifier le formatage du fichier ### a completer 

  VeriFile.open(mon_fichier.c_str());
  if(VeriFile) {

    VeriFile >> tmp;
    if(tmp != "Etat_initiaux") {
      VeriFile.close();
      return false;
    }

    if(valid) {
      valid = false;
      while(!((valid ) || (VeriFile.eof()))) {   // tant qu'on a pas trouver le mot clef ou qu'on est dans le fichier
        VeriFile >> tmp;
        if(tmp == "Etat_finaux") {
          valid = true;
        }
      }
    }
    if(valid) {
      valid = false;
      while(!((valid == true) || (VeriFile.eof()))) {
        VeriFile >> tmp;
        if(tmp == "Alphabet") {
          valid = true;
        }
      }
    }
    if(valid) {
      valid = false;
      while(!((valid == true) || (VeriFile.eof()))) {
        VeriFile >> tmp;
        if(tmp == "Automate") {
          valid = true;
        }
      }
    }
    if(valid) {
      valid = false;
      while(!((valid == true) || (VeriFile.eof()))) {
        VeriFile >> tmp;
        if(tmp == "FIN") {
          valid = true;
        }
      }
    }
    VeriFile.close();
    if(!valid) {
      return false;
    }
  } else {
    cerr << "Erreur d'ouverture !" << endl;
    return false;
  }

  ifstream File;

  File.open(mon_fichier.c_str());

  if(File) {

    // On elimine la première ligne        
    File >> tmp;

    // Recupéreration des états initiaux
    File >> tmp;

    if(tmp == "Etat_finaux") {
      cerr << "Pas d'etat Initial. Choisissez un fichier valide svp" << endl;
      File.close();
      return false;
    }
    while(tmp != "Etat_finaux") {
      ei.push_back(atoi(tmp.c_str()));
      File >> tmp;
    }

    // Récuperation des états finaux
    File >> tmp;
    while(tmp != "Alphabet") {
      ef.push_back(atoi(tmp.c_str()));
      File >> tmp;
    }

    // Récupération de l'alphabet
    File >> tmp;
    while(tmp != "Automate") {
      alphabet.push_back(tmp);
      File >> tmp;
    }

    i = 0;
    k = 0;
    bool find = false, init, fin, lect = false;
    int statetmp;               // stock l'etat sous forme d'entier pour eviter de rappeler atoi en boucle
    string firsttmp;            // garde en mémoire la premiere etape de la transition
    string scdtmp;              // la deuxiemme,

    while(tmp != "FIN") {
      if(tmp == "FIN" || !lect) {
        File >> tmp;
        lect = true;
      }
      // a chaque état rencontrer on verifie qu'il existe, sinon on le creer et on trie le tableau
      if(((i % 3) != 1)) {      // tout les cas sauf l'alphabet de transition 

        find = false;
        statetmp = atoi(tmp.c_str());

        if(Etat.size() != 0) {  // condition ne servant probablement a rien dans la version actuel du code
          for(k = 0; k < Etat.size(); k++) {
            if(Etat[k].returnState() == statetmp) {     // si l'etat existe
              find = true;
            }
          }
        }
        if(Etat.size() == 0 || find == false) { // si l'etat existait pas.

          // rechercher ses attribus init / final 
          init = fin = false;
          for(k = 0; k < ei.size() && !init; k++) {
            if(ei[k] == statetmp) {
              init = true;
            }
          }
          for(k = 0; k < ef.size() && !fin; k++) {
            if(ef[k] == statetmp) {
              fin = true;
            }
          }
          // creation de l'etat
          Etat.push_back(State(statetmp, init, fin));

        }
      }

      if((i % 3) == 0) {        // départ de la transition
        firsttmp = tmp;
      }

      find = false;
      if((i % 3) == 1) {        // alphabet utilise 
        for(k = 0; k < alphabet.size(); k++) {
          if(alphabet[k] == tmp) {      // si la lettre est dans l'alphabet
            find = true;
          }
        }
        // si l'a lettre n'a pas été trouvé
        if(!find) {
          cerr <<
              " La lettre de transition n'a pas été trouver dans l'alphabet"
              << endl;
          File.close();
          return false;
        }
        scdtmp = tmp;
      }
      if((i % 3) == 2) {        // arrivé 

        // on rajoute la transition dans l'automate et l'etat
        a_trans.push_back(transition
                          (atoi(firsttmp.c_str()), scdtmp, atoi(tmp.c_str())));

        for(k = 0; k < Etat.size(); k++) {
          if(Etat[k].returnState() == atoi(firsttmp.c_str())) {
            Etat[k].s_trans.push_back(transition
                                      (atoi(firsttmp.c_str()), scdtmp,
                                       atoi(tmp.c_str())));
            // initialisation de la structure transition au seins du vector de transition de la classe Etat
          }
        }
      }
      File >> tmp;
      i++;
    }

    File.close();       // Toutes bonne chose à une fin

  } else {
    cerr << "Erreur à l'ouverture !" << endl;
    return false;
  }

  // on trie pour que l'affichage soit plus plus beau.     
  sort(Etat.begin(), Etat.end(), vectorSort);

  if(Etat.size() == 1) {
    Etat[0].changeState(1);
  }
  return true;  // si tout a été chargé normalement
}

void Automate::isAFS() {
  bool valid = true;
  unsigned int i;

  /*
     Si il y a plus d'un etat initial : non standard
     Sinon Si un des etat initiaux est la cible d'une transition : non standar
   */

  if(ei.size() > 1) {
    valid = false;
  } else {
    for(i = 0; i < a_trans.size() && valid; i++) {
      if(ei[0] == a_trans[i].end) {
        valid = false;
      }
    }
  }
  if(Etat.size() == 1) {
    valid = true;
  }


  if(valid) {
    cout << endl << " L'automate est standars" << endl;
  } else {
    cout << endl << " Automate non-standard : Standardisation de l'automate" <<
        endl << endl;

    State tmpState(0, true, false);     // Futur etat initial

    for(i = 0; i < ei.size(); i++) {
      // Si il est initial et final on le rajoute à la liste des état finaux
      for(unsigned k = 0; k < ef.size() && ei[i] == ef[k]; k++) {
        tmpState.changeStateFin(true);
        ef.push_back(0);
      }

      for(unsigned int k = 0; k < Etat.size(); k++) {
        // Si l'etat est initial et que l'on est dans la table de transition.
        // On rajoute la transition dans l'etat temporaire
        for(unsigned int j = 0;
            (j < Etat[k].s_trans.size()) && (Etat[k].returnState() == ei[i]);
            j++) {
          tmpState.s_trans.push_back(Etat[k].s_trans[j]);
        }
        Etat[k].changeStateInit(false); // On enleve tout les etat initiaux de l'automate
      }
    }
    ei.clear();

    // On supprime les potentiels doublons
    for(i = 0; i < tmpState.s_trans.size(); i++) {
      tmpState.s_trans[i].begin = 0;    // On concidère 0 comme initial
      a_trans.push_back(tmpState.s_trans[i]);
    }
    removeTwinTrans(tmpState.s_trans);

    ei.push_back(0);    // Mise a jour de la table des état initiaux

    Etat.push_back(tmpState);

    removeTwinState(Etat);
    sort(Etat.begin(), Etat.end(), vectorSort); // Un peu de rangements ...
  }
}

bool Automate::isAFD() {

  if(ei.size() > 1) {
    return false;       // Si il y a plus d'un etat initial.
  }

  for(unsigned int i = 0; i < Etat.size(); i++) {
    for(unsigned int k = 0; k < Etat[i].s_trans.size(); k++) {
      for(unsigned int j = 0; j < Etat[i].s_trans.size(); j++) {        // j=k a verifier
        if((Etat[i].s_trans[k].alpha == Etat[i].s_trans[j].alpha) && (j != k)) {
          // si il y a deux fois la meme lettre dans une transition d'un etat.
          return false;
        }

      }
    }
  }
  return true;
}

void Automate::AFD() {

  vector < State > vectTmpState;        // contient le futur vector d'etat de l'automate
  State tmpState;               // contient l'etat temporaire a ajouter au tableau d'etat. 

  // Creation du premier Etat de l'automate deterministe
  tmpState.changeState(1);
  tmpState.changeStateInit(true);       // le premier etat est forcement initial

  for(unsigned int i = 0; i < ei.size(); i++) {
    for(unsigned int j = 0; j < Etat.size(); j++) {
      if(ei[i] == Etat[j].returnState()) {
        tmpState.s_etat.push_back(ei[i]);
      }
    }
  }
  for(unsigned int i = 0; i < tmpState.s_etat.size(); i++) {
    for(unsigned int k = 0; k < ef.size() && tmpState.s_etat[i] == ef[k]; k++) {
      tmpState.changeStateFin(true);
    }
  }
  vectTmpState.push_back(State(tmpState));
  reinitState(tmpState);

  unsigned int it = 0;

  while(it < vectTmpState.size()) {     // tant qu'on a pas tester tout les états de vectTmpState

    // recuperation de l'alphabet lu par l'etat. // evite de devoir tester tous les état par la suite
    vector < string > alphatmp;
    for(unsigned int i = 0; i < vectTmpState[it].s_etat.size(); i++) {
      for(unsigned int j = 0; j < Etat.size(); j++) {
        if(vectTmpState[it].s_etat[i] == Etat[j].returnState()) {
          for(unsigned int k = 0; k < Etat[j].s_trans.size(); k++) {
            alphatmp.push_back(Etat[j].s_trans[k].alpha);
          }
        }
      }
    }
    removeTwinVect(alphatmp);   // supprime les doublons

    sort(alphatmp.begin(), alphatmp.end());


    // pour chaque lettre lu part l'etat en cour
    for(unsigned int i = 0; i < alphatmp.size(); i++) {

      // pour chaque etat compris par l'etat en cour
      for(unsigned int j = 0; j < vectTmpState[it].s_etat.size(); j++) {

        // recherche des états
        for(unsigned int k = 0; k < Etat.size(); k++) {
          if(Etat[k].returnState() == vectTmpState[it].s_etat[j]) {
            for(unsigned int m = 0; m < Etat[k].s_trans.size(); m++) {
              if(Etat[k].s_trans[m].alpha == alphatmp[i]) {
                tmpState.s_etat.push_back(Etat[k].s_trans[m].end);

              }
            }
          }

        }       // fin recherche d'etat######### A REVOIR

      } // fin de parcour des états de l'etat en cour
      removeTwinVect(tmpState.s_etat);




      int statefind = 0;        // retourne l'etat trouver

      // rechercher si tmpState , n'existe pas deja
      // Si il existe :
      if(cmpState(tmpState, vectTmpState, statefind)) {
        // on décrémente le compteur en prévision de la fonction reinitialisé.
        tmpState.changeState(tmpState.returnState() - 1);
      } else {  // si il n'existe pas
        // recherche si le futur etat est Final
        for(unsigned int j = 0; j < tmpState.s_etat.size(); j++) {
          for(unsigned int k = 0; k < ef.size(); k++) {
            if(tmpState.s_etat[j] == ef[k]) {
              tmpState.changeStateFin(true);
            }
          }
        }


        // On rajoute l'etat au vecteur d'etat
        vectTmpState.push_back(State(tmpState));
        // on sauvegarde son numero pour ajouter les transitions
        statefind = tmpState.returnState();

      } // Fin si (l'etat existe

      // On met a jour les transitons de it vers le nouvel (ou non) etat
      // numero d'etat contenu dans statefind, soit recuperer, soit incrémenté (jme comprend)
      vectTmpState[it].s_trans.push_back(transition
                                         (vectTmpState[it].returnState(),
                                          alphatmp[i], statefind));
      removeTwinTrans(vectTmpState[it].s_trans);

      // On reinitialise le vecteur temporaire

      reinitState(tmpState);


    }   // fin de lecture alphabet de l'etat en cour
    alphatmp.clear();



    it++;       // tant qu'on a pas atteint la fin du stack d'etat
  }     // fin de traitement des états

  // reconstitution de l'automate
  ei.clear();
  ei.push_back(1);      // le premier etat est forcement initial

  ef.clear();
  a_trans.clear();
  Etat.clear();

  for(unsigned int i = 0; i < vectTmpState.size(); i++) {
    if(vectTmpState[i].returnFin()) {
      ef.push_back(vectTmpState[i].returnState());
    }
    for(unsigned int j = 0; j < vectTmpState[i].s_trans.size(); j++) {
      a_trans.push_back(vectTmpState[i].s_trans[j]);
    }
  }
  Etat = vectTmpState;



  /*
     creer état initial regroupant les état initiaux de l'automate original
     ajouter au vector tmp
     clean et incrimente le compteur de tmpstate

     Tant qu'il reste des état non traité 
     Pour chaque lettre de l'alphabet contenu dans l'etat L
	     Pour chaque etat qu'il contient

	     	On rajoute LES etat trouver au State tmp, en evitant les doublons;

	     Fin pour

	     Si ! l'etat existe deja -- comparaison vector tmpVectState a State tmp   
		     Si le futur etat est initial / final 
		     	- on met a jour le State tmp;
		     Fin Si
		     	- on rajoute l'etat au vecteur d'etat
		     Sinon 
		     	- on décremente le compteur d'etat avant qu'il soit clean
	     Fin si


	     On rajoute la transition de l'etat actuel vers le nouvelle (ou non ) etat : I L X
	     On clean le State tmp ( qui est alors incrémenté ) ;   

     	     Fin pour lettre 

     Fin pour nouvelle etat
     fin boucle si plus de nouvelle etat

     Reconstituer la liste des etat initiaux finaux (par etiquette cette fois ci
     Reconstituer liste des transition total de l'automate. 
     copier le vectortmp sur le vector Etat 
   */
}

bool Automate::isAFDC() {
  // L'automate deterministe est complet si il y a autant de transition que possible 
  // nombre d'etat * taille alphabet = taille table de transition

  cout << endl << " Alphabet : " << alphabet.
      size() << " | Etat : " << Etat.size() << endl;
  cout << " Total : " << a_trans.size() << " sur :  " << alphabet.size() *
      Etat.size() << endl;
  if((alphabet.size() * Etat.size() < a_trans.size())) {
    cerr << " erreur lors de la determinisation " << endl;
    return EXIT_FAILURE;
  }
  if((alphabet.size() * Etat.size() == a_trans.size())) {
    return true;
  } else {
    return false;
  }
}

bool Automate::AFDC(bool Comp) {
  cout << endl;
  int dustFind = 0;
  bool dust = true;

  // Recherche si un etat est deja une poubelle
  for(unsigned int i = 0; i < Etat.size() && dust; i++) {
    dust = true;
    if(Etat[i].s_trans.size() == 0) {
      dustFind = i;     // Si il l'etat n'a pas de transition.
    } else {
      dustFind = i;
      for(unsigned int j = 0; j < Etat[i].s_trans.size() && dustFind; j++) {
        dustFind = i;
        if(Etat[i].s_trans[j].end != Etat[i].returnState()) {
          dustFind = 0; // Si un etat n'a pas de transition autre que sur lui-même.
        }
      }
      if(dustFind) {
        dust = false;
      }
    }
    // Si on en a trouver un, on verifie qu'il n'est pas final
    if(dustFind) {
      for(unsigned int k = 0; k < ef.size(); k++) {
        if(Etat[i].returnState() == ef[k]) {
          dustFind = 0;
          dust = true;
        }
      }
    }
  }

  // creation etat poubelle
  State trash(Etat.size() + 1, false, false);

  if(!dustFind) {       // si on en a pas trouver d'etat implicite
    if(!Comp) { // Si l'automate n'est pas deja complet
      dustFind = Etat.size();
      for(unsigned int i = 0; i < alphabet.size(); i++) {
        // On met a jour les transitions de l'etat poubelle ( de lui-même vers lui-même )
        trash.s_trans.push_back(transition
                                (trash.returnState(), alphabet[i],
                                 trash.returnState()));
      }
      Etat.push_back(State(trash));     // On rajoute l'etat au vecteur d'etat
      for(unsigned int i = 0; i < trash.s_trans.size(); i++) {
        a_trans.push_back(transition(trash.s_trans[i]));        // On met a jour les transitions
      }
    }
  } else {
    trash = Etat[dustFind];     // on récupère l'etat poubelle
    Etat.push_back(State(trash));       // on le rajoute a la fin
    removeTwinState(Etat);      // supprimera la premiere occurence trouver du double

    // On regarde si la transition existe
    for(unsigned int j = 0; j < alphabet.size(); j++) {
      bool Cont = true;

      for(unsigned int i = 0; i < Etat[dustFind].s_trans.size() && Cont; i++) {
        if(Etat[dustFind].s_trans[i].alpha == alphabet[j]) {
          Cont = false;
        }
      }

      // Si il faut on mes à jours les tables de transitions
      if(Cont) {
        Etat[dustFind].s_trans.push_back(transition
                                         (Etat[dustFind].returnState(),
                                          alphabet[j],
                                          Etat[dustFind].returnState()));
        a_trans.push_back(transition
                          (Etat[dustFind].returnState(), alphabet[j],
                           Etat[dustFind].returnState()));
      }

    }

  }


  bool find = false;

  // Completion
  /*
     Pour chaque case de la table de transition
	     Si la transition n'existe pas
	     	On la rajoute au deux vector de transition
	     Fin Si
     Fin Pour table de transition
   */

  for(unsigned int i = 0; i < Etat.size(); i++) {
    for(unsigned int j = 0; j < alphabet.size(); j++) {
      for(unsigned int k = 0; k < Etat[i].s_trans.size(); k++) {
        if(alphabet[j] == Etat[i].s_trans[k].alpha) {
          find = true;
        }
      }
      if(!find) {
        Etat[i].s_trans.push_back(transition
                                  (Etat[i].returnState(), alphabet[j],
                                   Etat[dustFind].returnState()));
        a_trans.push_back(transition
                          (Etat[i].returnState(), alphabet[j],
                           Etat[dustFind].returnState()));
      }
      find = false;
    }
    // On trie la liste des transitions.
    sort(Etat[i].s_trans.begin(), Etat[i].s_trans.end(), transSort);
  }
  cout << endl;
  return !dust; // si on n'a rien fait on l'indique
}

void Automate::AFDCM() {
  cout << endl;

  /*
     ########### Creer les deux première partition Final / Non final. 

     vecteur de vecteur state et tmpstate

     Pour chaque etat i 

     si l'etat est final 
     	state[i][1]=2
     sinon 
     	state[i][1]=1
     fin Si       
     Fin pour etat
   */

  // Initialisation de la premier partition
  vector < vector < int > >state(Etat.size());
  vector < vector < int > >part(2);      // etat des partitions


  /*
     Shema d'une ligne de partition
     numero_d'etat ; numero de partition ; [...] partitition
   */

  for(unsigned int i = 0; i < Etat.size(); i++) {
    state[i].push_back(Etat[i].returnState());

    if(Etat[i].returnFin()) {   // si il est final
      state[i].push_back(1);
      part[1].push_back(Etat[i].returnState());
    } else {
      state[i].push_back(2);
      part[0].push_back(Etat[i].returnState());
    }
  }
  // ####### Fin creation part etat initial/ final

  /*
     ########### Creer la première table de partition des état. // nom_de_merde_style
     ######### Etat et state sont normalement dans le meme ordre
     Pour chaque state/etat i
	     pour chaque transition j // dans l'odre a b c d ... 
		     pour chaque state k ( on peut s'arreter si on trouve la condition)
			     si la destination de la transition est l'etat k
			     	On Tag le fichier dans la table state.
			     fin si
		     fin pour state k
	     fin pour transition
     fin pour etat /state i
   */


  for(unsigned int i = 0; i < Etat.size(); i++) {
    for(unsigned int j = 0; j < Etat[i].s_trans.size(); j++) {
      for(unsigned int k = 0; k < state.size(); k++) {
        if(Etat[i].s_trans[j].end == state[k][0]) {
          state[i].push_back(state[k][1]);
        }
      }
    }
  }
  // ################### Fin de creation première partition

  printMinimal(state);  // affichage de la première table de transitions

  bool find = false, partfind1 = false, partfind2 = false;      // si l'etat est encore valid
  unsigned int taillepart = 0;


  // boucle de minimisation, tant qu'on a de nouveau état, ou qu'on a autant d'etat que de partition.
  while(part.size() > taillepart && part.size() != Etat.size()) {
    cout << "Appuyer sur une touche pour continuer; " << endl;
    getchar();
    taillepart = part.size();   // Sert a savoir si le nombre de partition a changer

    // on efface les partitions pour les recréer après
    part.clear();

    // Comparaison des partitions etat par etat
    for(unsigned int i = 0; i < Etat.size(); i++) {
      for(unsigned int j = 0; j < Etat.size(); j++) {
        find = true;
        for(unsigned int k = 1; k < state[i].size(); k++) {
          if(i != j && i < j && find) { // si on regarde pas le meme etat ou n etat precedant et qu'on doit continuer
            if(state[i][k] != state[j][k] && find) {
              find = false;
            } else {
              find = true;
            }
          } else {      // si i = j ou i > j
            find = false;
          }
        }       // fin de recherche des etat identiques

        // si on a trouver tout les etats de la table actuel || si ils ont la meme partition
        if(find) {
          //  Redéfinition de la table des partitions.
          partfind1 = partfind2 = false;
          unsigned int k = 0;

          for(k = 0; k < part.size() && !(partfind1 || partfind2); k++) {
            if(part[k].size() > 0) {
              for(unsigned int m = 0; m < part[k].size(); m++) {
                if(part[k][m] == state[i][0]) {
                  partfind1 = true;
                }
                if(part[k][m] == state[j][0]) {
                  partfind2 = true;
                }
              }
            }
          }
          k--;  // sorti de boucle k est incrémenté ...
          if(partfind1 || partfind2) {
            if(partfind1 && !partfind2) {
              part[k].push_back(state[j][0]);
            } else if(!partfind1 && partfind2) {
              part[k].push_back(state[i][0]);
            }
          } else {      // les etat n'etait dans aucune partition existante
            // nouvelle ligne dans la table
            part.resize(part.size() + 1);
            part[part.size() - 1].push_back(state[i][0]);
            part[part.size() - 1].push_back(state[j][0]);
          }

        }       // find if


      } // fin comparaison etat
    }   // fin comparaison etat
    // si l'etat n'a aucun equivalent, il est tout seul dans sa partition
    for(unsigned int i = 0; i < state.size(); i++) {    // pour chaque etat
      partfind1 = false;
      for(unsigned int j = 0; j < part.size(); j++) {   // on le cherche dans la table de partition
        for(unsigned int k = 0; k < part[j].size(); k++) {
          if(part[j][k] == state[i][0]) {
            partfind1 = true;
          }
        }
      }
      if(!partfind1) {  // si on l'a pas trouver
        part.resize(part.size() + 1);
        part[part.size() - 1].push_back(state[i][0]);   // on le rajoute
      }
    }

    cout << " Etat des partitions après traitement " << endl;
    for(unsigned int i = 0; i < part.size(); i++) {
      cout << " " << intToRomain(i + 1) << " : ";
      for(unsigned int j = 0; j < part[i].size(); j++) {
        cout << part[i][j] << " ";
      }
      cout << endl;
    }
    cout << endl;
    // ############# Fin de creation de la nouvelle table de partition.


    // on met a jour le statut de state par rapport à la nouvelle table de partition.
    for(unsigned int i = 0; i < part.size(); i++) {
      for(unsigned int j = 0; j < part[i].size(); j++) {
        for(unsigned int k = 0; k < state.size(); k++) {
          if(part[i][j] == state[k][0]) {
            state[k][1] = i + 1;
          }
        }
      }
    }

    // on met a jour les partition proprement dite


    for(unsigned int i = 0; i < Etat.size(); i++) {
      unsigned int alphacount = 2;

      for(unsigned int j = 0; j < Etat[i].s_trans.size(); j++) {
        for(unsigned int k = 0; k < state.size(); k++) {
          if(Etat[i].s_trans[j].end == state[k][0]
             && alphacount <= alphabet.size() + 2) {
            state[i][alphacount] = state[k][1];
            alphacount++;
          }
        }
      }
    }

    printMinimal(state);
  }     // Fin while


  /*
     # Reconsituer l'etat minimal en mémoire
     # effacer l'etat
     # creer les etats correspondant aux partitions
     # mettre a jour les etats correspondant et les transition
     # mettre a jour la table de transition de l'automate
   */

  if(part.size() == Etat.size()) {
    cout << endl << " l'automate etait minimal ..." << endl;
  } else {
    cout << endl << " l'automate a ete minimiser ... " << endl;
  }
  cout << endl;


  // Mise a jour de l'etat
  State tmpState;
  int numState = 0;

  Etat.clear();
  a_trans.clear();
  for(unsigned int i = 0; i < part.size(); i++) {
    // Recherche du numero de la partition associer
    for(unsigned int j = 0; j < state.size(); j++) {
      for(unsigned int k = 0; k < part[i].size(); k++) {
        if(part[i][k] == state[j][0]) {
          numState = state[j][1];
        }
      }

    }
    tmpState.changeState(numState);
    // rechercher liste des etats de l'etat
    for(unsigned int j = 0; j < part[i].size(); j++) {
      tmpState.s_etat.push_back(part[i][j]);

      for(unsigned int k = 0; k < ei.size(); k++) {
        if(ei[k] == part[i][j]) {
          tmpState.changeStateInit(true);
        }
      }
      for(unsigned int k = 0; k < ef.size(); k++) {
        if(ef[k] == part[i][j]) {
          tmpState.changeStateFin(true);
        }
      }
    }
    // remplissage table de transition

    for(unsigned int j = 0; j < state.size(); j++) {
      find = false;
      if(state[j][1] == numState && !find) {    // si on est a l'etat correspondant
        find = true;
        for(unsigned int k = 0; k < alphabet.size(); k++) {
          tmpState.
              s_trans.push_back(transition
                                (numState, alphabet[k], state[j][k + 2]));
          a_trans.push_back(transition(numState, alphabet[k], state[j][k + 2]));
        }
      }
    }
    Etat.push_back(tmpState);
    reinitState(tmpState);
  }

  // On met a jour Etat final / Initial
  ei.clear();
  ef.clear();
  for(unsigned int i = 0; i < Etat.size(); i++) {
    if(Etat[i].returnInit()) {
      ei.push_back(Etat[i].returnState());
    }
    if(Etat[i].returnFin()) {
      ef.push_back(Etat[i].returnState());
    }

  }
}

void Automate::printMinimal(vector < vector < int > >state) {
  // affichage automate. 
  cout << "  E/S   | Etat || Part ||";
  for(unsigned int i = 0; i < alphabet.size(); i++) {
    cout << "  " << alphabet[i] << "  |";
  }

  cout << endl << "-------------------------";
  for(unsigned int j = 0; j < alphabet.size(); j++) {
    cout << "------";
  }
  string tmp;
  bool findInit, findFin;

  cout << endl;
  for(unsigned int i = 0; i < Etat.size(); i++) {
    for(unsigned int j = 0; j < state[i].size(); j++) {
      if(j == 0) {

        findInit = findFin = false;

        for(unsigned int k = 0; k < ei.size(); k++) {
          if(ei[k] == Etat[i].returnState()) {
            findInit = true;
          }
        }

        for(unsigned int k = 0; k < ef.size(); k++) {
          if(ef[k] == Etat[i].returnState()) {
            findFin = true;
          }
        }

        if(findInit) {
          if(findFin) { // initial + final
            cout << "  <-->";
          } else {      // juste initial
            cout << "  --> ";
          }
        } else {
          if(findFin) { // juste final
            cout << "  <-- ";
          } else {      // rien du tout
            cout << "      ";
          }

        }
        cout << "  | ";

        cout << "  " << state[i][j] << "  ||";
      }
      // Affichage des partitions
      if(j == 1) {
        tmp = intToRomain(state[i][j]);
        if(tmp.size() == 1) {
          cout << "   " << tmp << "  ||";
        }
        if(tmp.size() == 2) {
          cout << "  " << tmp << "  ||";
        }
        if(tmp.size() == 3) {
          cout << "  " << tmp << " ||";
        }
        if(tmp.size() == 4) {
          cout << " " << tmp << " ||";
        }
      }
      if(j > 1) {
        tmp = intToRomain(state[i][j]);
        if(tmp.size() == 1) {
          cout << "  " << tmp << "  |";
        }
        if(tmp.size() == 2) {
          cout << "  " << tmp << " |";
        }
        if(tmp.size() == 3) {
          cout << " " << tmp << " |";
        }
        if(tmp.size() == 4) {
          cout << " " << tmp << "|";
        }
      }
    }
    cout << endl << "-------------------------";
    for(unsigned int j = 0; j < alphabet.size(); j++) {
      cout << "------";
    }
    cout << endl;
  }
}

void Automate::printAutomate(int statut) {
//     Affichage de l'automate chargé

  cout << endl << " ###### Affichage de l'automate  : " << statut << " #######"
      << endl << endl;

  // ###################################
  // ######## Table de transition ######
  // ###################################

  bool findInit = false, findFin = false, findAffiche = false;
  unsigned int i = 0;

  if(statut >= 3) {
    cout << "  E/S   |" << "    Etat    |   ";  //<<
  } else {
    cout << "  E/S   |" << "  Etat  |   ";      //<<
  }

  for(i = 0; i < alphabet.size(); i++) {
    cout << alphabet[i] << "   |   ";
  }

  if(statut >= 3) {
    cout << endl << "----------------------";
  } else {
    cout << endl << "------------------";
  }


  for(unsigned int k = 0; k < alphabet.size(); k++) {
    cout << "--------";
  }
  cout << endl;

  for(i = 0; i < Etat.size(); i++) {
    findInit = findFin = false;
    for(unsigned int k = 0; k < ei.size(); k++) {
      if(ei[k] == Etat[i].returnState()) {
        findInit = true;
      }
    }

    for(unsigned int k = 0; k < ef.size(); k++) {
      if(ef[k] == Etat[i].returnState()) {
        findFin = true;
      }
    }

    if(findInit) {
      if(findFin) {     // initial + final
        cout << "  <-->";
      } else {  // juste initial
        cout << "  --> ";
      }
    } else {
      if(findFin) {     // juste final
        cout << "  <-- ";
      } else {  // rien du tout
        cout << "      ";
      }

    }
    cout << "  | ";

    // ############## affichage Etat

    // on tient compte du nombre d'etat (jusqu'a 99) 
    // affichage des numero d'etat

    if(statut >= 3) {
      if(Etat[i].returnState() > 9) {
        cout << "" << Etat[i].returnState() << ": ";
        for(unsigned int j = 0; j < Etat[i].s_etat.size(); j++) {
          cout << Etat[i].s_etat[j] << " ";
        }
        for(unsigned int j = (Etat[i].s_etat.size() * 2); j < 7; j++) {
          cout << " ";
        }
      } else if(statut == 4
                && Etat[i].returnState() ==
                Etat[Etat.size() - 1].returnState()) {
        cout << " " << "  Poub  " << "  |";
      } else {
        cout << "" << Etat[i].returnState() << ": ";
        for(unsigned int j = 0; j < Etat[i].s_etat.size(); j++) {
          cout << Etat[i].s_etat[j] << " ";
        }
        for(unsigned int j = (Etat[i].s_etat.size() * 2); j < 8; j++) {
          cout << " ";
        }
        cout << "|";
      }
    } else {
      if(Etat[i].returnState() > 9) {
        cout << "  " << Etat[i].returnState() << "   |";
      } else if(statut == 4
                && Etat[i].returnState() ==
                Etat[Etat.size() - 1].returnState()) {
        cout << " " << "Poub" << "  |";
      } else {
        cout << "   " << Etat[i].returnState() << "   |";
      }
    }

    vector < int >varAffiche;

    // affichage des transition
    for(unsigned int j = 0; j < alphabet.size(); j++) {
      for(unsigned int k = 0; k < Etat[i].s_trans.size(); k++) {
        if(Etat[i].s_trans[k].alpha == alphabet[j]) {
          findAffiche = true;
          varAffiche.push_back(Etat[i].s_trans[k].end);
        }
      }

      if(findAffiche) {
        // affichage des états poubelle si AFDC
        if(statut == 4 && varAffiche[0] == Etat[Etat.size() - 1].returnState()) {
          cout << " " << "Poub" << "  |";
        } else {
          if(statut == 2) {
            for(unsigned int k = 0; k < varAffiche.size(); k++) {
              if(varAffiche.size() == 1) {
                cout << "   " << varAffiche[k] << "   ";
              } else if(varAffiche.size() == 2) {
                cout << " " << varAffiche[k] << " ";
              } else {  // l'affichage sera un peu déformer
                cout << "" << varAffiche[k] << " ";
              }
            }
            if(varAffiche.size() == 1) {
              cout << "|";
            } else if(varAffiche.size() == 2) {
              cout << " |";
            } else {    // l'affichage sera un peu déformer
              cout << "|";
            }
          } else {
            cout << "   " << varAffiche[0] << "   |";
          }
        }
      } else {
        cout << "       |";
      }
      findAffiche = false;
      varAffiche.clear();

      /*# pour chaque lettre 
		 si la transition lié a la lettre existe
		 	on affiche l'etat final 
		 sinon 
		 	on affiche un blanc
		 fin si
         fin pour 
       */
    }

    if(statut >= 3) {
      cout << endl << "----------------------";
    } else {
      cout << endl << "------------------";
    }
    for(unsigned int k = 0; k < alphabet.size(); k++) {
      cout << "--------";
    }
    cout << endl;
  }

  cout << endl;

}

void Automate::readWord() {

  string word;
  bool empty = false;
  int choice;

  cout << endl << " Que voulez vous faire ? " << endl;
  cout << " 1 : Lire un mot " << endl;
  cout << " 0 : Lire le mot vide " << endl;

  secureImput(choice, 0, 1);
  if(choice) {
    cout << " Veuillez entrée le mot que vous voulez tester " << endl;
    cin >> word;
    cout << " Mot lu : " << word << "." << endl;
  } else {
    empty = true;
  }

  if(empty) {   // pour un mot vide , il faut qu'un initial soit final
    empty = false;
    for(unsigned int i = 0; i < ei.size(); i++) {
      for(unsigned int j = 0; j < ef.size() && !empty; j++) {
        if(ei[i] == ef[j]) {
          empty = true;
        }
      }
    }
    if(empty) {
      cout << endl << "Le mot vide est reconnu" << endl;
    } else {
      cout << "Le mot vide n'est pas reconnu" << endl;
    }

  } else {

    int etatUsed = ei[0];       // on part de l'etat initial
    bool Cont = false;
    string tmp;

    for(unsigned int i = 0; i < word.size() && !Cont; i++) {

      Cont = true;
      for(unsigned int j = 0; j < a_trans.size() && Cont; j++) {
        tmp = word[i];
        if((a_trans[j].begin == etatUsed) && (a_trans[j].alpha == tmp)) {
          etatUsed = a_trans[j].end;
          Cont = false;
        }
      }
      if(Cont) {
        cout << " Aucune transition trouvé a partir de : " << i << " : " <<
            word[i] << endl;
      }
    }

    if(!Cont) { // si on a fini de lire le mot
      Cont = true;
      for(unsigned int i = 0; i < ef.size() && Cont; i++) {
        if(etatUsed == ef[i]) {
          cout << " Le mot est reconnu par l'automate " << endl;
          Cont = false;
        }
      }
      if(Cont) {
        cout << " Le mot n'est pas reconnu par l'automate " << endl;
      }
    }


    /*


       etatused=ei[o]
       pour chaque caractère i && !continue
	       continue = true
	       pour chaque transition k de a_trans && continue
		       si a_trans[k].init == etatused
			       si a_trans[k].alpha = carac[i]
				       etatused=a_trans[k].end
				       continue=false
			       fin si
		       fin si
	       fin pour transition
       fin pour caractère

       si continue
       		aucune transition trouver
       fin si
       pour chaque etat final 
	       si etatused est final
	       		le mot est reconnu
	       sinon 
	       	l	e mot est trop court
	       fin si
       fin pour chaque etat
     */
    cout << endl;
  }

}
