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

%###############################################################################
% PURPOSE
%-------------------------------------------------------------------------------
% Establishes the names of all files for this session, based on the
% arguments provided on the command line and the parent directory.
%###############################################################################




%###############################################################################
% MODULE
%###############################################################################

:- module(load__data_files, [load_data_files/0]).

%###############################################################################
% DEPENDENCIES
%###############################################################################

:- use_module('librarypredicates.pro',
              [file_exists/1]).

:- use_module('data__switches.pro', [get_switch_deadpaths/1,
                                     get_switch_input_file/1,
                                     get_switch_log/1]).
:- use_module('data__data_files.pro', [get_datafiles_vcg/1,
                                       add_datafiles_vcg/1,
                                       get_datafiles_dpc/1,
                                       add_datafiles_dpc/1,
                                       get_datafiles_simplified_vcg/1,
                                       add_datafiles_simplified_vcg/1,
                                       get_datafiles_summary_dpc/1,
                                       add_datafiles_summary_dpc/1,
                                       get_datafiles_fdl/1,
                                       add_datafiles_fdl/1,
                                       get_datafiles_local_user_rule/1,
                                       add_datafiles_local_user_rule/1,
                                       get_datafiles_global_user_rule/1,
                                       add_datafiles_global_user_rule/1,
                                       get_datafiles_rule/1,
                                       add_datafiles_rule/1,
                                       get_datafiles_pfs/1,
                                       add_datafiles_pfs/1,
                                       get_datafiles_simplified_pfs/1,
                                       add_datafiles_simplified_pfs/1,
                                       get_datafiles_dec/1,
                                       add_datafiles_dec/1,
                                       get_datafiles_log/1,
                                       add_datafiles_log/1,
                                       add_datafiles_debug/2]).
:- use_module('ioutilities.pro',
              [show_error/2]).
:- use_module('newutilities.pro',
              [explode_separator_content_as_list/3,
               implode_separator_content_list/3]).

:- use_module('simplifier_ioutilities.pro',
              [retrieve_proof_file_kind/1]).

%###############################################################################
% TYPES
%###############################################################################

%###############################################################################
% DATA
%###############################################################################

%###############################################################################
% PREDICATES
%###############################################################################


:- set_prolog_flag(double_quotes, chars).

%===============================================================================
% load_data_files.
%-------------------------------------------------------------------------------
%Based on known information, determine and store the name of every file
%that may be used.
%===============================================================================

load_data_files:-

    % Establish all of the file names for this session.
    establish_static_files,
    establish_dynamic_files,
    !.

%===============================================================================
% establish_static_files.
%-------------------------------------------------------------------------------
% Calculate and store all of the hard-coded static files. It is expected
% that these files will only be used internally for debugging purposes.
%===============================================================================
establish_static_files:-

    %Add all debug files.
    establish_debug_file(data__prf),
    establish_debug_file(data__vcg),
    establish_debug_file(data__files),
    !.

%-------------------------------------------------------------------------------

%Adds a debug file in a consistent manner.
establish_debug_file(DebugFileKind):-
    implode_separator_content_list('',
                                   ['debug_', DebugFileKind, '.pro'],
                                   DebugFile_Atom),
    absolute_file_name(DebugFile_Atom, AbsoluteDebugFile_Atom),
    add_datafiles_debug(DebugFileKind, AbsoluteDebugFile_Atom),
    !.

%===============================================================================
% establish_dynamic_files.
%-------------------------------------------------------------------------------
% Calculate and store all of the files, whose location depends on
% changeable information.
%===============================================================================

% Input file has not been provided.
establish_dynamic_files:-
    \+ get_switch_input_file(_InputFile_Atom),
    show_error('Target file not provided on the command-line.', []).

% Input file has been provided.
establish_dynamic_files:-
    get_switch_input_file(InputFile_Atom),

    %The provided input file will use the syntax relevant for the current
    %platform. The input file provided may be relative to the current
    %directory, or rooted to some point in the filesystem. To treat the
    %platform specific relative or rooted file name consistently it is
    %always put into its absolute form, via a platform portable predicate.
    absolute_file_name(InputFile_Atom, AbsoluteInputFile_Atom),

    %Determine the proof file kind.
    proof_file_info(AbsoluteInputFile_Atom,
                    ProofFileKind,
                    AbsoluteDirectory_Atom,
                    BaseFile_Atom),

    establish_proof_file_dependent_files(ProofFileKind,
                                         AbsoluteDirectory_Atom,
                                         BaseFile_Atom),
    establish_common_files(AbsoluteDirectory_Atom,
                           BaseFile_Atom),
    !.

% None of the above is an error.
establish_dynamic_files:-
    show_error('Unexpected error in establishing input file details.', []).

%-------------------------------------------------------------------------------

%Set up files for verification conditions.
establish_proof_file_dependent_files(verification_conditions,
                                     AbsoluteDirectory_Atom,
                                     BaseFile_Atom):-

    %Mandatory input files.
    %----------------------

    %.vcg file
    implode_separator_content_list('',
                                   [AbsoluteDirectory_Atom, BaseFile_Atom, '.vcg'],
                                   VcgFile_Atom),
    ensure_datafile_exists(VcgFile_Atom),
    add_datafiles_vcg(VcgFile_Atom),

    %.fdl file
    implode_separator_content_list('',
                                   [AbsoluteDirectory_Atom, BaseFile_Atom, '.fdl'],
                                   FdlFile_Atom),
    ensure_datafile_exists(FdlFile_Atom),
    add_datafiles_fdl(FdlFile_Atom),

    %Optional input files.
    %---------------------

    % Although the current examiner always generates VCs with a supporting
    % rls file, this has not always been the case. Thus, the rls files are
    % optional.

    %.rls file
    implode_separator_content_list('',
                                   [AbsoluteDirectory_Atom, BaseFile_Atom, '.rls'],
                                   RuleFile_Atom),
    potentially_add_datafiles_rule(RuleFile_Atom),

    %.rlu file (local)
    implode_separator_content_list('',
                                   [AbsoluteDirectory_Atom, BaseFile_Atom, '.rlu'],
                                   LocalUserRuleFile_Atom),
    potentially_add_datafiles_local_user_rule(LocalUserRuleFile_Atom),

    %.rlu file (global)
    retrieve_parent_directory(AbsoluteDirectory_Atom,
                              ParentDirectory_Atom),
    implode_separator_content_list('',
                                   [AbsoluteDirectory_Atom, ParentDirectory_Atom, '.rlu'],
                                   GlobalUserRuleFile_Atom),
    potentially_add_datafiles_global_user_rule(LocalUserRuleFile_Atom,
                                               GlobalUserRuleFile_Atom),

    %Mandatory output files.
    %-----------------------

    %.siv file
    implode_separator_content_list('',
                                   [AbsoluteDirectory_Atom, BaseFile_Atom, '.siv'],
                                   SimplifiedVcgFile_Atom),
    add_datafiles_simplified_vcg(SimplifiedVcgFile_Atom),
    !.

% Set up files for dead path search.
establish_proof_file_dependent_files(zombie_scope,
                                     AbsoluteDirectory_Atom,
                                     BaseFile_Atom):-
    %Mandatory input files.
    %----------------------

    %.dpc file
    implode_separator_content_list('',
                                   [AbsoluteDirectory_Atom, BaseFile_Atom, '.dpc'],
                                   DpcFile_Atom),
    ensure_datafile_exists(DpcFile_Atom),
    add_datafiles_dpc(DpcFile_Atom),

    %.fdl file
    implode_separator_content_list('',
                                   [AbsoluteDirectory_Atom, BaseFile_Atom, '.fdl'],
                                   FdlFile_Atom),
    ensure_datafile_exists(FdlFile_Atom),
    add_datafiles_fdl(FdlFile_Atom),

    %Optional input files.
    %---------------------

    % Although the current examiner always generates VCs with a supporting
    % rls file, this has not always been the case. Thus, the rls files are
    % optional.

    %.rls file
    implode_separator_content_list('',
                                   [AbsoluteDirectory_Atom, BaseFile_Atom, '.rls'],
                                   RuleFile_Atom),
    potentially_add_datafiles_rule(RuleFile_Atom),

    %Mandatory output files.
    %-----------------------

    %.sdp file
    implode_separator_content_list('',
                                   [AbsoluteDirectory_Atom, BaseFile_Atom, '.sdp'],
                                   SummaryDpcFile_Atom),
    add_datafiles_summary_dpc(SummaryDpcFile_Atom),

    !.




%Set up files for path functions.
establish_proof_file_dependent_files(path_functions,
                                     AbsoluteDirectory_Atom,
                                     BaseFile_Atom):-

    %Mandatory input files.
    %----------------------

    %.pfs file
    implode_separator_content_list('',
                                   [AbsoluteDirectory_Atom, BaseFile_Atom, '.pfs'],
                                   PfsFile_Atom),
    ensure_datafile_exists(PfsFile_Atom),
    add_datafiles_pfs(PfsFile_Atom),

    %.dec file
    implode_separator_content_list('',
                                   [AbsoluteDirectory_Atom, BaseFile_Atom, '.dec'],
                                   DecFile_Atom),
    ensure_datafile_exists(DecFile_Atom),
    add_datafiles_dec(DecFile_Atom),

    %Mandatory output files.
    %-----------------------

    %.sip file
    implode_separator_content_list('',
                                   [AbsoluteDirectory_Atom, BaseFile_Atom, '.sip'],
                                   SimplifiedPfsFile_Atom),
    add_datafiles_simplified_pfs(SimplifiedPfsFile_Atom),
    !.



%None of the above is unexpected.
establish_proof_file_dependent_files(ProofFileKind,
                                     _AbsoluteDirectory_Atom,
                                     _BaseFile_Atom):-
    show_error('Unexpected proof file kind: ~p.', [ProofFileKind]).


%-------------------------------------------------------------------------------

ensure_datafile_exists(File_Atom):-
    file_exists(File_Atom),
    !.

ensure_datafile_exists(File_Atom):-
    show_error('Required input file does not exist: ~a.', [File_Atom]).

%-------------------------------------------------------------------------------

potentially_add_datafiles_rule(RuleFile_Atom):-
    file_exists(RuleFile_Atom),
    add_datafiles_rule(RuleFile_Atom),
    !.

% From above, file does not exist, so do not add.
potentially_add_datafiles_rule(_RuleFile_Atom):-
    !.

%-------------------------------------------------------------------------------

potentially_add_datafiles_local_user_rule(LocalUserRuleFile_Atom):-
    file_exists(LocalUserRuleFile_Atom),
    add_datafiles_local_user_rule(LocalUserRuleFile_Atom),
    !.

% From above, file does not exist, so do not add.
potentially_add_datafiles_local_user_rule(_LocalUserRuleFile_Atom):-
    !.

%-------------------------------------------------------------------------------

potentially_add_datafiles_global_user_rule(LocalUserRuleFile_Atom,
                                           GlobalUserRuleFile_Atom):-

    % While unusual, it is possible for the optional user rule input files
    % to be exactly the same. In this case the global usr rule file is not
    % added. (For example, the examiner may generate false VCs following a
    % semantic error.  It is a semantic error in SPARK for a package to
    % have a subprogram with the same name. In this case the examiner
    % generates false VCs for the subprogram, using the same name as its
    % package, creating potential duplicate same name for the local and
    % global user rule files).
    %







    \+ (LocalUserRuleFile_Atom = GlobalUserRuleFile_Atom),
    file_exists(GlobalUserRuleFile_Atom),
    add_datafiles_global_user_rule(GlobalUserRuleFile_Atom),
    !.

% From above, file does not exist, so do not add.
potentially_add_datafiles_global_user_rule(_LocalUserRuleFile_Atom,
                                           _GlobalUserRuleFile_Atom):-
    !.

%-------------------------------------------------------------------------------

establish_common_files(AbsoluteDirectory_Atom,
                       BaseFile_Atom):-
    establish_log_file(AbsoluteDirectory_Atom,
                       BaseFile_Atom),
    !.

%-------------------------------------------------------------------------------

% Log file requested. Use default name.
% Log file is slg when Simplifier is discharging VCs and zlg when Simplifier
% is searching for dead paths,

establish_log_file(AbsoluteDirectory_Atom,
                   BaseFile_Atom):-
    get_switch_deadpaths(off),
    get_switch_log(yes_log_file),

    %.slg file
    implode_separator_content_list('',
                                   [AbsoluteDirectory_Atom, BaseFile_Atom, '.slg'],
                                   LogFile_Atom),
    add_datafiles_log(LogFile_Atom),
    !.

establish_log_file(AbsoluteDirectory_Atom,
                   BaseFile_Atom):-
    get_switch_deadpaths(on),
    get_switch_log(yes_log_file),

    %.zlg file
    implode_separator_content_list('',
                                   [AbsoluteDirectory_Atom, BaseFile_Atom, '.zlg'],
                                   LogFile_Atom),
    add_datafiles_log(LogFile_Atom),
    !.

% Log file requested, with specific name.
establish_log_file(_AbsoluteDirectory_Atom,
                   _BaseFile_Atom):-
    get_switch_log(provided_log_file(LogFile_Atom)),

    % To treat the platform specific relative or rooted file name
    % consistently it is always put into its absolute form, via a platform
    % portable predicate.
    absolute_file_name(LogFile_Atom, AbsoluteLogFile_Atom),
    add_datafiles_log(AbsoluteLogFile_Atom),
    !.

% User has specified that no log be used.
establish_log_file(_AbsoluteDirectory_Atom,
                   _BaseFile_Atom):-
    get_switch_log(no_log_file),
    !.

% None of the above is an error.
establish_log_file(_AbsoluteDirectory_Atom,
                   _BaseFile_Atom):-
    show_error('Unable to determine correct logging behaviour.',
                []).

%===============================================================================
% proof_file_info(+AbsoluteInputFile_Atom,
%                 -ProofFileKind,
%                 -AbsoluteDirectory_Atom,
%                 -BaseFile_Atom).
%-------------------------------------------------------------------------------
% Given an input file (AbsoluteInputFile_Atom) determine its proof file
% kind (ProofFileKind) and its absolute directory (with trailing '/') and
% its base file name (BaseFile_Atom). Note that if the proof file kind can
% not be determined from the file name, it is assumed that the extension
% '.vcg' is missing and corrects aspects accordingly. Note that sicstus
% uses '/' as the directory separator, regardless of whatever the platform
% uses.
%
% For example:
% AbsoluteInputFile_Atom=U:/one/two/three/four.vcg
% ProofFileKind=verification_conditions
% AbsoluteDirectory_Atom=U:/one/two/three/
% BaseFile_Atom=four
%
% For example:
% AbsoluteInputFile_Atom=U:/one/two/three/six
% ProofFileKind=verification_conditions
% AbsoluteDirectory_Atom=U:/one/two/three/
% BaseFile_Atom=six
%===============================================================================

proof_file_info(AbsoluteInputFile_Atom,
                ProofFileKind,
                AbsoluteDirectory_Atom,
                BaseFile_Atom):-

    %Retrieve the directory parts and file part.
    explode_separator_content_as_list('/',
                                      AbsoluteInputFile_Atom,
                                      Item_AtomList),

    %The last part is the file part.
    append(Directory_AtomList, [File_Atom], Item_AtomList),
    determine_proof_file_kind_and_base_file(File_Atom,
                                            ProofFileKind,
                                            BaseFile_Atom),

    %Reassemble the directory part.
    implode_separator_content_list('/',
                                   Directory_AtomList,
                                   AbsoluteDirectoryLessTrailing_Atom),

    %Add the trailing '/'.
    atom_concat(AbsoluteDirectoryLessTrailing_Atom,
                '/',
                AbsoluteDirectory_Atom),
    !.

%-------------------------------------------------------------------------------

determine_proof_file_kind_and_base_file(File_Atom,
                                        ProofFileKind,
                                        BaseFile_Atom):-
    atom_chars(File_Atom, File_CharList),
    determine_proof_file_kind_and_base_file_x(File_CharList,
                                              ProofFileKind,
                                              BaseFile__CharList),
    atom_chars(BaseFile_Atom, BaseFile__CharList),
    !.

%-------------------------------------------------------------------------------

% If deadpath switch is off.

% Without extension, verification_conditions is the default.
determine_proof_file_kind_and_base_file_x(File__BaseFile__CharList,
                                          verification_conditions,
                                          File__BaseFile__CharList):-
    get_switch_deadpaths(off),
    \+ member('.', File__BaseFile__CharList),
    !.

% With explicit vcg extension is verification_conditions.
determine_proof_file_kind_and_base_file_x(File_CharList,
                                          verification_conditions,
                                          BaseFile_CharList):-
    get_switch_deadpaths(off),
    append(BaseFile_CharList, ".vcg", File_CharList),
    !.

% If dead path switch is on

% Without extension deadpath_search.
determine_proof_file_kind_and_base_file_x(File__BaseFile__CharList,
                                          zombie_scope,
                                          File__BaseFile__CharList):-
    get_switch_deadpaths(on),
    \+ member('.', File__BaseFile__CharList),
    !.

% With explicit dpc extension
determine_proof_file_kind_and_base_file_x(File_CharList,
                                          zombie_scope,
                                          BaseFile_CharList):-
    get_switch_deadpaths(on),
    append(BaseFile_CharList, ".dpc", File_CharList),
    !.



% With explicit pfs extension is path_functions.
determine_proof_file_kind_and_base_file_x(File_CharList,
                                          path_functions,
                                          BaseFile_CharList):-
    append(BaseFile_CharList, ".pfs", File_CharList),
    !.



% Any other extension is treated as an error.
determine_proof_file_kind_and_base_file_x(File_CharList,
                                          _ProofFileKind,
                                          _BaseFile_CharList):-
    atom_chars(File_Atom, File_CharList),
    show_error('Provided input file ~a should have no extension or have a .vcg or .pfs extension.',
               [File_Atom]).

%===============================================================================
% retrieve_parent_directory(+AbsoluteDirectory_Atom,
%                           -ParentDirectory_Atom).
%-------------------------------------------------------------------------------
% Given an absolute directory (with trailing '/') determine the parent
% directory name.
%
% For example:
% AbsoluteDirectory_Atom=U:/one/two/three/
% ParentDirectory_Atom=three
%===============================================================================

retrieve_parent_directory(AbsoluteDirectory_Atom,
                          ParentDirectory_Atom):-

    %Retrieve the directory parts and file part.
    explode_separator_content_as_list('/',
                                      AbsoluteDirectory_Atom,
                                      Item_AtomList),
    append(_LeadingItem_AtomList,
           [ParentDirectory_Atom, _TopDirectory_Atom],
           Item_AtomList),
    !.


:- set_prolog_flag(double_quotes, codes).

%###############################################################################
% END-OF-FILE
