-------------------------------------------------------------------------------
-- (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:                                                                    --
--                                                                             --
--Top level package for the summary tool                                       --
--The main program is simply a call to the procedure Main_Procedure wrapped in --
--an execption handler to deal with the exceptions raised by FatalErrors       --
--                                                                             --
---------------------------------------------------------------------------------
with Banner;
with CommandLine;
with E_Strings;
with FatalErrors;
with FileDetails;
with FileHeap;
with FindFiles;
with Heap;
with SPARK_IO;
with Total;
with VCHeap;
with VCS;

use type FileDetails.FileTypes;
use type SPARK_IO.File_Status;

package body TopPackage is

   procedure Main_Procedure is
      Unused_Directory_Is_Resolved : Boolean;
      Filename                     : E_Strings.T;
      File_Type                    : FileDetails.FileTypes;
      Next_File                    : Heap.Atom;
      Report_File                  : SPARK_IO.File_Type := SPARK_IO.Null_File;
      Status                       : SPARK_IO.File_Status;
      Success                      : Boolean;
      This_File                    : Heap.Atom;
      Temp_File                    : SPARK_IO.File_Type := SPARK_IO.Null_File;
      Temp_False_File              : SPARK_IO.File_Type := SPARK_IO.Null_File;
      Temp_Contra_File             : SPARK_IO.File_Type := SPARK_IO.Null_File;
      Temp_Victor_File             : SPARK_IO.File_Type := SPARK_IO.Null_File;
      Temp_Riposte_File            : SPARK_IO.File_Type := SPARK_IO.Null_File;
      Temp_User_File               : SPARK_IO.File_Type := SPARK_IO.Null_File;
      Temp_Rlu_Error_File          : SPARK_IO.File_Type := SPARK_IO.Null_File;
      Temp_Rlu_Used_File           : SPARK_IO.File_Type := SPARK_IO.Null_File;
      Temp_PR_Verr_File            : SPARK_IO.File_Type := SPARK_IO.Null_File;
      Temp_Warn_Error_File         : SPARK_IO.File_Type := SPARK_IO.Null_File;
      Temp_SDP_Error_File          : SPARK_IO.File_Type := SPARK_IO.Null_File;
      Temp_DPC_Error_File          : SPARK_IO.File_Type := SPARK_IO.Null_File;
      Temp_Victor_Error_File       : SPARK_IO.File_Type := SPARK_IO.Null_File;
      Temp_Riposte_Error_File      : SPARK_IO.File_Type := SPARK_IO.Null_File;
      Status_Temp                  : SPARK_IO.File_Status;
   begin
      VCHeap.Initialize;
      CommandLine.Read;

      if CommandLine.Data.VersionRequested then
         -- print banner on screen
         Banner.ReportVersion;
      else
         Banner.Screen;

         if not CommandLine.Data.Valid then
            FatalErrors.Process (FatalErrors.Invalid_Command_Line, E_Strings.Empty_String);
         end if;

         -- read file structure
         SPARK_IO.Put_Line (SPARK_IO.Standard_Output, "Reading file structure ...", 0);
         SPARK_IO.New_Line (SPARK_IO.Standard_Output, 1);

         FindFiles.Scan (CommandLine.Data.StartDirectory);

         -- open report file
         E_Strings.Create (File         => Report_File,
                           Name_Of_File => CommandLine.Data.ReportFile,
                           Form_Of_File => "",
                           Status       => Status);
         if Status /= SPARK_IO.Ok then
            FatalErrors.Process (FatalErrors.Could_Not_Create_Report_File, CommandLine.Data.ReportFile);
         end if;

         -- print the report file banner
         Banner.Report (Report_File);

         -- process the files
         This_File := FileHeap.FirstEntry;

         Success := True;

         -- create temporary file to store names of files with undischarged vcs
         SPARK_IO.Create (Temp_File, 0, "", "", Status_Temp);
         if Status_Temp /= SPARK_IO.Ok then
            FatalErrors.Process (FatalErrors.Problem_Creating_Temp_File, E_Strings.Empty_String);
         end if;

         --# assert True;
         -- create temporary file to store names of files with false vcs
         SPARK_IO.Create (Temp_False_File, 0, "", "", Status_Temp);
         if Status_Temp /= SPARK_IO.Ok then
            FatalErrors.Process (FatalErrors.Problem_Creating_Temp_File, E_Strings.Empty_String);
         end if;

         -- create temporary file to store names of files with vcs proved by contradiction
         SPARK_IO.Create (Temp_Contra_File, 0, "", "", Status_Temp);
         if Status_Temp /= SPARK_IO.Ok then
            FatalErrors.Process (FatalErrors.Problem_Creating_Temp_File, E_Strings.Empty_String);
         end if;

         -- create temporary file to store names of files with vcs proved by Victor
         SPARK_IO.Create (Temp_Victor_File, 0, "", "", Status_Temp);
         if Status_Temp /= SPARK_IO.Ok then
            FatalErrors.Process (FatalErrors.Problem_Creating_Temp_File, E_Strings.Empty_String);
         end if;

         -- create temporary file to store names of files with vcs proved by Riposte
         SPARK_IO.Create (Temp_Riposte_File, 0, "", "", Status_Temp);
         if Status_Temp /= SPARK_IO.Ok then
            FatalErrors.Process (FatalErrors.Problem_Creating_Temp_File, E_Strings.Empty_String);
         end if;

         -- create temporary file to store names of files with vcs proved using a
         -- user-defined proof rule
         SPARK_IO.Create (Temp_User_File, 0, "", "", Status_Temp);
         if Status_Temp /= SPARK_IO.Ok then
            FatalErrors.Process (FatalErrors.Problem_Creating_Temp_File, E_Strings.Empty_String);
         end if;

         --# assert True;

         -- create temporary file to store names of user rule files that contain
         -- syntax errors
         SPARK_IO.Create (Temp_Rlu_Error_File, 0, "", "", Status_Temp);
         if Status_Temp /= SPARK_IO.Ok then
            FatalErrors.Process (FatalErrors.Problem_Creating_Temp_File, E_Strings.Empty_String);
         end if;

         -- create temporary file to store names of user rule files that contain
         -- rules used for proof
         SPARK_IO.Create (Temp_Rlu_Used_File, 0, "", "", Status_Temp);
         if Status_Temp /= SPARK_IO.Ok then
            FatalErrors.Process (FatalErrors.Problem_Creating_Temp_File, E_Strings.Empty_String);
         end if;

         -- create temporary file to store names of review files containing errors
         SPARK_IO.Create (Temp_PR_Verr_File, 0, "", "", Status_Temp);
         if Status_Temp /= SPARK_IO.Ok then
            FatalErrors.Process (FatalErrors.Problem_Creating_Temp_File, E_Strings.Empty_String);
         end if;

         -- create temporary file to store names of files containing warnings or errors
         SPARK_IO.Create (Temp_Warn_Error_File, 0, "", "", Status_Temp);
         if Status_Temp /= SPARK_IO.Ok then
            FatalErrors.Process (FatalErrors.Problem_Creating_Temp_File, E_Strings.Empty_String);
         end if;

         -- create temporary file to store names of missing SDP file.
         SPARK_IO.Create (Temp_SDP_Error_File, 0, "", "", Status_Temp);
         if Status_Temp /= SPARK_IO.Ok then
            FatalErrors.Process (FatalErrors.Problem_Creating_Temp_File, E_Strings.Empty_String);
         end if;

         -- create temporary file to store names of missing DPC file.
         SPARK_IO.Create (Temp_DPC_Error_File, 0, "", "", Status_Temp);
         if Status_Temp /= SPARK_IO.Ok then
            FatalErrors.Process (FatalErrors.Problem_Creating_Temp_File, E_Strings.Empty_String);
         end if;

         --  Finally, we create a temporary file to store the names of
         --  erroneous vct/vlg files.
         SPARK_IO.Create (Temp_Victor_Error_File, 0, "", "", Status_Temp);
         if Status_Temp /= SPARK_IO.Ok then
            FatalErrors.Process (FatalErrors.Problem_Creating_Temp_File, E_Strings.Empty_String);
         end if;

         --  ... and one for bad rsm files from Riposte.
         SPARK_IO.Create (Temp_Riposte_Error_File, 0, "", "", Status_Temp);
         if Status_Temp /= SPARK_IO.Ok then
            FatalErrors.Process (FatalErrors.Problem_Creating_Temp_File, E_Strings.Empty_String);
         end if;

         --# assert True;

         while not Heap.IsNullPointer (This_File) and Success loop
            -- read file name
            --# accept F, 10, Unused_Directory_Is_Resolved, "Unused_Directory_Is_Resolved unused here";
            FileHeap.Details (This_File, Success, Filename, File_Type, Unused_Directory_Is_Resolved);
            --# end accept;
            if not Success then
               FatalErrors.Process (FatalErrors.Data_Structure_Inconsistency, E_Strings.Empty_String);
            end if;

            if File_Type = FileDetails.PlainFile then
               --# accept F, 41, "Expression is stable but efficient";
               if CommandLine.Data.AnalyseVCs then

                  --Rather than assume that old values will be overwritten, actually start from
                  --an initiised state each time.
                  VCHeap.Initialize;
                  if CommandLine.Data.ShortSummary then

                     VCS.Analyse
                       (SPARK_IO.Null_File,
                        Filename,
                        CommandLine.Data.AnalyseProofLog,
                        Temp_File,
                        Temp_False_File,
                        Temp_Contra_File,
                        Temp_Victor_File,
                        Temp_Riposte_File,
                        Temp_User_File,
                        Temp_Rlu_Error_File,
                        Temp_Rlu_Used_File,
                        Temp_PR_Verr_File,
                        Temp_Warn_Error_File,
                        Temp_SDP_Error_File,
                        Temp_DPC_Error_File,
                        Temp_Victor_Error_File,
                        Temp_Riposte_Error_File);
                  else
                     VCS.Analyse
                       (Report_File,
                        Filename,
                        CommandLine.Data.AnalyseProofLog,
                        Temp_File,
                        Temp_False_File,
                        Temp_Contra_File,
                        Temp_Victor_File,
                        Temp_Riposte_File,
                        Temp_User_File,
                        Temp_Rlu_Error_File,
                        Temp_Rlu_Used_File,
                        Temp_PR_Verr_File,
                        Temp_Warn_Error_File,
                        Temp_SDP_Error_File,
                        Temp_DPC_Error_File,
                        Temp_Victor_Error_File,
                        Temp_Riposte_Error_File);
                  end if;
               end if;
               --# end accept;

               -- put command to analyse path function files here
               -- Not Implemented in POGS yet...
               -- if CommandLine.Data.AnalysePFs then
               --   null;
               -- end if;

            end if;

            -- get next item in linked list
            FileHeap.Next (This_File, Success, Next_File);

            -- note that Success will be tested next, at the top of the loop
            This_File := Next_File;
         end loop;

         -- Output totals
         --# accept F, 10, Temp_File, "Temp_File unused here" &
         --#        F, 10, Temp_False_File, "Temp_False_File unused here" &
         --#        F, 10, Temp_Contra_File, "Temp_Contra_File unused here" &
         --#        F, 10, Temp_Victor_File, "Temp_Victor_File unused here" &
         --#        F, 10, Temp_Riposte_File, "Temp_Riposte_File unused here" &
         --#        F, 10, Temp_User_File, "Temp_User_File unused here" &
         --#        F, 10, Temp_Rlu_Error_File, "Temp_Rlu_Error_File unused here" &
         --#        F, 10, Temp_Rlu_Used_File, "Temp_Rlu_Used_File unused here" &
         --#        F, 10, Temp_Warn_Error_File, "Temp_PR_Verr_File unused here" &
         --#        F, 10, Temp_PR_Verr_File, "Temp_PR_Verr_File unused here" &
         --#        F, 10, Temp_DPC_Error_File, "Temp_DPC_Error_File unused here" &
         --#        F, 10, Temp_SDP_Error_File, "Temp_SDP_Error_File unused here" &
         --#        F, 10, Temp_Victor_Error_File, "Temp_Victor_Error_File unused here" &
         --#        F, 10, Temp_Riposte_Error_File, "Temp_Riposte_Error_File unused here";
         Total.Output
           (Report_File,
            Temp_File,
            Temp_False_File,
            Temp_Contra_File,
            Temp_Victor_File,
            Temp_Riposte_File,
            Temp_User_File,
            Temp_Rlu_Error_File,
            Temp_Rlu_Used_File,
            Temp_PR_Verr_File,
            Temp_Warn_Error_File,
            Temp_SDP_Error_File,
            Temp_DPC_Error_File,
            Temp_Victor_Error_File,
            Temp_Riposte_Error_File);
         --# end accept;

         Banner.FinishReport (Report_File);

         -- close report file
         --# accept F, 10, Status, "Status unused here" &
         --#        F, 10, Report_File, "Report_File unused here";
         SPARK_IO.Close (Report_File, Status);
      end if;

      --# accept F, 33, Unused_Directory_Is_Resolved, "Unused_Directory_Is_Resolved unused here";
   end Main_Procedure;

end TopPackage;
