with Ada.Text_Io; use Ada.Text_Io;
with Contact_Cle; use Contact_Cle;
with Arbre_Bin_Recherche_Cle_G;
with Liste_Ordonnee_Cle_G;
with Ada.IO_Exceptions;
with Ada.Calendar; use Ada.Calendar; 
with Ada.Command_Line; use Ada.Command_Line;


procedure Gerer_Annuaire_Inverse is
   
   -------------------------------------------------------------------------
   -- Parametre du programme
   --
   -- Attention avec une valeur à TRUE le chargement de document volumineux 
   -- est beaucoup plus long.
   
   ANALYSE_AVEC_LISTE : Boolean := TRUE; 
   
   -------------------------------------------------------------------------
   
   
   
   -- Instanciation des paquetages
   package Arbre_Contacts is new Arbre_Bin_Recherche_Cle_G(Un_Contact, Cle_contact, Cle, "<", "=", Liberer_Contact, Contact_To_string);
   use Arbre_Contacts;
   
   package Liste_Contacts is new Liste_Ordonnee_Cle_G(Un_Contact, Cle_contact, Cle, "<", "=", Liberer_Contact, Contact_To_string);
   use Liste_Contacts;
   
   procedure Att_Liste is begin
      New_Line;
      Put_Line("Attention l'utilisation de listes est ACTIVEE et non nécessaire !"); 
      Put_Line("L'option peut être désactivé à la compilation ou en passant le ");
      Put_Line("parametre -a à l'execution.");
      New_Line;
      Put_Line("L'argument -p peut être spécifié pour lancer des tests de performance.");
      New_Line;
   end Att_Liste;
   
   Invalid_Argument : exception;
   
   -- Variables pour la lecture du fichier annuaire
   Fichier : File_Type;
   Chaine, Ligne : String(1..80);
   Len, last : Integer := 0;
   AB : Arbre;
   C : Un_Contact;
   Tel : String(1..10);
   Auto : Boolean := False;
   Prenom, Nom, Ville, Specia, Telephone, Fin, I, compteur : Integer := 0;
   
   -- Variables liées aux listes
   L : Une_Liste_Ordonnee;
   AnL : Boolean := ANALYSE_AVEC_LISTE;
   Performance : Boolean := False;
   
   -- Varaibles temps
   T1, T2 , TA , TB: Time;
   
begin
   Put_Line("Programme d'annuaire inversé - Version ABR");
   
   -- Analyse des arguments (s'il y en a)
   if Argument_Count = 1 and then Argument(1) = "-a"  then AnL := FALSE; end if;
   if Argument_Count = 1 and then Argument(1) = "-p"  then Performance := TRUE; end if;
   
   if Argument_Count = 2 and then ((Argument(1) = "-a" and Argument(2) = "-p") or ((Argument(1) = "-p" and Argument(2) = "-a"))) then AnL := FALSE; Performance := TRUE; end if;
   
   if Performance and not AnL then raise Invalid_Argument; end if;
   
   
   
   if AnL then Att_Liste; end if;
   
   -- Entourloupe pour avoir un nom de fichier contraint, saisi par l'utilisateur et de bonne taille
   Put_Line("Nom de l'annuaire: ");
   Get_Line(Chaine, Len);
   
   -- (1) Option de test simple: si on laisse le champ vide, l'annuaire "T_10.txt" sera chargé 
   if Len = 0 and not AnL then Len := 12; Auto := True; end if;
   
   -- On récupère le contenu du fichier choisi
   declare
      Nom_Fichier : String(Chaine'First..Len) := Chaine(Chaine'First..Len);
      Cle_Cherche : Cle_Contact;
   begin
      -- (1)
      if Auto then Nom_Fichier := "A_150000.txt"; end if;
      
      -- On ouvre le fichier dans "Fichier"
      open(Fichier, in_File, "./jeux_de_donnees/" & Nom_Fichier);
      Put_Line("Début du chargemnt du fichier...");
      Compteur := 0;
      
      -- Tant qu'on n'a pas atteint la fin du fichier
      while not End_Of_File(Fichier) loop
	 Get_Line (Fichier,  Ligne ,  Len ) ; 
	 
	 -- Variables pour marquer les positions des différents éléments
	 Prenom := 1;
	 Nom := 0;
	 Ville := 0;
	 Specia := 0;
	 Telephone := 0;
	 Fin := 0;
	 I := 1;
	 
	 -- On transforme une chaine de caractère en contact
	 while Telephone = 0 loop
	    if Ligne(I) = ' ' then
	       if Nom = 0 then Nom := I;
	       elsif Ville = 0 then Ville := I;
	       elsif Specia = 0 then Specia := I;
	       elsif Telephone = 0 then Telephone := I; Fin := Telephone + 11; 
	       end if;
	    end if;
	    I := I + 1;
	 end loop;
	 C := Creer_Contact(Ligne(Prenom..Nom-1), Ligne(Nom+1..Ville-1), Ligne(Ville+1..Specia-1), Ligne(Specia+1..Telephone-1), Ligne(Telephone+1..Fin-1));
	 
	 -- On insère le contact créé dans un arbre et / ou une liste
	 Inserer(C, AB);
	 if AnL then Inserer(C, L); end if;  -- Ssi l'option est activée
	 
	 -- Compte du nombre de contacts chargés pour un meilleur suivi
	 Compteur := Compteur + 1;
	 if (Compteur mod 1000) = 0 then
	    Put_Line(Integer'Image(Compteur) & " contacts chargés");
	    if AnL and then Compteur mod 10000 = 0 then Att_Liste; end if;
	 end if;
	 
      end loop;
      Put_Line("Fin du chargement du ficier...");
      Close(Fichier);
      Put_Line("Annuaire en mémoire.");
      New_Line;
      
      
      -- La liste contient l'annuaire donné
      --Put_Line("Liste avec les contacts : ");
      --Put_Line(Liste_To_String(L));
      --New_Line;
      
      if not Performance then
	 loop 
	    -- L'arbre AB contient l'annuaire saisi
	    -- on fait donc la recherche dans cet arbre
	    
	    Put_Line("Veillez saisir un numéro à rechercher: ");
	    Get_Line(Cle_Cherche, Len);
	    
	    -- Recherche dans l'arbre
	    Put_Line("Recherche de " & Cle_Cherche & " dans l'arbre");
	    T1 := Clock;
	    C := Rechercher_Par_Cle(Cle_cherche, AB);
	    T2 := Clock;
	    Put_Line("Entrée trouvée : " & Contact_To_String(C));
	    Put_Line("La recherche a durée : " & Duration'Image(T2 - T1));
	    New_Line;
	    
	    -- Recherche dans la liste
	    if AnL then
	       Put_Line("Recherche dans la liste : ");
	       T1 := Clock;
	       C := Rechercher_Par_Cle(Cle_cherche, L);
	       T2 := Clock;
	       Put_Line("Entrée trouvée : " & Contact_To_String(C));
	       Put_Line("La recherche a durée : " & Duration'Image(T2 - T1));
	    end if;
	    
	    New_Line;
	 end loop;
      end if;            
      
      
      -----------------------------------------------------------------------------------
      
      -- Tests de performance
      New_Line;
      Put_Line("Test de performance des différentes structures : ");
      
      if not AnL then raise Invalid_Argument; end if;
      
      Put_Line("On recherche tout les éléments présent dans chaque structure.");
      open(Fichier, in_File, "./jeux_de_donnees/performance/" & Nom_Fichier & ".perf");
      
      Put_Line("Recherche dans l'arbre : ");
      TA := Clock;
      while not End_Of_File(Fichier) loop
	 Tel := Get_Line(Fichier)(1..10);
	 Put("Arbre : Recherche de " & Tel & "... ");
	 C := Rechercher_Par_Cle(Tel, AB);
	 Put_Line("Trouvé !");
      end loop;
      TB := Clock;
      
      Put_Line("La recherche de l'ensemble des éléments dans un arbre a durée : " & Duration'Image(TB - TA));
      New_Line;
      
      Reset(Fichier);
      
      Put_Line("Recherche dans la liste : ");
      T1 := Clock;
      while not End_Of_File(Fichier) loop
	 Tel := Get_Line(Fichier)(1..10);
	 Put("Liste : Recherche de " & Tel & "... ");
	 C := Rechercher_Par_Cle(Tel, L);
	 Put_Line("Trouvé !");
      end loop;
      T2 := Clock;

      Put_Line("La recherche de l'ensemble des éléments dans une liste a durée : " & Duration'Image(T2 - T1));
      New_Line;
      
      Put_Line("Résultats :");
      Put_Line("Arbre : " & Duration'Image(TB - TA));
      Put_Line("Liste : " & Duration'Image(T2 - T1));
      
      New_Line;
      Put_Line("...fini.");
      
      
      -----------------------------------------------------------------------------------
      
   exception
      when Invalid_Argument => Put_Line("L'argument -a a été spécifié, les tests de performnces ne peuvent pas avoir lieu."); raise PROGRAM_ERROR;
      when Arbre_Contacts.Element_Non_Present => Put_Line("Equivalence numéro introuvable.");
      when ADA.IO_EXCEPTIONS.NAME_ERROR => Put_Line("Fichier invalide.");
   end;
end Gerer_Annuaire_Inverse;
