/* ***********************************************************
	key module
************************************************************ */

:- export set_n_create/1, declare_or_clear/1, separate_key_val/4.
:- export ':='/2, insert_val/1.
:- export del_key/1, del_keys/1, ins_key/1, copy_keys/2, incr/3.
:- export bulk_ins/2, bulk_del/1.
:- import bulkins/2, bulkdel/1 from tr_appl1.
:- import simple_assign/2 from tr_appl1.
:- import declare/1, create/2, destroy/2, set/2, keyed/3, key/1, val/3, keyof/2 
	  from keys_basics1.
:- import deletebase/1, insertbase/1, getlist/3, delete_all/1 from basic_funs1.
:- import length/2 from basics.

:- op(450,fx,[ins_key,del_key]).
:- op(900,xfy,[':=']).


ins_key(X) :- 
	functor(X,Name,NArgs),
	(
	keyed(Name,NArgs,NArgs) -> true
	;
	declare(key(Name/NArgs))),
	create(X,[]).

del_key(X) :-
	functor(X,Name,NArgs),
	keyed(Name,NArgs,NArgs),
	destroy(X,[]).

bulk_ins(FromPred,ToPred) :-
	ToPred =.. [Name|ToArgs],
	length(ToArgs,NArgs),
	keyed(Name,NArgs,NKeys),
	separate_key_val(ToArgs,NKeys,ToKeys,ToVals),
	Keys =.. [Name|ToKeys],
	bulkins(FromPred,keyof(NArgs,Keys)),
	getlist(val(NArgs,Keys,ToVals),FromPred,VList),
	insertvlist(VList).

bulk_del(Pred) :-
	Pred =.. [Name|Args],
	length(Args,NArgs),
	keyed(Name,NArgs,NKeys),
	separate_key_val(Args,NKeys,ToKeys,ToVals),
	Keys =.. [Name|ToKeys],
	bulkdel(keyof(NArgs,Keys)),
	delete_all(val(NArgs,Keys,ToVals)).
/*
copy_keys(FromKeys,ToKeys) :-
	functor(FromKeys,FName,FNKeys),
	functor(ToKeys,TName,TNKeys),
	keyed(FName,FNArgs,FNKeys),
	(
	keyed(TName,TNArgs,TNKeys) -> true
	;
	declare(key(TName/Total,TNKeys))
	),
	bulkins(key(FromKeys),key(ToKeys)),
	getlist(val(ToKeys,Val),val(FromKeys,Val),ValList),
	insertvlist(ValList).
*/
insertvlist([]).
insertvlist([val(NArgs,Keys,Val)|Rest]) :-
	(
	val(NArgs,Keys,V) -> deletebase(val(NArgs,Keys,V))
	;
	true),
	insertbase(val(NArgs,Keys,Val)),
	insertvlist(Rest).

del_keys(P) :-
	functor(P,_,NArgs),
	bulkdel(keyof(NArgs,P)),
	delete_all(val(NArgs,P,_)).

% assign FromP to ToPred, note that ToPred should have been declared.
%
':='(ToPred,FromP) :-
	ToPred =.. [TName|Args],
	length(Args,NArgs),
	keyed(TName,NArgs,TKey),
	do_assign_keyandval(TName,Args,FromP,TKey).

do_assign_keyandval(ToName,Args,TestPred,NKey) :-
	separate_key_val(Args,NKey,Keys,Vals), !,
	length(Args,NArgs),
	ToKey =.. [ToName|Keys],
	getlist(val(NArgs,ToKey,Vals),TestPred,VList),
	simple_assign(keyof(NArgs,ToKey),TestPred), 
	delete_all(val(NArgs,ToKey,Vals)), 
	insert_val(VList).

insert_val([]).
insert_val([val(NArgs,Key,Vals)|Rest]) :-
	( val(NArgs,Key,_) -> true
	  ;
	  insertbase(val(NArgs,Key,Vals)) ),
	  insert_val(Rest).

% separate that attributes into keys and values.
%
separate_key_val(Args,0,[],Args).
separate_key_val([K1|Args],NKey,[K2|Keys],Val) :-
	NKey>0,
	M is NKey - 1,
	separate_key_val(Args,M,Keys,Val),
	K2 = K1.

% increment the value of the key be delta
% note that the value field of the key has only one entry
incr(Key,OldVal,Delta) :-
	keyof(NArgs,Key),
	val(NArgs,Key,[OldVal]),
	integer(OldVal),
	NewVal is OldVal + Delta,
	set(Key,[NewVal]).


% create and set the values of new predicates, for the use in upload.
set_n_create(X) :- 
	X =.. [Name|Args],
	keyed(Name,NArgs,NKey),
	length(Args,NArgs),
	separate_key_val(Args,NKey,Keys,Vals),
	P =.. [Name|Keys],
	create(P,Vals).


/*
declare_or_clear(declare(key(NamenArgs,NKeys))) :-
		(
		  declare(key(NamenArgs,NKeys)) -> true
		  ;
		  NamenArgs = Name/NArgs,
		  clear_old_values(Name,NArgs,NKeys)
		).

declare_or_clear(declare(NamenArgs)) :-
		not(NamenArgs = key(_,_)),
		(
		  declare(NamenArgs) -> true
		  ;
		  NamenArgs = Name/NArgs,
		  clear_old_values(Name,NArgs,0)
		).
clear_old_values(Name,NArgs,NKeys) :-
		keyed(Name,NArgs,NKeys),
		createpreds(NArgs,ArgList),
		Pred =.. [Name|ArgList],
		bulk_del(Pred).
*/
