with Ada.Command_Line; use Ada.Command_Line;
with Ada.Text_IO;      use Ada.Text_IO;
with GNAT.OS_Lib;      use GNAT.OS_Lib;

with Projects.Registry;    use Projects, Projects.Registry;
with Src_Info;             use Src_Info;
with Src_Info.Queries;     use Src_Info.Queries;

with Test_Utils;           use Test_Utils;
with Language_Handlers;    use Language_Handlers;
with Traces;               use Traces;

procedure Read_Scope_Tree is

   procedure Help;

   ----------
   -- Help --
   ----------

   procedure Help is
   begin
      Put_Line ("Invalid number of arguments.");
      Put_Line
        ("Usage: " & Command_Name & " project_file source_filename"
         & " [entity_name entity_line entity_column]");
   end Help;

   Me : Debug_Handle := Create ("T");

   Prj_Filename     : String_Access;
   Source_Filename  : String_Access;
   Project          : Project_Type;
   Registry         : aliased Project_Registry;
   Source_Info_List : Src_Info.LI_File_List;
   LI_Unit          : LI_File_Ptr;
   Tree             : Scope_Tree;
   Entity_Name      : String_Access;
   Line, Column     : Natural := 0;
   Entity           : Entity_Information;
   Status           : Find_Decl_Or_Body_Query_Status;
   Node             : Scope_Tree_Node;
   Handler          : Language_Handler;

begin
   Handler := Create_Lang_Handler (Registry'Unrestricted_Access);

   --  ??? We should enhance this test driver in the future in order
   --      to be able to test cases where the parser should fail.
   --      One way to do this is use command-line options, which will
   --      specify that a failure is expected, and even maybe an exception
   --      (with the exception name).

   if Argument_Count < 2 then
      Help;
      return;
   end if;

   Prj_Filename := new String'(Argument (1));
   if not Is_Regular_File (Prj_Filename.all) then
      Put_Line ("No such file: '" & Prj_Filename.all & "'");
      return;
   end if;

   Source_Filename := new String'(Argument (2));
   if not Is_Regular_File (Source_Filename.all) then
      Put_Line ("No such file: '" & Source_Filename.all & "'");
      return;
   end if;

   if Argument_Count >= 3 then
      Entity_Name := new String'(Argument (3));

      if Argument_Count >= 4 then
         Line := Natural'Value (Argument (4));
      end if;

      if Argument_Count >= 5 then
         Column := Natural'Value (Argument (5));
      end if;
   end if;

   Reset (Source_Info_List);
   Load_Project (Prj_Filename.all, Handler, Registry, Project);
   Load_LI_File
     (Source_Info_List, Handler, Registry, Source_Filename.all, LI_Unit);

   if LI_Unit /= No_LI_File then
      if Entity_Name = null then
         Tree := Create_Tree (LI_Unit);
         Trace_Dump (Me, Tree, Subprograms_Pkg_Only => False);

      else
         Put_Line ("Entity: " & Entity_Name.all);
         Find_Declaration
           (Lib_Info           => LI_Unit,
            File_Name          => Source_Filename.all,
            Entity_Name        => Entity_Name.all,
            Line               => Line,
            Column             => Column,
            Entity             => Entity,
            Status             => Status);

         if Status = Src_Info.Queries.Overloaded_Entity_Found then
            Put_Line ("Entity " & Entity_Name.all & " is overloaded.");

         elsif Status /= Src_Info.Queries.Success then
            Put_Line ("Declaration not found for " & Entity_Name.all);

         else
            --  Load the LI file that will contain the scope for the entity
            Load_LI_File (Source_Info_List, Handler, Registry,
                          Get_Declaration_File_Of (Entity), LI_Unit);
            Tree := Create_Tree (LI_Unit);

            Node := Find_Entity_Scope (Tree, Entity);

            if Node /= Null_Scope_Tree_Node then
               Trace_Dump (Me, Tree, Node, Subprograms_Pkg_Only => False);
            else
               Put_Line ("No such entity: " & Entity_Name.all
                         & Get_Declaration_Line_Of (Entity)'Img
                         & Get_Declaration_Column_Of (Entity)'Img);
            end if;
         end if;
      end if;
   else
      Put_Line ("LI file not found for " & Source_Filename.all);
   end if;

exception
   when others =>
      null;
end Read_Scope_Tree;
