:- ensure_loaded(typeops).        % in order to use TYPICAL
:- ensure_loaded('container_lib.pl').  % additional non-variant section part
%----
:- ensure_loaded('container_quicksort.pl'). % a variant section part
% :- ensure_loaded('container keysort.pl').   % a alternative variant part
/*****************************************************************
	container_access

        several predicates to operate with abstract data-structure container
*******************************************************************/
:- tap_interface.

:- type container(T).       % abstract declaration

:- type entry(T) == keyvalue(int,T).

:- import_type(prolog_misc, keyvalue(K,V)).

:- pred get_first(container(T),entry(T)).
:- pred get_next(container(T), entry(T), entry(T)).

:- pred add_entry(entry(T), container(T), container(T)).

:- pred new_container(container(T)).

:- pred merge_cont(container(T), container(T), container(T)).

% ...

:- tap_interface_end.

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

:- tap_body(container_access, [container_lib, container_access]).

:- import(prolog_meta).               % getting definition of list(T),too

:- type container(T) == list(entry(T)).    % entry is defined in interface



/*-----
	new_container(-container)

        gives back a new container object
*/
:- pred new_container(container(T)).

new_container([]).





/*-------
	add_entry(+entry,+container,-container)

        adds entry uniquely into container
*/
:- pred add_entry(entry(T), container(T), container(T)).

add_entry(NewEntry, ContIn, ContOut) :-
	\+ entry_exist(ContIn, NewEntry), !,
	append([NewEntry], ContIn, ContOut_us),
	sort_cont(ContOut_us, ContOut).


/* alternative solution for add_entry/3:
add_entry(NewEntry, ContIn, ContOut) :- 
	\+ entry_exist(ContIn, NewEntry), !,
	append_sort([NewEntry],ContIn, ContOut).
*/





/*------
	entry_exist(+container,+entry)

        testing if entry is already in container
*/
:- pred entry_exist(container(T), entry(T)).

entry_exist([Entry|_ContRest], Candidate) :-
	Entry  == Candidate, !.
entry_exist([_Entry|ContRest], Candidate) :-
	entry_exist(ContRest, Candidate).
	

/*-------
	get_first(+container,-entry)

        gives back the first entry of container
*/
:- pred get_first(container(T), entry(T)).

get_first([Entry|_], Entry).


/*------
	get_next(+container,+entryin,-entryout)

        gives back entryout, which is the next entry after entryin in container
*/
:- pred get_next(container(T), entry(T), entry(T)).

get_next([X,Y|_ContRest], EntryIn, EntryOut) :-
	X == EntryIn, !,
	EntryOut = Y.
get_next([_|ContRest], EntryIn, EntryOut) :-
	get_next(ContRest, EntryIn, EntryOut).


/*-------
	merge_cont(+container, +container,-container)

        merges the contents of two container objects and 
        gives back the resulting container object
*/
:- pred merge_cont(container(T), container(T), container(T)).

merge_cont(ContainerIn1, ContainerIn2, ContainerOut) :-
	merge(ContainerIn1, ContainerIn2, ContainerOut).

% ...

:- tap_body_end(container_access).
