/**
 * Warranty & Liability
 * To the extent permitted by applicable law and unless explicitly
 * otherwise agreed upon, XLOG Technologies AG makes no warranties
 * regarding the provided information. XLOG Technologies AG assumes
 * no liability that any problems might be solved with the information
 * provided by XLOG Technologies AG.
 *
 * Rights & License
 * All industrial property rights regarding the information - copyright
 * and patent rights in particular - are the sole property of XLOG
 * Technologies AG. If the company was not the originator of some
 * excerpts, XLOG Technologies AG has at least obtained the right to
 * reproduce, change and translate the information.
 *
 * Reproduction is restricted to the whole unaltered document. Reproduction
 * of the information is only allowed for non-commercial uses. Selling,
 * giving away or letting of the execution of the library is prohibited.
 * The library can be distributed as part of your applications and libraries
 * for execution provided this comment remains unchanged.
 *
 * Restrictions
 * Only to be distributed with programs that add significant and primary
 * functionality to the library. Not to be distributed with additional
 * software intended to replace any components of the library.
 *
 * Trademarks
 * Jekejeke is a registered trademark of XLOG Technologies AG.
 */

:- ensure_loaded(library(util/sequence)).
:- ensure_loaded(library(text/format)).

/*********************************************************************/
/* Statistics                                                        */
/*********************************************************************/

/**
 * statistics(K, V):
 * The predicate succeeds for the value V of the flag K. See
 * documentation for the available flags.
 */
% statistics(-Atom, -Term)
statistics(Key, Value) :- var(Key), !,
   sys_stat_map(Map),
   ir_object_keys(Map, Keys),
   member(Key, Keys),
   ir_object_current(Map, Key, Value).
statistics(Key, Value2) :-
   sys_stat_map(Map),
   ir_object_current(Map, Key, Value), !,
   Value2 = Value.
statistics(Key, _) :-
   throw(error(domain_error(prolog_flag, Key),_)).

/**
 * statistics:
 * The predicate displays the current statistics key value pairs.
 */
% statistics
statistics :-
   current_output(Stream),
   statistics(K, V),
   put_message(Stream, statistics(K,V)), nl,
   fail.
statistics.

/*********************************************************************/
/* Time Measurement                                                  */
/*********************************************************************/

/**
 * time(A):
 * The predicate succeeds whenever the goal A succeeds. As a
 * side effect, timing of the call or redo is shown.
 */
% time(+Goal)
time(G) :-
   X =.. [v,0,0,0],
   try_call_finally(
      sys_time_set(X),
      G,
      sys_time_show(X)).

% sys_time_set(+Compound)
sys_time_set(X) :-
   sys_stat_map(Map),
   ir_object_current(Map, time, Time),
   ir_object_current(Map, gctime, Gctime),
   ir_object_current(Map, calls, Calls),
   change_arg(1, X, Time),
   change_arg(2, X, Gctime),
   change_arg(3, X, Calls).

% sys_time_show(+Compound)
sys_time_show(X) :-
   current_output(Stream),
   arg(1, X, Time1),
   arg(2, X, Gctime1),
   arg(3, X, Calls1),
   sys_stat_map(Map),
   ir_object_current(Map, time, Time),
   ir_object_current(Map, gctime, Gctime),
   ir_object_current(Map, calls, Calls),
   Time2 is Time-Time1,
   Gctime2 is Gctime-Gctime1,
   Calls2 is Calls-Calls1,
   (Time2 =\= 0 -> Lips is round(Calls2 / Time2); Lips = 0),
   member(K-V, [time-Time2, gctime-Gctime2, lips-Lips]),
   put_message(Stream, time(K,V)),
   fail.
sys_time_show(_) :-
   nl.

/*********************************************************************/
/* Listing Indexes                                                   */
/*********************************************************************/

/**
 * jiti_list:
 * jiti_list(I):
 * The predicate lists the index statictics of the user predicates.
 * The unary predicate allows specifying a predicate indicator.
 */
% jiti_list
jiti_list :-
   jiti_list(_).

% jiti_list(+Indicator)
jiti_list(I) :-
   current_output(Stream),
   sys_jiti_list(I, Stream).

% sys_jiti_list(+Indicator, +Stream)
sys_jiti_list(F/N, Stream) :- !,
   sys_jiti_list_pattern(F, N, Stream).
sys_jiti_list(F, Stream) :-
   sys_jiti_list_pattern(F, _, Stream).

% sys_jiti_list_pattern(+Atom, +Integer, +Stream)
sys_jiti_list_pattern(F, N, Stream) :-
   call_nth(sys_jiti_list_indicator(F, N), C),
   (C > 1 -> nl(Stream); true),
   sys_jiti_list_pred(F, N, Stream),
   fail.
sys_jiti_list_pattern(_, _, _).

% sys_jiti_list_pred(+Atom, +Integer, +Stream)
sys_jiti_list_pred(F, N, Stream) :-
   put_message(Stream, jiti_list(pred,F/N)),
   nl(Stream),
   kb_pred_link(F, N, Q),
   kb_link_flags(Q, D),
   (D /\ 16 =\= 0 -> T = 'prehash'; T = 'functor'),
   put_message(Stream, jiti_list(type,T)),
   nl(Stream),
   kb_link_stat_get(Q, M),
   ir_object_keys(M, L),
   member(I, L),
   ir_object_current(M, I, S),
   member(K-V, [path-I, size-S]),
   put_message(Stream, jiti_list(K,V)),
   nl(Stream),
   fail.
sys_jiti_list_pred(_, _, _).

/****************************************************************/
/* Indexes Filter                                               */
/****************************************************************/

% sys_jiti_list_indicator(-Atom, +Integer)
sys_jiti_list_indicator(F, N) :-
   current_predicate(F/N),
   kb_pred_link(F, N, Q),
   kb_link_stat_has(Q),
   \+ sys_user_stop(F, N),
   functor(H, F, N),
   \+ \+ sys_user_ref(H, _).

/*********************************************************************/
/* User Database                                                     */
/*********************************************************************/

% sys_user_stop(+Atom, -Integer)
sys_user_stop(sys_op, 5).
sys_user_stop(sys_source, 3).
sys_user_stop(sys_srcprop, 2).
sys_user_stop(sys_predprop, 3).
sys_user_stop(sys_lastpred, 3).
sys_user_stop(sys_including, 3).
sys_user_stop(sys_emulated, 2).
sys_user_stop(sys_init_goal, 1).
sys_user_stop(sys_trace_skip, 2).

% sys_user_ref(+Term, -Ref)
sys_user_ref(H, C) :-
   kb_clause_ref(H, 0, C),
   kb_clause_shard(C, P),
   \+ sys_user_nope(P).

% sys_user_nope(+Atom)
sys_user_nope(system).
sys_user_nope(Path) :-
   current_prolog_flag(system_url, Base),
   file_directory_name(Base, Dir),
   sub_atom(Path, 0, _, _, Dir).

/*********************************************************************/
/* Other Texts                                                       */
/*********************************************************************/

% strings(+Atom, +Atom, -Atom)
:- multifile(strings/3).
strings('statistics.gctime', de, '% GC Zeit~t~3f~40| ms').
strings('statistics.maxinfs', de,'% Autoyield~t~d~40|').
strings('statistics.calls', de,  '% Aufrufe~t~d~40|').
strings('statistics.time', de,   '% Betriebszeit~t~3f~40| ms').
strings('statistics.wall', de,   '% Uhrzeit~t~d~40| ms').
strings('statistics.used', de,   '% Speicher~t~d~40| B').

strings('time.time', de, '% Zeit ~3f ms').
strings('time.gctime', de, ', GC ~3f ms').
strings('time.lips', de, ', Lips ~d k').

strings('jiti_list.pred', de,    '% Prädikat~t~w~40|').
strings('jiti_list.type', de,    '% Typ~t~w~40|').
strings('jiti_list.path', de,    '% Argumente~t~w~40|').
strings('jiti_list.size', de,    '% Kardinalität~t~d~40|').

strings('statistics.gctime', '', '% GC time~t~3f~40| ms').
strings('statistics.maxinfs', '','% Autoyield~t~d~40|').
strings('statistics.calls', '',  '% Calls~t~d~40|').
strings('statistics.time', '',   '% Realtime~t~3f~40| ms').
strings('statistics.wall', '',   '% Walltime~t~d~40| ms').
strings('statistics.used', '',   '% Memory~t~d~40| B').

strings('time.time', '', '% Time ~3f ms').
strings('time.gctime', '', ', GC ~3f ms').
strings('time.lips', '', ', Lips ~d k').

strings('jiti_list.pred', '',    '% Predicate~t~w~40|').
strings('jiti_list.path', '',    '% Type~t~w~40|').
strings('jiti_list.type', '',    '% Arguments~t~w~40|').
strings('jiti_list.size', '',    '% Cardinality~t~d~40|').

/*******************************************************************/
/* Foreign Predicates                                              */
/*******************************************************************/

% sys_stat_map(X):
% defined in foreign(tester/statlib)

% garbage_collect:
% defined in foreign(tester/statlib)

% kb_link_stat_has(Q):
% defined in foreign(tester/statlib)

% kb_link_stat_get(Q, M):
% defined in foreign(tester/statlib)

:- ensure_loaded(foreign(tester/statlib)).