----------------------------------------------------------------------
--  Rules.Use_Clauses - Package body                                --
--                                                                  --
--  This software  is (c) The European Organisation  for the Safety --
--  of Air  Navigation (EUROCONTROL) and Adalog  2004-2005. The Ada --
--  Controller  is  free software;  you can redistribute  it and/or --
--  modify  it under  terms of  the GNU  General Public  License as --
--  published by the Free Software Foundation; either version 2, or --
--  (at your  option) any later version.  This  unit is distributed --
--  in the hope  that it will be useful,  but WITHOUT ANY WARRANTY; --
--  without even the implied warranty of MERCHANTABILITY or FITNESS --
--  FOR A  PARTICULAR PURPOSE.  See the GNU  General Public License --
--  for more details.   You should have received a  copy of the GNU --
--  General Public License distributed  with this program; see file --
--  COPYING.   If not, write  to the  Free Software  Foundation, 59 --
--  Temple Place - Suite 330, Boston, MA 02111-1307, USA.           --
--                                                                  --
--  As  a special  exception, if  other files  instantiate generics --
--  from the units  of this program, or if you  link this unit with --
--  other files  to produce  an executable, this  unit does  not by --
--  itself cause the resulting executable  to be covered by the GNU --
--  General  Public  License.   This  exception  does  not  however --
--  invalidate any  other reasons why the executable  file might be --
--  covered by the GNU Public License.                              --
--                                                                  --
--  This  software is  distributed  in  the hope  that  it will  be --
--  useful,  but WITHOUT  ANY  WARRANTY; without  even the  implied --
--  warranty  of  MERCHANTABILITY   or  FITNESS  FOR  A  PARTICULAR --
--  PURPOSE.                                                        --
----------------------------------------------------------------------

-- ASIS
with
  Asis.Clauses;

-- Ada
with
  Ada.Strings.Wide_Unbounded;

-- Adalog
with
  Thick_Queries,
  Utilities;

-- Adactl
with
  Framework.Language,
  Framework.Rules_Manager,
  Framework.Reports;

package body Rules.Use_Clauses is
   use Framework;

   type Usage is array (Rule_Types) of Boolean;

   Rule_Used : Usage := (others => False);
   Save_Used : Usage;
   Labels    : array (Rule_Types) of Ada.Strings.Wide_Unbounded.Unbounded_Wide_String;

   type Usage_Type is array (Rule_Types) of Boolean;
   type Package_Context is new Rule_Context with
      record
         Allowed : Usage_Type;
      end record;

   Allowed_Packages : Context_Store;

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

   procedure Help is
      use Utilities;
   begin
      User_Message ("Rule: " & Rule_Id);
      User_Message ("Parameter(s): Allowed package names");
      User_Message ("Control occurrences of use clauses that mention");
      User_Message ("any package but the ones passed as parameters (if any)");
   end Help;

   -------------
   -- Add_Use --
   -------------

   procedure Add_Use (Label         : in Wide_String;
                      Use_Rule_Type : in Rule_Types) is
      use Ada.Strings.Wide_Unbounded;
      use Framework.Language;

   begin
      if Rule_Used (Use_Rule_Type) then
         Parameter_Error (Rule_Id &
                            ": this rule can be specified only once for check " &
                            "and once for search");
      end if;
      Labels    (Use_Rule_Type) := To_Unbounded_Wide_String (Label);
      Rule_Used (Use_Rule_Type) := True;

      while Parameter_Exists loop
         declare
            Entity : constant Entity_Specification := Get_Entity_Parameter;
            Value  : Package_Context := (Allowed => (others => False));
         begin
            Value.Allowed (Use_Rule_Type) := True;
            Associate (Allowed_Packages, Entity, Value);
         exception
            when Already_In_Store =>
               Value := Package_Context (Association (Allowed_Packages, Entity));
               Value.Allowed (Use_Rule_Type) := True;
               Update (Allowed_Packages, Value);
         end;
      end loop;
   end Add_Use;

   -------------
   -- Command --
   -------------

   procedure Command (Action : Framework.Rules_Manager.Rule_Action) is
      use Ada.Strings.Wide_Unbounded, Framework.Rules_Manager;
   begin
      case Action is
         when Clear =>
            Rule_Used := (others => False);
            Labels    := (others => Null_Unbounded_Wide_String);
            Clear (Allowed_Packages);
         when Suspend =>
            Save_Used := Rule_Used;
            Rule_Used := (others => False);
         when Resume =>
            Rule_Used := Save_Used;
      end case;
   end Command;

   -------------
   -- Prepare --
   -------------

   procedure Prepare is
   begin
      Balance (Allowed_Packages);
   end Prepare;

   -------------------------------
   -- Process_Use_Clause --
   -------------------------------

   procedure Process_Use_Clause (Clause : in Asis.Clause) is
      use Ada.Strings.Wide_Unbounded, Asis.Clauses, Thick_Queries;
      use Framework, Framework.Reports;

   begin
      if Rule_Used = (Rule_Used'Range => False) Then
         return;
      end if;
      Rules_Manager.Enter (Rule_Id);

      declare
         Names : constant Asis.Name_List := Clause_Names (Clause);
      begin
         for N in Names'Range loop
            declare
               Context : Rule_Context'Class := Matching_Context (Allowed_Packages, Names (N));
            begin
               for R in Rule_Types loop
                  if Rule_Used (R) and then
                    (Context = No_Matching_Context or else
                     not Package_Context (Context).Allowed (R))
                  then
                     Report (Rule_Id,
                             To_Wide_String (Labels (R)),
                             R,
                             Get_Location (Clause),
                             "use clause for """ & Extended_Name_Image (Names (N)) & '"');
                     exit;
                  end if;
               end loop;
            end;
         end loop;
      end;
   end Process_Use_Clause;

begin
   Framework.Rules_Manager.Register (Rule_Id,
                                     Help    => Help'Access,
                                     Add_Use => Add_Use'Access,
                                     Command => Command'Access,
                                     Prepare => Prepare'Access);
end Rules.Use_Clauses;
