-------------------------------------------------------------------------------
-- (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.
--
--=============================================================================

--------------------------------------------------------------------------------
--Synopsis:                                                                   --
--                                                                            --
--Produce the banner(s) to display on the screen and in the report file       --
--------------------------------------------------------------------------------

with CommandLine;
with E_Strings;
with Version;

package body Banner is
   LenDateTime : constant Integer := 23;
   subtype TypDateTimeRange is Integer range 1 .. LenDateTime;
   subtype TypDateTime is String (TypDateTimeRange);

   type Justification is (Left, Middle, Right);

   -- Creates a banner line with the given text and justification.
   function CreateBannerLine
     (FromText          : in String;
      WithJustification : in Justification;
      FillChar          : in Character)
     return              TypBannerLine
   is
      TheLine    : TypBannerLine := TypBannerLine'(TypBannerLine'First .. TypBannerLine'Last => ' ');
      StartingAt : Positive;

      -- Copies the Source into the Dest starting at the given location in Dest
      -- Characters will be lost if Dest is not big enough.
      procedure Insert (Source     : in     String;
                        Dest       : in out TypBannerLine;
                        StartingAt : in     Positive)
      --# derives Dest from *,
      --#                   Source,
      --#                   StartingAt;
      is
      begin
         for I in Natural range 1 .. Source'Length loop
            exit when I + (StartingAt - 1) > Dest'Length;
            --# assert I <= TypBannerRange'Last
            --#   and StartingAt <= Dest'Length
            --#   and I + (StartingAt - 1) <= Dest'Length;
            Dest (I + (StartingAt - 1))   := Source (I);
         end loop;
      end Insert;

   begin

      -- Fill the line up with fill characters.
      for I in Natural range 1 .. TheLine'Length loop
         TheLine (I) := FillChar;
      end loop;

      case WithJustification is
         when Left =>

            StartingAt := 1;

         when Middle =>

            if TheLine'Length - FromText'Length <= 1 then
               StartingAt := 1;
            else
               StartingAt := (TheLine'Length - FromText'Length) / 2;
            end if;

         when Right =>

            if TheLine'Length - FromText'Length <= 0 then
               StartingAt := 1;
            else
               StartingAt := (TheLine'Length - FromText'Length) + 1;
            end if;

      end case;

      Insert (Source     => FromText,
              Dest       => TheLine,
              StartingAt => StartingAt);

      return TheLine;
   end CreateBannerLine;

   function MinorSeparatorLine return TypBannerLine is
   begin
      return CreateBannerLine ("-", Left, '-');
   end MinorSeparatorLine;

   function MajorSeparatorLine return TypBannerLine is
   begin
      return CreateBannerLine ("=", Left, '=');
   end MajorSeparatorLine;

   function EndOfReportMarker return TypBannerLine is
      subtype MyStringIndex is Positive range 1 .. 34;
      subtype MyString is String (MyStringIndex);
      Text : constant MyString := " End of Semantic Analysis Summary ";
   begin
      return CreateBannerLine (Text, Middle, '=');
   end EndOfReportMarker;

   function NameOfReport return TypBannerLine is
      subtype MyStringIndex is Positive range 1 .. 25;
      subtype MyString is String (MyStringIndex);
      Text : constant MyString := "Semantic Analysis Summary";
   begin
      return CreateBannerLine (Text, Middle, ' ');
   end NameOfReport;

   function Copyright (J : in Justification) return TypBannerLine
   --# global in CommandLine.Data;
      is separate;

   function Get_Version (J : in Justification) return TypBannerLine
   --# global in CommandLine.Data;
      is separate;

   procedure DateTime (DateString : out TypDateTime)
   --# derives DateString from ;
      is separate;

   ----------------------------------------------------------------------
   -- this procedure prints the top 5 banner lines to the output
   procedure TopBanner (File : in SPARK_IO.File_Type)
   --# global in     CommandLine.Data;
   --#        in out SPARK_IO.File_Sys;
   --# derives SPARK_IO.File_Sys from *,
   --#                                CommandLine.Data,
   --#                                File;
   is
   begin
      SPARK_IO.Put_Line (File, MinorSeparatorLine, 0);
      SPARK_IO.Put_Line (File, NameOfReport, 0);
      SPARK_IO.Put_Line (File, Get_Version (Middle), 0);
      SPARK_IO.Put_Line (File, Copyright (Middle), 0);
      SPARK_IO.Put_Line (File, MinorSeparatorLine, 0);
      SPARK_IO.New_Line (File, 1);
   end TopBanner;

   procedure ReportVersion is
   begin
      SPARK_IO.Put_Line (SPARK_IO.Standard_Output, Get_Version (Left), 0);
      SPARK_IO.Put_Line (SPARK_IO.Standard_Output, Copyright (Left), 0);
   end ReportVersion;

   -------------------------------------------------------------------------
   procedure FinishReport (File : in SPARK_IO.File_Type) is
   begin
      SPARK_IO.Put_Line (File, EndOfReportMarker, 0);
   end FinishReport;

   --------------------------------------------------------------------------
   procedure Screen is
   begin
      TopBanner (SPARK_IO.Standard_Output);
   end Screen;

   --------------------------------------------------------------------------
   procedure Report (File : in SPARK_IO.File_Type) is

      DateAndTime : TypDateTime;

      ------------------------------------------------------------------------
      procedure OutputAnalysisType (File : in SPARK_IO.File_Type)
      --# global in     CommandLine.Data;
      --#        in out SPARK_IO.File_Sys;
      --# derives SPARK_IO.File_Sys from *,
      --#                                CommandLine.Data,
      --#                                File;
      is
      begin
         if CommandLine.Data.AnalyseVCs then
            SPARK_IO.Put_Line (File, "Verification Condition files (.vcg)", 0);
            SPARK_IO.Put_Line (File, "Simplified Verification Condition files (.siv)", 0);
            SPARK_IO.Put_Line (File, "Victor result files (.vct)", 0);
            SPARK_IO.Put_Line (File, "Riposte result files (.rsm)", 0);
         end if;
         if CommandLine.Data.AnalysePFs then
            SPARK_IO.Put_Line (File, "Path Function files (.pfs)", 0);
            SPARK_IO.Put_Line (File, "Simplified Path Function files (.sip)", 0);
         end if;
         if CommandLine.Data.AnalyseProofLog then
            SPARK_IO.Put_Line (File, "Proof Logs (.plg)", 0);
         end if;

         SPARK_IO.Put_Line (File, "Dead Path Conjecture files (.dpc)", 0);
         SPARK_IO.Put_Line (File, "Summary Dead Path files (.sdp)", 0);

         if not CommandLine.Data.ShortSummary then
            SPARK_IO.New_Line (File, 1);
            SPARK_IO.Put_Line (File, """status"" column keys:", 0);
            SPARK_IO.Put_Line (File, "    1st character:", 0);
            SPARK_IO.Put_Line (File, "        '-' - No VC", 0);
            SPARK_IO.Put_Line (File, "        'S' - No SIV", 0);
            SPARK_IO.Put_Line (File, "        'U' - Undischarged", 0);
            SPARK_IO.Put_Line (File, "        'E' - Proved by Examiner", 0);
            SPARK_IO.Put_Line (File, "        'I' - Proved by Simplifier by Inference", 0);
            SPARK_IO.Put_Line (File, "        'X' - Proved by Simplifier by Contradiction", 0);
            SPARK_IO.Put_Line (File, "        'P' - Proved by Simplifier using User Defined Proof Rules", 0);
            SPARK_IO.Put_Line (File, "        'V' - Proved by Victor", 0);
            SPARK_IO.Put_Line (File, "        'O' - Proved by Riposte", 0);
            SPARK_IO.Put_Line (File, "        'C' - Proved by Checker", 0);
            SPARK_IO.Put_Line (File, "        'R' - Proved by Review", 0);
            SPARK_IO.Put_Line (File, "        'F' - VC is False", 0);

            SPARK_IO.Put_Line (File, "    2nd character:", 0);
            SPARK_IO.Put_Line (File, "        '-' - No DPC", 0);
            SPARK_IO.Put_Line (File, "        'S' - No SDP", 0);
            SPARK_IO.Put_Line (File, "        'U' - Unchecked", 0);
            SPARK_IO.Put_Line (File, "        'D' - Dead path", 0);
            SPARK_IO.Put_Line (File, "        'L' - Live path", 0);
         end if;
      end OutputAnalysisType;
      --------------------------------------------------------------------------
   begin -- Report

      TopBanner (File);

      -- extra lines to state what type of analysis we're doing,
      -- the starting directory, and the date of generation

      SPARK_IO.Put_Line (File, "Summary of:", 0);
      SPARK_IO.New_Line (File, 1);

      OutputAnalysisType (File);

      SPARK_IO.New_Line (File, 1);
      SPARK_IO.Put_Line (File, "in the directory:", 0);

      if CommandLine.Data.PlainOutput then
         SPARK_IO.New_Line (File, 1);
      else
         E_Strings.Put_Line (File  => File,
                             E_Str => CommandLine.Data.StartDirectory);
      end if;

      SPARK_IO.New_Line (File, 1);

      SPARK_IO.Put_String (File, "Summary produced: ", 0);

      if CommandLine.Data.PlainOutput then
         SPARK_IO.New_Line (File, 1);
      else
         DateTime (DateAndTime);
         SPARK_IO.Put_Line (File, DateAndTime, 0);
      end if;

      SPARK_IO.New_Line (File, 1);

      if CommandLine.Data.IgnoreDates then
         SPARK_IO.Put_Line (File, "Ignore Dates option selected.", 0);
         SPARK_IO.New_Line (File, 1);
      end if;
   end Report;

end Banner;
