/**
 * 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.
 */

/**
 * last(L, E):
 * The predicate succeeds with E being the last element of the list L.
 */
% last(+List, -Elem)
last([X|Y], Z) :- sys_last(Y, Z, X).

% sys_last(+List, +Elem, -Elem)
sys_last([], X, X).
sys_last([X|Y], Z, _) :- sys_last(Y, Z, X).

/**
 * last(L, E, R):
 * The predicate succeeds with E being the last element of the list L
 * and R being the remainder of the list.
 */
% last(+List, -Elem, -List)
last([X|Y], Z, T) :- sys_last(Y, Z, X, T).

% sys_last(+List, +Elem, -Elem, -List)
sys_last([], X, X, []).
sys_last([X|Y], Z, U, [U|T]) :- sys_last(Y, Z, X, T).

/**
 * nth0(I, L, E):
 * The predicate succeeds with E being the (I+1)-th element of the list L.
 */
% nth0(-Integer, +List, -Elem)
nth0(N, L, E) :- var(N), !,
   L = [X|Y], sys_nth(Y, X, E, 0, N).
nth0(N, L, E) :- must_be(integer, N),
   N >= 0, sys_nth(N, L, E).

% sys_nth(+List, +Elem, -Elem, +Integer, -Integer)
sys_nth(_, X, X, N, N).
sys_nth([X|Y], _, Z, N, M) :-
   H is N+1, sys_nth(Y, X, Z, H, M).

% sys_nth(+Integer, -List, -Elem)
sys_nth(0, R, X) :- !, R = [X|_].
sys_nth(N, [_|Y], X) :-
   M is N-1, sys_nth(M, Y, X).

/**
 * nth0(I, L, E, R):
 * The predicate succeeds with E being the (I+1)-th element of the list L
 * and R being the remainder of the list.
 */
% nth0(-Integer, +List, -Elem, -List)
nth0(N, L, E, R) :- var(N), !,
   L = [X|Y], sys_nth(Y, X, E, 0, N, R).
nth0(N, L, E, R) :- must_be(integer, N),
   N >= 0, sys_nth(N, L, E, R).

% sys_nth(+List, +Elem, -Elem, +Integer, -Integer, -List)
sys_nth(Y, X, X, N, N, Y).
sys_nth([X|Y], H, Z, N, M, [H|T]) :-
   J is N+1, sys_nth(Y, X, Z, J, M, T).

% sys_nth(+Integer, -List, -Elem, -List)
sys_nth(0, R, X, Y) :- !, R = [X|Y].
sys_nth(N, [H|Y], X, [H|T]) :-
   M is N-1, sys_nth(M, Y, X, T).

/**
 * nth1(I, L, E):
 * The predicate succeeds with E being the I-th element of the list L.
 */
% nth1(+Integer, +List, -Elem)
nth1(N, L, E) :- var(N), !,
   L = [X|Y], sys_nth(Y, X, E, 1, N).
nth1(N, L, E) :- must_be(integer, N),
   N >= 1, H is N-1, sys_nth(H, L, E).

/**
 * nth1(I, L, E, R):
 * The predicate succeeds with E being the I-th element of the list L
 * and R being the remainder of the list.
 */
% nth1(+Integer, +List, -Elem, -List)
nth1(N, L, E, R) :- var(N), !,
    L = [X|Y], sys_nth(Y, X, E, 1, N, R).
nth1(N, L, E, R) :- must_be(integer, N),
    N >= 1, H is N-1, sys_nth(H, L, E, R).

/*******************************************************************/
/* include/3 and exclude/3                                         */
/*******************************************************************/

/**
 * include(C, L, R):
 * The predicate succeeds in R with the elements of L
 * such that the closure C succeeds once.
 */
% include(+Closure, +List, -List)
include(C, L, R) :-
   ir_site_new(C, D),
   sys_include(L, D, R).

% sys_include(+List, +Closure, -List)
sys_include([], _, []).
sys_include([X|L], C, R) :-
   call(C, X), !,
   R = [X|S],
   sys_include(L, C, S).
sys_include([_|L], C, R) :-
   sys_include(L, C, R).

/**
 * exclude(C, L, R):
 * The predicate succeeds in R without the elements of L
 * such that the closure C succeeds once.
 */
% exclude(+Closure, +List, -List)
exclude(C, L, R) :-
   ir_site_new(C, D),
   sys_exclude(L, D, R).

% sys_exclude(+List, +Closure, -List)
sys_exclude([], _, []).
sys_exclude([X|L], C, R) :-
   call(C, X), !,
   sys_exclude(L, C, R).
sys_exclude([X|L], C, [X|R]) :-
   sys_exclude(L, C, R).





