-------------------------------------------------------------------------------
-- (C) Altran Praxis Limited
-------------------------------------------------------------------------------
--
-- The SPARK toolset 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 3, or (at your option) any later
-- version. The SPARK toolset 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 the SPARK toolset; see file
-- COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy of
-- the license.
--
--=============================================================================

separate (ErrorHandler)
package body ErrorAccumulator is

   -----------------------------------------------------------------------------

   function Is_Active (This : T) return Boolean is
   begin
      return This.Active;
   end Is_Active;

   function Is_Error_Continuation (The_Error : Error_Types.StringError) return Boolean is
   begin
      return ((The_Error.ErrorType = Error_Types.CondlDependencyErr
                 and then The_Error.MessageId = ErrorHandler.Dependency_Err_Number (ErrorHandler.May_Be_Used_Continue))
              or else (The_Error.ErrorType = Error_Types.UncondDependencyErr
                         and then The_Error.MessageId = ErrorHandler.Dependency_Err_Number (ErrorHandler.Not_Used_Continue)));
   end Is_Error_Continuation;

   function Is_Error_Start (The_Error : Error_Types.StringError) return Boolean is
   begin
      return ((The_Error.ErrorType = Error_Types.CondlDependencyErr
                 and then The_Error.MessageId = ErrorHandler.Dependency_Err_Number (ErrorHandler.May_Be_Used_New))
              or else (The_Error.ErrorType = Error_Types.UncondDependencyErr
                         and then The_Error.MessageId = ErrorHandler.Dependency_Err_Number (ErrorHandler.Not_Used_New)));
   end Is_Error_Start;

   procedure Start_Msg
     (This         :    out T;
      Start_Error  : in     ErrorHandler.Error_Struct;
      Start_Indent : in     Natural;
      Explanation  : in     E_Strings.T;
      Line_Length  : in     Natural;
      Indent       : in     Natural)
   is
   begin
      This :=
        T'
        (Active       => True,
         Start_Error  => Start_Error,
         Start_Indent => Start_Indent,
         Explanation  => Explanation,
         Line_Length  => Line_Length,
         Indent       => Indent);

   end Start_Msg;

   procedure Flush (This    : in out T;
                    Listing : in     SPARK_IO.File_Type) is
      Unused_New_Start : Natural;
   begin
      if This.Active then
         if not E_Strings.Is_Empty (E_Str => This.Explanation) then
            --# accept F, 10, Unused_New_Start, "Expected ineffective assignment";
            ErrorHandler.PrintLine
              (Listing      => Listing,
               Start_Pos    => This.Start_Indent,
               End_Pos      => This.Line_Length,
               Indent       => This.Indent,
               Line         => This.Explanation,
               Add_New_Line => False,
               New_Start    => Unused_New_Start);
            --# end accept;
         end if;
         SPARK_IO.Put_String (File => Listing,
                              Item => ".",
                              Stop => 1);
         This.Active := False;
      end if;
      --# accept Flow, 33, Unused_New_Start, "Expected to be neither referenced nor exported";
   end Flush;

   procedure Add
     (This            : in out T;
      Error           : in     ErrorHandler.Error_Struct;
      End_Pos, Indent : in     Natural;
      Listing         : in     SPARK_IO.File_Type)
   is

      New_Start : Natural;

      function Need_To_Add return Boolean
      --# global in Error;
      --#        in This;
      is
      begin
         return (This.Start_Error.Error.MessageId = ErrorHandler.Dependency_Err_Number (ErrorHandler.May_Be_Used_New) and
                   Error.Error.ErrorType = Error_Types.CondlDependencyErr and
                   Error.Error.MessageId = ErrorHandler.Dependency_Err_Number (ErrorHandler.May_Be_Used_Continue))
           or else (This.Start_Error.Error.MessageId = ErrorHandler.Dependency_Err_Number (ErrorHandler.Not_Used_New) and
                      Error.Error.ErrorType = Error_Types.UncondDependencyErr and
                      Error.Error.MessageId = ErrorHandler.Dependency_Err_Number (ErrorHandler.Not_Used_Continue));
      end Need_To_Add;

   begin
      if This.Active then
         if Need_To_Add then

            ErrorHandler.PrintLine
              (Listing      => Listing,
               Start_Pos    => This.Start_Indent,
               End_Pos      => End_Pos,
               Indent       => Indent,
               Line         => Error.Error.Message,
               Add_New_Line => False,
               New_Start    => New_Start);
            This.Start_Indent := New_Start;

         elsif Is_Error_Continuation (The_Error => Error.Error) then

            SystemErrors.Fatal_Error (Sys_Err => SystemErrors.Other_Internal_Error,
                                      Msg     => "in ErrorHandler.ErrorAccumulator.Add");
         else
            Flush (This    => This,
                   Listing => Listing);

         end if;
      end if;

   end Add;

end ErrorAccumulator;
