with GNAT.Strings;
with GNATCOLL.Projects;          use GNATCOLL.Projects;
with GNATCOLL.VFS;               use GNATCOLL.VFS;
with GNATCOLL.Traces;            use GNATCOLL.Traces;
with GNATCOLL.VFS_Utils;         use GNATCOLL.VFS_Utils;

with Ada.Containers.Indefinite_Ordered_Sets;
with Ada.Containers.Indefinite_Vectors;

with Ada.Text_IO;

with GNAT.OS_Lib;             use GNAT.OS_Lib;
with Ada.Characters.Handling; use Ada.Characters.Handling;

procedure Main is
   Env                 : Project_Environment_Access;
   Source_Project_Tree : GNATCOLL.Projects.Project_Tree;

   P : Project_Type;

   package String_Set is new Ada.Containers.Indefinite_Ordered_Sets (String);
   use String_Set;

   Paths         : String_Set.Set;

   procedure Has_Elem (Paths : String_Set.Set; Elem : String; Msg : String);
   procedure Has_Elem (Paths : String_Set.Set; Elem : String; Msg : String) is
   begin
      if Paths.Find (Elem) = String_Set.No_Element then
         Ada.Text_IO.Put_Line (Elem & Msg);
      end if;
   end Has_Elem;

   procedure Check_Info
     (File_Name    : String;
      Info_Elem    : File_Info;
      Project_Name : String;
      Unit_Part    : Unit_Parts;
      Unit_Name    : String;
      Language     : String);
   procedure Check_Info
     (File_Name    : String;
      Info_Elem    : File_Info;
      Project_Name : String;
      Unit_Part    : Unit_Parts;
      Unit_Name    : String;
      Language     : String) is
   begin
      if To_Lower (Info_Elem.Project.Name) /= To_Lower (Project_Name) then
         Ada.Text_IO.Put_Line
           ("wrong project for " & File_Name
            & ": " & To_Lower (Info_Elem.Project.Name)
            & " instead of " & To_Lower (Project_Name));
      end if;
      if Info_Elem.Language /= Language then
         Ada.Text_IO.Put_Line
           ("wrong language for " & File_Name
            & ": " & Info_Elem.Language & " instead of " & Language);
      end if;
      if Info_Elem.Unit_Part /= Unit_Part then
         Ada.Text_IO.Put_Line
           ("wrong unit part for " & File_Name
            & ": " & Unit_Parts'Image (Info_Elem.Unit_Part) &
              " instead of "  & Unit_Parts'Image (Unit_Part));
      end if;
      if Info_Elem.Unit_Name /= Unit_Name then
         Ada.Text_IO.Put_Line
           ("wrong unit name for " & File_Name
            & ": " & Info_Elem.Unit_Name & " instead of " & Unit_Name);
      end if;
   end Check_Info;


   Cur_Dir : constant Virtual_File := Get_Current_Dir;

   Str : String_Access;
begin
   Parse_Config_File;
   Set_Active (Create ("Projects.Aggregate"), True);
--     Set_Active (Create ("Projects"), True);
   Initialize (Env);
   Env.Register_Default_Language_Extension ("C", ".h", ".c");
   Env.Set_Path_From_Gnatls ("gnatls", Str);
   Free (Str);
   Source_Project_Tree.Load (GNATCOLL.VFS.Create (+"aggr.gpr"), Env);

   if Source_Project_Tree.Root_Project = No_Project then
      Ada.Text_IO.Put_Line ("project not loaded");
   end if;

   declare

      Source_Name_1 : constant String :=
        "src_a" & Directory_Separator & "a1.adb";
      --  Not ambiguous base name.

      Source_Name_2 : constant String :=
        "src_a" & Directory_Separator & "c1.ads";
      --  Ambiguous base name.

      Source_Name_3 : constant String :=
        "c2" & Directory_Separator & "src_c2"
        & Directory_Separator & "shared_src.ads";
      --  Belongs to several projects.

      Source_Name_4 : constant String :=
        "c2" & Directory_Separator & "src_c"
        & Directory_Separator & "foo.c";
      --  C file with ambigous base name.

      Files : constant File_Array := Env.Predefined_Source_Files;
      --  Predefined files.

      File : Virtual_File;

      use File_Info_Sets;

      Infoset   : File_Info_Set;
      Info_Elem : File_Info;

   begin

      for I in Files'Range loop

         if
           Integer (Info_Set (Source_Project_Tree, Files (I)).Length) > 1
         then
            Ada.Text_IO.Put_Line
              ("multiple info for predefinded file "
               & Files (I).Display_Full_Name);
         else
            Info_Elem := Info_Set
              (Source_Project_Tree, Files (I)).First_Element.all;

            if Info_Elem.Project.Name /= "default" then
               Ada.Text_IO.Put_Line
                 ("predefined "
                  & Files (I).Display_Full_Name
                  & " belongs to "
                  & Info_Elem.Project.Name);
            end if;

            if
              Info_Elem.Language = "c"
            then
               if Info_Elem.Unit_Part /= Unit_Separate then
                  Ada.Text_IO.Put_Line
                    ("wrong unit part for predefined "
                     & Files(I).Display_Full_Name);
               end if;
            else
               if Info_Elem.Unit_Part = Unit_Separate then
                  Ada.Text_IO.Put_Line
                    ("wrong unit part for predefined "
                     & Files (I).Display_Full_Name);
               end if;
            end if;
         end if;

      end loop;

      File := Create
        (Source_Project_Tree, Files (Files'First).Base_Name);
      Info_Elem := Info_Set (Source_Project_Tree, File).First_Element.all;

      Infoset := Info_Set
        (Source_Project_Tree, Create (Normalize_Pathname (+Source_Name_1)));
      if Integer (Infoset.Length) /= 1 then
         Ada.Text_IO.Put_Line
           ("multiple info for " & Source_Name_1);
      else
         Info_Elem := Infoset.First_Element.all;

         Check_Info
           (Source_Name_1,
            Info_Elem,
            "a",
            Unit_Body,
            "a1",
            "ada");
      end if;

      Infoset := Info_Set
        (Source_Project_Tree, Create (Normalize_Pathname (+Source_Name_2)));
      if Integer (Infoset.Length) /= 1 then
         Ada.Text_IO.Put_Line
           ("multiple info for " & Source_Name_2);
      else
         Info_Elem := Infoset.First_Element.all;

         Check_Info
           (Source_Name_2,
            Info_Elem,
            "a",
            Unit_Spec,
            "c1",
            "ada");
      end if;

      Infoset := Info_Set
        (Source_Project_Tree, Create (Normalize_Pathname (+Source_Name_3)));
      if Integer (Infoset.Length) /= 2 then
         Ada.Text_IO.Put_Line
           ("wrong number of info for " & Source_Name_3);
      else
         Info_Elem := Infoset.First_Element.all;

         Check_Info
           (Source_Name_3,
            Info_Elem,
            "c",
            Unit_Spec,
            "shared_src",
            "ada");

         Paths.Include
           (+Relative_Path (Info_Elem.Project.Project_Path, Cur_Dir));

         Info_Elem := Infoset.Last_Element.all;

         Check_Info
           (Source_Name_3,
            Info_Elem,
            "c",
            Unit_Spec,
            "shared_src",
            "ada");

         Paths.Include
           (+Relative_Path (Info_Elem.Project.Project_Path, Cur_Dir));

         Has_Elem
           (Paths,
            "c1" & Directory_Separator & "c.gpr",
            " missed in info for shared_src.ads");
         Has_Elem
           (Paths,
            "c2" & Directory_Separator & "c.gpr",
            " missed in info for shared_src.ads");

         Paths.Clear;
      end if;

      Infoset := Info_Set
        (Source_Project_Tree, Create (Normalize_Pathname (+Source_Name_4)));
      if Integer (Infoset.Length) /= 1 then
         Ada.Text_IO.Put_Line
           ("multiple info for " & Source_Name_4);
      else
         Info_Elem := Infoset.First_Element.all;

         Check_Info
           (Source_Name_4,
            Info_Elem,
            "c",
            Unit_Body,
            "",
            "c");
      end if;

   end;

   Source_Project_Tree.Unload;
   Free (Env);
end Main;
