--
--  Copyright (C) 2024, AdaCore
--
--  SPDX-License-Identifier: Apache-2.0 WITH LLVM-Exception
--

with GPR2.Build.Artifacts.Files;
with GPR2.Build.Source;
with GPR2.Path_Name.Set;
with GPR2.Project.Registry.Attribute;
with GPR2.Project.Attribute_Index;

private with GPR2.View_Ids;

package GPR2.Build.Actions.Compile is

   type Compile_Id (<>) is new Actions.Action_Id with private;

   function Create
     (Main_Src : Simple_Name;
      Lang     : Language_Id;
      View     : GPR2.Project.View.Object) return Compile_Id;

   overriding function Image (Self : Compile_Id) return String;

   overriding function Db_Filename (Self : Compile_Id) return Simple_Name;

   overriding function "<" (L, R : Compile_Id) return Boolean;

   type Object is new Actions.Object with private;
   --  Action responsible for building Ada sources

   overriding function UID (Self : Object) return Actions.Action_Id'Class;

   procedure Initialize (Self : in out Object; Src : GPR2.Build.Source.Object);

   overriding function View (Self : Object) return GPR2.Project.View.Object;

   function Input (Self : Object) return GPR2.Build.Source.Object;

   function Object_File (Self : Object) return Artifacts.Files.Object;

   overriding procedure On_Tree_Insertion
     (Self     : Object;
      Db       : in out GPR2.Build.Tree_Db.Object;
      Messages : in out GPR2.Log.Object);

   overriding procedure Compute_Signature (Self : in out Object);

   overriding procedure Compute_Command
     (Self : in out Object;
      Args : out GNATCOLL.OS.Process.Argument_List;
      Env  : out GNATCOLL.OS.Process.Environment_Dict);

   overriding function Skip (Self : Object) return Boolean;

   overriding function Working_Directory
     (Self : Object) return Path_Name.Object;

private

   use type GPR2.View_Ids.View_Id;
   package PRA renames GPR2.Project.Registry.Attribute;
   package PAI renames GPR2.Project.Attribute_Index;

   type Compile_Id (Name_Len : Natural) is new Actions.Action_Id with record
      Lang     : Language_Id;
      Ctxt     : GPR2.Project.View.Object;
      Src_Name : Simple_Name (1 .. Name_Len);
   end record;

   function Create
     (Main_Src : Simple_Name;
      Lang     : Language_Id;
      View     : GPR2.Project.View.Object) return Compile_Id
   is (Name_Len => Main_Src'Length,
       Lang     => Lang,
       Ctxt     => View,
       Src_Name => Main_Src);

   overriding function Image (Self : Compile_Id) return String is
     ("[Compile " & Image (Self.Lang) & "] " & String (Self.Src_Name) &
        " (" & String (Self.Ctxt.Path_Name.Simple_Name) & ")");

   overriding function Db_Filename (Self : Compile_Id) return Simple_Name is
     (Simple_Name ("compile_" & To_Lower (Self.Src_Name)
      & ".json"));

   overriding function "<" (L, R : Compile_Id) return Boolean is
     (if L.Ctxt.Id = R.Ctxt.Id
      then L.Src_Name < R.Src_Name
      else L.Ctxt.Id < R.Ctxt.Id);

   type Object is new Actions.Object with record
      Obj_File : Artifacts.Files.Object;
      --  Compiled object file, can be undefined if not compiled yet

      Dep_File : Artifacts.Files.Object;
      --  Dependency information generated by the compiler

      Deps     : GPR2.Path_Name.Set.Object;
      --  List of known dependencies for this unit

      Lang     : GPR2.Language_Id;
      --  Language of the source

      Src_Name : GPR2.Path_Name.Object;
      --  Source name

      Ctxt     : GPR2.Project.View.Object;
      --  View owning the source
   end record;

   function Src_Index (Self : Object) return Unit_Index is
     (No_Index);
   --  Need that for indexed sources, for now only Ada multi-unit sources

   function Dependency_File (Self : Object) return Simple_Name is
      (Self.Src_Name.Base_Filename & ".dep");

   overriding function View (Self : Object) return GPR2.Project.View.Object is
     (Self.Ctxt);

   function Input (Self : Object) return GPR2.Build.Source.Object is
     (Self.Ctxt.Source (Self.Src_Name.Simple_Name));

   function Object_File (Self : Object) return Artifacts.Files.Object is
     (Self.Obj_File);

   overriding function Working_Directory
     (Self : Object) return Path_Name.Object is
     (Self.Ctxt.Object_Directory);

   overriding function Skip (Self : Object) return Boolean is
     (Self.View.Is_Externally_Built
      or else not Self.View.Attribute
        (PRA.Compiler.Driver, PAI.Create (Self.Lang)).Is_Defined
      or else Self.View.Attribute
        (PRA.Compiler.Driver, PAI.Create (Self.Lang)).Value.Text'Length = 0);

   function Lookup
     (V          : GPR2.Project.View.Object;
      BN         : Simple_Name;
      In_Lib_Dir : Boolean;
      Must_Exist : Boolean)
      return GPR2.Path_Name.Object;
   --  Look for BN in V's hierarchy of object directories

end GPR2.Build.Actions.Compile;
