-------------------------------------------------------------------------------
-- (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 EchoErrorEntry (Echo_File : in SPARK_IO.File_Type;
                          Error     : in Error_Types.StringError) is

   subtype Big_String_I is Positive range 1 .. 1024;
   subtype Big_String is String (Big_String_I);

   Source_File_Name : Big_String;
   Source_File_Stop : Natural;
   Source_Filename  : E_Strings.T;
   Err_Struct       : Error_Struct;
   New_Start        : Natural;
   Was_Active       : Boolean;
   Line_Length      : Natural;
   New_Line_Count   : Natural;
   Local_Error      : Error_Types.StringError;
   Explanation      : E_Strings.T;

   procedure Echo_Source_Line (Echo_File   : in SPARK_IO.File_Type;
                               Err_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 *,
   --#                                Err_Line_No,
   --#                                SPARK_IO.File_Sys &
   --#         SPARK_IO.File_Sys from *,
   --#                                CommandLineData.Content,
   --#                                Echo_File,
   --#                                Error_Context_Rec,
   --#                                Err_Line_No;
   is
      Source_File : SPARK_IO.File_Type;
      Success     : SPARK_IO.File_Status;
   begin
      if Error_Context_Rec.Line_No > Err_Line_No then
         Error_Context_Rec.Line_No      := 0;
         Error_Context_Rec.Current_Line := E_Strings.Empty_String;
         Source_File                    := Error_Context_Rec.Source;
         --# accept Flow, 10, Success, "Expected ineffective assignment to Success";
         SPARK_IO.Reset (Source_File, SPARK_IO.In_File, Success);
         --# end accept;
         Error_Context_Rec.Source := Source_File;
      end if;
      if Err_Line_No > 0 and then Error_Context_Rec.Line_No < Err_Line_No - 1 then
         SPARK_IO.Skip_Line (Error_Context_Rec.Source, Integer ((Err_Line_No - Error_Context_Rec.Line_No) - 1));
      end if;
      GetFileLine;
      Error_Context_Rec.Line_No := Err_Line_No;
      New_Line (Echo_File, 1);
      Print_Source_Line (To_File => Echo_File);
      --# accept Flow, 33, Success, "Expected Success to be neither referenced nor exported";
   end Echo_Source_Line;

   procedure Put_Error_Pointer (Echo_File : in SPARK_IO.File_Type;
                                Err_Pos   : in Natural)
   --# global in     Error_Context_Rec;
   --#        in out SPARK_IO.File_Sys;
   --# derives SPARK_IO.File_Sys from *,
   --#                                Echo_File,
   --#                                Error_Context_Rec,
   --#                                Err_Pos;
   is
   begin
      Move_To_Indent
        (Source_File => Echo_File,
         Line        => Error_Context_Rec.Current_Line,
         Indent      => Source_Line_Indent,
         Position    => Err_Pos - 1);
      Put_Char (Echo_File, '^');
      New_Line (SPARK_IO.Standard_Output, 1);
   end Put_Error_Pointer;

   function Need_Source_Line (Error : Error_Types.StringError) return Boolean
   --# global in Error_Context_Rec;
   is
   begin
      return Error.Position.Start_Line_No /= Error_Context_Rec.Line_No and Error.ErrorType /= Error_Types.NoErr;
   end Need_Source_Line;

begin
   if Error_Context_Rec.Echo then
      if CommandLineData.Content.Brief then
         Line_Length    := 0;
         New_Line_Count := 1;
      else
         Line_Length    := Error_Line_Length;
         New_Line_Count := 1;
      end if;

      Err_Struct := Error_Struct'(Err_Num => 0,
                                  Error   => Error);

      Was_Active := ErrorAccumulator.Is_Active (This => Echo_Accumulator);
      if ErrorAccumulator.Is_Active (This => Echo_Accumulator) then
         ErrorAccumulator.Add (Echo_Accumulator, Err_Struct, Line_Length, 11, Echo_File);
      end if;

      --# assert True;

      if not ErrorAccumulator.Is_Active (This => Echo_Accumulator) then

         if Was_Active then
            New_Line (Echo_File, New_Line_Count);
         end if;

         if CommandLineData.Content.Brief then
            SPARK_IO.Name (Error_Context_Rec.Source, Source_File_Name, Source_File_Stop);
            Source_Filename := E_Strings.Section (E_Strings.Copy_String (Str => Source_File_Name), 1, Source_File_Stop);
            case CommandLineData.Content.Brief_Option is
               when CommandLineData.No_Path =>
                  E_Strings.Put_String (File  => Echo_File,
                                        E_Str => FileSystem.Base_Name (Path   => Source_Filename,
                                                                       Suffix => ""));
               when CommandLineData.Full_Path =>
                  E_Strings.Put_String (File  => Echo_File,
                                        E_Str => Source_Filename);
            end case;

            Put_Char (Echo_File, ':');
            Put_Integer (Echo_File, Integer (Error.Position.Start_Line_No), 0, 10);
            Put_Char (Echo_File, ':');
            Put_Integer (Echo_File, Error.Position.Start_Pos, 0, 10);
            Put_Char (Echo_File, ':');
            Put_Char (Echo_File, ' ');
            Output_Brief_Error_Marker (File       => Echo_File,
                                       Err_Type   => Error.ErrorType,
                                       Message_Id => Error.MessageId);

         else
            if Need_Source_Line (Error => Error) then
               Echo_Source_Line (Echo_File   => Echo_File,
                                 Err_Line_No => Error.Position.Start_Line_No);
            end if;
            if Error_Has_Position_Inline (Err_Type => Error.ErrorType) then
               Put_Error_Pointer (Echo_File => Echo_File,
                                  Err_Pos   => Error.Position.Start_Pos);
            else
               New_Line (Echo_File, 1);
            end if;
            Output_Error_Marker (File       => Echo_File,
                                 Err_Type   => Error.ErrorType,
                                 Message_Id => Error.MessageId,
                                 Err_Count  => 0);

         end if;

         if ErrorAccumulator.Is_Error_Start (The_Error => Error) then
            -- extract explanation  from message here and pass it into ErrorAccumulator for later Flush --PNA
            Local_Error := Error;
            Split_String_At_Explanation (E_Str       => Local_Error.Message,
                                         Explanation => Explanation);

            PrintLine (Echo_File, 31, Line_Length, 11, Local_Error.Message, False, New_Start);

            ErrorAccumulator.Start_Msg
              (This         => Echo_Accumulator,
               Start_Error  => Err_Struct,
               Start_Indent => New_Start,
               Explanation  => Explanation,
               Line_Length  => Line_Length,
               Indent       => 11);  -- in rather than recalculate them in error accumulator
         else
            -- leave message text unchanged and display it
            --# accept Flow, 10, New_Start, "Expected ineffective assignment to New_Start";
            PrintLine (Echo_File, 31, Line_Length, 11, -- Expect ineff assignment to New_Start
                       Error.Message, False, New_Start);
            --# end accept;
            New_Line (Echo_File, New_Line_Count);
         end if;
      end if;

   end if;

end EchoErrorEntry;
