% -----------------------------------------------------------------------------
%  (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
%-------------------------------------------------------------------------------
% Provides access to all information related to vcs. This information will
% be retrieved from the provided vcg file.
%###############################################################################


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

:- module(data__vcg, [get_vcg_file_handle/1,
                      add_vcg_file_handle/1,

                      get_vcg_seen_vc/0,
                      add_vcg_seen_vc/0,
                      get_vcg_trace/2,
                      add_vcg_trace/2,
                      get_vcg_vc/5,
                      add_vcg_vc/5,
                      get_vcg_hypothesis/3,
                      add_vcg_hypothesis/3,
                      get_vcg_conclusion/3,
                      add_vcg_conclusion/3,

                      get_zombiescope_no_check_required/1,
                      add_zombiescope_no_check_required/1,

                      prune_vcg_file_handle/0,
                      prune_all_vcg_vc/0,
                      prune_all_vcg_hypothesis/0,
                      prune_all_vcg_conclusion/0,
                      prune_all_zombiescope_no_check_required/0,
                      prune_vcg_hypothesis/3,

                      save_data__vcg/0]).

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

:- use_module('data__formats.pro',
              [add_state/2,
               add_type/2]).
:- use_module('ioutilities.pro',
              [write_terms_to_file/2]).
:- use_module('data__data_files.pro',
               [must_get_datafiles_debug/2]).

:- use_module('data__switches', [get_switch_deadpaths/1,
                                 get_switch_hyp_limit/1]).

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

% For path(s) from XXX to YYY:
% For checks of refinement integrity:
:- add_type('VCTrace',
            [traverseCutpoints('VCCutpointFrom', 'VCCutpointTo'),
             checkRefinementIntegrity,
             subclassInheritanceIntegrity]).

% start
% assertion of line NN
% ZZZ assertion of line NN
:- add_type('VCCutpointFrom',
            [start,
             assertion('AssertionKind', 'Line_Int')]).

% finish
% assertion of line NN
% default assertion of line NN
% check associated with statement of line NN
% run-time check associated with statement of line NN
% precondition check associated with statement of line NN
:- add_type('VCCutpointTo',
            [finish,
             assertion('AssertionKind', 'Line_Int'),
             check('CheckKind', 'Line_Int')]).

:- add_type('AssertionKind',
            [userprovided,
             default]).

:- add_type('CheckKind',
            [userprovided,
             runtime,
             precondition]).


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

% VCs are loaded one-at-a-time. Thus, need a location to store the VCG file
% handle between each VC load.
:- add_state(get_vcg_file_handle,
             get_vcg_file_handle('VcgFile_Stream')).
:- dynamic(get_vcg_file_handle/1).

% Record that a vc has been seen.
:- add_state(get_vcg_seen_vc,
             get_vcg_seen_vc).
:- dynamic(get_vcg_seen_vc/0).

% A vcg file has a number of trace lines.
% Each trace line has a number of VCs.
% Each VC has a number of hypotheses and a number of conclusions.
:- add_state(get_vcg_trace,
             get_vcg_trace('TraceId_Atom', 'VCTrace')).
:- dynamic(get_vcg_trace/2).

:- add_state(get_vcg_vc,
             get_vcg_vc('VCId_Atom',
                        'Order_Int',
                        'Name_Atom',
                        'Number_Int',
                        'ParentVCTraceId_Atom')).
:- dynamic(get_vcg_vc/5).

:- add_state(get_vcg_hypothesis,
             get_vcg_hypothesis('Number_Int', 'Hyp_Term', 'ParentVCId_Atom')).

:- dynamic(get_vcg_hypothesis/3).

:- add_state(get_vcg_conclusion,
             get_vcg_conclusion('Number_Int', 'Conc_Term', 'ParentVCId_Atom')).
:- dynamic(get_vcg_conclusion/3).

:- add_state(get_zombiescope_no_check_required,
             get_zombiescope_no_check_required('ParentVCId_Atom')).

:- dynamic(get_zombiescope_no_check_required/1).

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


%===============================================================================
% Add.
%===============================================================================

add_vcg_file_handle(VcgFile_Stream):-
    assert(get_vcg_file_handle(VcgFile_Stream)),
    !.

add_vcg_seen_vc:-
    assert(get_vcg_seen_vc),
    !.

add_vcg_trace(TraceId_Atom, VCTrace):-
    assert(get_vcg_trace(TraceId_Atom, VCTrace)),
    !.

add_vcg_vc(VCId_Atom, Order_Int, Name_Atom, Number_Int, ParentVCTraceId_Atom):-
    assert(get_vcg_vc(VCId_Atom, Order_Int, Name_Atom, Number_Int, ParentVCTraceId_Atom)),
    !.

add_vcg_hypothesis(Number_Int, Hyp_Term, ParentVCId_Atom):-
    get_switch_deadpaths(off),
    assert(get_vcg_hypothesis(Number_Int, Hyp_Term, ParentVCId_Atom)),
    !.

% Loading hyps for ZombieScope.

add_vcg_hypothesis(Number_Int, Hyp_Term, ParentVCId_Atom):-
    get_switch_deadpaths(on),
    get_switch_hyp_limit(HypLimit_Int),
    add_dpc_hypothesis(HypLimit_Int, Number_Int, Hyp_Term, ParentVCId_Atom),
    !.

% Always load hyp if the limit is set to 0.
add_dpc_hypothesis(0, Number_Int, Hyp_Term, ParentVCId_Atom):-   
    assert(get_vcg_hypothesis(Number_Int, Hyp_Term, ParentVCId_Atom)),
    !.

% Only load if limit has not been exceeded.
add_dpc_hypothesis(HypLimit_Int, Number_Int, Hyp_Term, ParentVCId_Atom):-
    Number_Int =< HypLimit_Int,
    assert(get_vcg_hypothesis(Number_Int, Hyp_Term, ParentVCId_Atom)),
    !.

% Remove the DPC if the the limit has been exceeded.
add_dpc_hypothesis(_HypLimit_Int, _Number_Int, _Hyp_Term, ParentVCId_Atom):-
    prune_all_vcg_hypothesis,
    add_vcg_hypothesis(1, 'true', ParentVCId_Atom),
    add_dpc_hypothesis_x(ParentVCId_Atom),
    !.

add_dpc_hypothesis_x(VCId_Atom):-
    user:log_fact(zombiescope_exceed_limit, [VCId_Atom]),
    !.

add_dpc_hypothesis_x(VCId_Atom):-
    retractall(user:log_fact(_, _)), 
    user:assert_log_fact(zombiescope_exceed_limit, [VCId_Atom]),
    !.
    

add_vcg_conclusion(Number_Int, Conc_Term, ParentVCId_Atom):-
    assert(get_vcg_conclusion(Number_Int, Conc_Term, ParentVCId_Atom)),
    !.

add_zombiescope_no_check_required(ParentVCId_Atom):-
    assert(get_zombiescope_no_check_required(ParentVCId_Atom)),
    !.

%===============================================================================


%===============================================================================
% Prune.
%===============================================================================

prune_vcg_file_handle:-
    retractall(get_vcg_file_handle(_VcgFile_Stream)),
    !.

prune_all_vcg_vc:-
    retractall(get_vcg_vc(_VCId_Atom, _Order_Int, _Name_Atom, _Number_Int, _ParentVCTraceId_Atom)),
    !.

prune_all_vcg_hypothesis:-
    retractall(get_vcg_hypothesis(_Number_Int, _Hyp_Term, _ParentVCId_Atom)),
    !.

prune_all_vcg_conclusion:-
    retractall(get_vcg_conclusion(_Number_Int, _Conc_Term, _ParentVCId_Atom)),
    !.

prune_all_zombiescope_no_check_required:-
    retractall(get_zombiescope_no_check_required(_VCId_Atom)),
    !.

prune_vcg_hypothesis(Number_Int, Hyp_Term, ParentVCId_Atom):-
    retract(get_vcg_hypothesis(Number_Int, Hyp_Term, ParentVCId_Atom)),
    !.


%===============================================================================


%===============================================================================
% save_data__vcg.
%===============================================================================

save_data__vcg:-
    must_get_datafiles_debug(data__vcg, DebugFile_Atom),
    write_terms_to_file(DebugFile_Atom,
                        [data__vcg:get_vcg_file_handle/1,
                         data__vcg:get_vcg_seen_vc/0,
                         data__vcg:get_vcg_trace/2,
                         data__vcg:get_vcg_vc/5,
                         data__vcg:get_vcg_hypothesis/3,
                         data__vcg:get_vcg_conclusion/3]),
    !.
%===============================================================================


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