-------------------------------------------------------------------------------
-- (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)
procedure AppendErrors (Report  : in SPARK_IO.File_Type;
                        Purpose : in Error_Types.ConversionRequestSource) is
   Err_Count       : Natural;
   OK              : Boolean;
   Next_Error      : Error_Types.StringError;
   Num_Err         : Error_Types.NumericError;
   Success         : SPARK_IO.File_Status;
   Temp_Error_File : Error_IO.File_Type;
   Accumulator     : ErrorAccumulator.T := ErrorAccumulator.Clear;

   procedure Put_Source_Line (To_File : in SPARK_IO.File_Type;
                              Line_No : in LexTokenManager.Line_Numbers)
   --# global in     CommandLineData.Content;
   --#        in out Error_Context_Rec;
   --#        in out SPARK_IO.File_Sys;
   --# derives Error_Context_Rec from *,
   --#                                Line_No,
   --#                                SPARK_IO.File_Sys &
   --#         SPARK_IO.File_Sys from *,
   --#                                CommandLineData.Content,
   --#                                Error_Context_Rec,
   --#                                Line_No,
   --#                                To_File;
   --  pre     Error_Context_Rec.LineNo /= Line_No;
   --  post    Error_Context_Rec.LineNo =  Line_No;
   is
   begin
      loop
         GetFileLine;
         exit when Error_Context_Rec.Line_No >= Line_No;
      end loop;
      if not CommandLineData.Content.XML then
         Print_Source_Line (To_File => To_File);
      end if;
   end Put_Source_Line;

   procedure Get_Error_Set (Error_Set  :    out Error_Sets;
                            Next_Error : in out Error_Types.StringError;
                            OK         :    out Boolean)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     Error_Context_Rec;
   --#        in     LexTokenManager.State;
   --#        in     Purpose;
   --#        in out Conversions.State;
   --#        in out Err_Count;
   --#        in out SPARK_IO.File_Sys;
   --# derives Conversions.State,
   --#         Next_Error,
   --#         OK,
   --#         SPARK_IO.File_Sys from CommandLineData.Content,
   --#                                Conversions.State,
   --#                                Dictionary.Dict,
   --#                                Error_Context_Rec,
   --#                                LexTokenManager.State,
   --#                                Purpose,
   --#                                SPARK_IO.File_Sys &
   --#         Error_Set,
   --#         Err_Count         from CommandLineData.Content,
   --#                                Conversions.State,
   --#                                Dictionary.Dict,
   --#                                Error_Context_Rec,
   --#                                Err_Count,
   --#                                LexTokenManager.State,
   --#                                Next_Error,
   --#                                Purpose,
   --#                                SPARK_IO.File_Sys;
   --  post    not OK or
   --          Error_Context_Rec.LineNo /= Next_Error.Position.StartLineNo or
   --          Errors.Length = ExaminerConstants.MaxErrorSetSize;
   is
      L_OK    : Boolean;
      Errors  : Error_Sets;
      Num_Err : Error_Types.NumericError;
   begin
      Errors := Empty_Error_Set;
      loop
         Errors.Length                        := Errors.Length + 1;
         Errors.Content (Errors.Length).Error := Next_Error;
         if ErrorAccumulator.Is_Error_Continuation (The_Error => Next_Error) then
            Errors.Content (Errors.Length).Err_Num := 0;
         else
            Err_Count                              := Err_Count + 1;
            Errors.Content (Errors.Length).Err_Num := Err_Count;
         end if;
         loop
            Error_IO.Get_Numeric_Error (Error_Context_Rec.Errs, Num_Err);
            Conversions.ToString (Num_Err, Purpose, Next_Error);
            L_OK := (Next_Error /= Error_Types.Empty_StringError);

            exit when not L_OK;
            exit when Next_Error.ErrorType /= Error_Types.NoErr;
         end loop;
         exit when not L_OK;
         exit when Error_Context_Rec.Line_No /= Next_Error.Position.Start_Line_No;
         exit when Errors.Length = ExaminerConstants.MaxErrorSetSize;
      end loop;

      OK        := L_OK;
      Error_Set := Errors;
   end Get_Error_Set;

   procedure Process_Error_Set (Listing    : in     SPARK_IO.File_Type;
                                Next_Error : in out Error_Types.StringError;
                                OK         :    out Boolean)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     Error_Context_Rec;
   --#        in     LexTokenManager.State;
   --#        in     Purpose;
   --#        in out Accumulator;
   --#        in out Conversions.State;
   --#        in out Err_Count;
   --#        in out SPARK_IO.File_Sys;
   --#        in out XMLReport.State;
   --# derives Accumulator,
   --#         XMLReport.State   from *,
   --#                                Accumulator,
   --#                                CommandLineData.Content,
   --#                                Conversions.State,
   --#                                Dictionary.Dict,
   --#                                Error_Context_Rec,
   --#                                Err_Count,
   --#                                LexTokenManager.State,
   --#                                Next_Error,
   --#                                Purpose,
   --#                                SPARK_IO.File_Sys &
   --#         Conversions.State,
   --#         Next_Error,
   --#         OK                from CommandLineData.Content,
   --#                                Conversions.State,
   --#                                Dictionary.Dict,
   --#                                Error_Context_Rec,
   --#                                LexTokenManager.State,
   --#                                Purpose,
   --#                                SPARK_IO.File_Sys &
   --#         Err_Count         from *,
   --#                                CommandLineData.Content,
   --#                                Conversions.State,
   --#                                Dictionary.Dict,
   --#                                Error_Context_Rec,
   --#                                LexTokenManager.State,
   --#                                Next_Error,
   --#                                Purpose,
   --#                                SPARK_IO.File_Sys &
   --#         SPARK_IO.File_Sys from *,
   --#                                Accumulator,
   --#                                CommandLineData.Content,
   --#                                Conversions.State,
   --#                                Dictionary.Dict,
   --#                                Error_Context_Rec,
   --#                                Err_Count,
   --#                                LexTokenManager.State,
   --#                                Listing,
   --#                                Next_Error,
   --#                                Purpose,
   --#                                XMLReport.State;
   is
      Error_Set : Error_Sets;
   begin
      Get_Error_Set (Error_Set  => Error_Set,
                     Next_Error => Next_Error,
                     OK         => OK);
      if not CommandLineData.Content.XML then
         Put_Error_Pointers (Listing => Listing,
                             Errors  => Error_Set);
         Put_Error_Messages (Listing     => Listing,
                             Errors      => Error_Set,
                             Start_Pos   => 29,
                             Accumulator => Accumulator);
      else
         Put_Error_Messages_XML (Listing     => Listing,
                                 Errors      => Error_Set,
                                 Start_Pos   => 29,
                                 Accumulator => Accumulator);
      end if;

   end Process_Error_Set;

   procedure Process_Errors_On_Line
     (Listing    : in     SPARK_IO.File_Type;
      Next_Error : in out Error_Types.StringError;
      OK         :    out Boolean)
   --# global in     CommandLineData.Content;
   --#        in     Dictionary.Dict;
   --#        in     Error_Context_Rec;
   --#        in     LexTokenManager.State;
   --#        in     Purpose;
   --#        in out Accumulator;
   --#        in out Conversions.State;
   --#        in out Err_Count;
   --#        in out SPARK_IO.File_Sys;
   --#        in out XMLReport.State;
   --# derives Accumulator,
   --#         Conversions.State,
   --#         Err_Count,
   --#         Next_Error,
   --#         OK,
   --#         SPARK_IO.File_Sys,
   --#         XMLReport.State   from Accumulator,
   --#                                CommandLineData.Content,
   --#                                Conversions.State,
   --#                                Dictionary.Dict,
   --#                                Error_Context_Rec,
   --#                                Err_Count,
   --#                                LexTokenManager.State,
   --#                                Listing,
   --#                                Next_Error,
   --#                                Purpose,
   --#                                SPARK_IO.File_Sys,
   --#                                XMLReport.State;
   is
      L_OK                   : Boolean;
      Accumulator_Was_Active : Boolean;
   begin
      if not Error_Has_Position_Inline (Err_Type => Next_Error.ErrorType) and then not CommandLineData.Content.XML then
         SPARK_IO.New_Line (Listing, 1);
      end if;
      loop
         Process_Error_Set (Listing    => Listing,
                            Next_Error => Next_Error,
                            OK         => L_OK);
         exit when not L_OK;
         exit when Error_Context_Rec.Line_No /= Next_Error.Position.Start_Line_No;
      end loop;
      OK                     := L_OK;
      Accumulator_Was_Active := ErrorAccumulator.Is_Active (This => Accumulator);
      ErrorAccumulator.Flush (Accumulator, Listing);
      if Accumulator_Was_Active then
         if CommandLineData.Content.XML then
            XMLReport.End_Message (Report => Listing);
         else
            New_Line (Listing, 1);
         end if;
      end if;
   end Process_Errors_On_Line;

   procedure Set_Up_Files (OK : out Boolean)
   --# global in out Error_Context_Rec;
   --#        in out SPARK_IO.File_Sys;
   --#           out Err_Count;
   --# derives Error_Context_Rec,
   --#         SPARK_IO.File_Sys from *,
   --#                                Error_Context_Rec &
   --#         Err_Count         from  &
   --#         OK                from Error_Context_Rec,
   --#                                SPARK_IO.File_Sys;
   is
      L_OK        : Boolean;
      Success     : SPARK_IO.File_Status;
      Source_File : SPARK_IO.File_Type;
      Error_File  : Error_IO.File_Type;
   begin
      Source_File := Error_Context_Rec.Source;
      SPARK_IO.Reset (Source_File, SPARK_IO.In_File, Success);
      Error_Context_Rec.Source  := Source_File;
      L_OK                      := Success = SPARK_IO.Ok;
      Error_Context_Rec.Line_No := 0;
      Err_Count                 := 0;
      Error_File                := Error_Context_Rec.Errs;
      Error_IO.Reset (Error_File, SPARK_IO.In_File, Success);
      Error_Context_Rec.Errs := Error_File;
      OK                     := L_OK and Success = SPARK_IO.Ok;
   end Set_Up_Files;

   procedure Put_Error_Count (File : in SPARK_IO.File_Type;
                              Cnt  : in Natural)
   --# global in out SPARK_IO.File_Sys;
   --# derives SPARK_IO.File_Sys from *,
   --#                                Cnt,
   --#                                File;
   is
   begin
      SPARK_IO.Put_Integer (File, Cnt, 0, 10);
      SPARK_IO.Put_Line (File, " error(s) or warning(s)", 0);
      SPARK_IO.New_Line (File, 1);
   end Put_Error_Count;

begin
   if Error_Context_Rec.Num_Errs = 0 then
      if not CommandLineData.Content.XML then
         SPARK_IO.Put_Line (Report, "No errors found", 0);
         SPARK_IO.New_Line (Report, 1);
      end if;
   else
      Error_Context_Rec.Current_Line := E_Strings.Empty_String;
      if not CommandLineData.Content.XML then
         Put_Error_Count (File => Report,
                          Cnt  => Integer (Error_Context_Rec.Num_Errs));
      end if;
      Set_Up_Files (OK => OK);
      if OK then
         if not CommandLineData.Content.XML then
            SPARK_IO.Put_Line (Report, "Line", 0);
         end if;
         loop
            Error_IO.Get_Numeric_Error (Error_Context_Rec.Errs, Num_Err);
            Conversions.ToString (Num_Err, Purpose, Next_Error);
            OK := (Next_Error /= Error_Types.Empty_StringError);

            exit when not OK;
            exit when Next_Error.ErrorType /= Error_Types.NoErr;
         end loop;
         --    assert Error_Context_Rec.Line_No = 0 and
         --         OK -> Next_Error.Position.StartLineNo >= 1;
         loop
            exit when not OK;
            --  assert Error_Context_Rec.Line_No /= Next_Error.Position.StartLineNo;
            Put_Source_Line (To_File => Report,
                             Line_No => Next_Error.Position.Start_Line_No);
            --  assert Error_Context_Rec.Line_No = Next_Error.Position.StartLineNo;
            Process_Errors_On_Line (Listing    => Report,
                                    Next_Error => Next_Error,
                                    OK         => OK);
            --  assert OK -> Error_Context_Rec.Line_No /= Next_Error.Position.StartLineNo;
            --# accept Flow, 41, "Expected stable expression";
            if not CommandLineData.Content.XML then
               --# end accept;
               SPARK_IO.New_Line (Report, 1);
            end if;
         end loop;
      else
         SPARK_IO.Put_Line (Report, "***      Bad error list, unable to report errors", 0);
         SPARK_IO.New_Line (Report, 1);
      end if;
   end if;

   if CommandLineData.Content.XML then
      Justifications.Print_Justifications_XML (Which_Table => Error_Context_Rec.Justifications_Data_Table,
                                               File        => Report);
   else
      Justifications.Print_Justifications (Which_Table => Error_Context_Rec.Justifications_Data_Table,
                                           File        => Report);
   end if;

   WarningStatus.Report_Suppressed_Warnings (To_File => Report,
                                             Counter => Error_Context_Rec.Counter);

   Temp_Error_File := Error_Context_Rec.Errs;
   --# accept Flow, 10, Success, "Expected ineffective assignment to Success";
   Error_IO.Close (Temp_Error_File, Success);
   --# end accept;
   Error_Context_Rec.Errs := Temp_Error_File;
   --# accept Flow, 33, Success, "Expected Success to be neither referenced nor exported";
end AppendErrors;
