:- object(bintree,
	implements(dictionaryp),
	extends(compound)).


	:- info([
		version is 1.0,
		author is 'Paulo Moura',
		date is 2000/7/24,
		comment is 'Dictionary protocol implemented using binary trees.']).


	:- private(map/4).
	:- metapredicate(map(*, *, *, ::)).

	:- mode(map(+atom, +tree, -tree, -callable), zero_or_one).


	as_list(Tree, List) :-
		as_list(Tree, [], List).


	as_list(t, List, List).

	as_list(t(Key, Value, Left, Right), Acc, List) :-
		as_list(Right, Acc, Acc2),
		as_list(Left, [Key-Value| Acc2], List).


	empty(Tree) :-
		Tree == t.


	insert(Key, Value, t, t(Key, Value, t, t)) :-
		nonvar(Key).

	insert(Key, Value, t(Key1, Value1, Left1, Right1), t(Key1, Value2, Left2, Right2)) :-
		compare(Order, Key, Key1),
		insert(Order, Key, Value, Key1, Value1, Left1, Right1, Value2, Left2, Right2).


	insert(=, _, Value, _, _, Left, Right, Value, Left, Right).

	insert(<, Key, Value, _, Value1, Left1, Right, Value1, Left2, Right) :-
		insert(Key, Value, Left1, Left2).

	insert(>, Key, Value, _, Value1, Left, Right1, Value1, Left, Right2) :-
		insert(Key, Value, Right1, Right2).


	insert_all([], Tree, Tree).

	insert_all([Key-Value| Rest], Old, New) :-
		insert(Key, Value, Old, Aux),
		insert_all(Rest, Aux, New).


	lookup(Key, Value, Tree) :-
		var(Key) ->
			lookup_var(Key, Value, Tree)
			;
			lookup_nonvar(Key, Value, Tree).


	lookup_nonvar(Key, Value, t(Key1, Value1, Left1, Right1)) :-
		compare(Order, Key, Key1),
		lookup_nonvar(Order, Key, Value, Value1, Left1, Right1).


	lookup_nonvar(=, _, Value, Value, _, _).

	lookup_nonvar(<, Key, Value, _, Left, _) :-
		lookup_nonvar(Key, Value, Left).

	lookup_nonvar(<, Key, Value, _, _, Right) :-
		lookup_nonvar(Key, Value, Right).


	lookup_var(Key, Value, t(_, _, Left, _)) :-
		lookup_var(Key, Value, Left).

	lookup_var(Key, Value, t(Key, Value,_,_)).

	lookup_var(Key, Value, t(_, _, _, Right)) :-
		lookup_var(Key, Value, Right).


	keys(Tree, Keys) :-
		keys(Tree, [], Keys).


	keys(t, Keys, Keys).

	keys(t(Key, _, Left, Right), Acc, Keys) :-
		keys(Right, Acc, Acc2),
		keys(Left, [Key| Acc2], Keys).


	delete(t, _, _, t).

	delete(t(Key1, Value1, Left1, Right1), Key, Value, Out) :-
		compare(Order, Key, Key1),
		delete(Order, Key1, Value1, Left1, Right1, Key, Value, Out).


	delete(=, Key1, Value1, Left1, Right1, Key1, Value1, Out) :-
		join(Left1, Right1, Out).

	delete(<, Key1, Value1, Left1, Right1, Key, Value, t(Key1, Value1, Left2, Right1)) :-
		delete(Left1, Key, Value, Left2).

	delete(>, Key1, Value1, Left1, Right1, Key, Value, t(Key1, Value1, Left1, Right2)) :-
		delete(Right1, Key, Value, Right2).


	join(t, Right, Right) :-
		!.

	join(Left, t, Left) :-
		!.

	join(t(Key, Value, Left, Right), Tree, t(Key, Value, Left, Right2)) :-
		join(Right, Tree, Right2).


	map(Pred, Old, New) :-
		map(Pred, Old, New, _).


	map(Pred, t(Key1, Value1, Left1, Right1), t(Key2, Value2, Left2, Right2), Goal) :-
		Goal =.. [Pred, Key1-Value1, Key2-Value2],
		once(Goal),
		map(Pred, Left1, Left2, _),
		map(Pred, Right1, Right2, _).

	map(_, t, t, _).


	new(t).


	size(Dictionary, Size) :-
		size(Dictionary, 0, Size).


	size(t, Size, Size).

	size(t(_, _, Left, Right), Acc, Size) :-
		size(Left, Acc, Acc2),
		Acc3 is Acc2 + 1,
		size(Right, Acc3, Size).


:- end_object.