:- export set_n_create/1, incr_counter/2, init_keyappl/0,counter/1.
:- export ':='/2, separate_key_val/4, insert_val/3.
:- export del_key/1, ins_key/1.
:- export bulk_ins/2, bulk_del/1.
:- import createpreds/2 from tr_basics2.
:- import insertdblist/2, bulk_erase/2,
	  assign/2 from tr_appl2.
:- import declare/1, destroy/2, keyed/3, create/2, 
	  set/2 from keys_basics2.
:- import inserting/1, deletedname/2, dbname/2,
	  deletelist/1, getlist/3, index_list/2 from basic_funs2.
:- import length/2, append/3 from basics.


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

init_keyappl :- 
	declare(key(counter/1,0)),
	create(counter,[1]).


ins_key(X) :- 
	functor(X,Name,NArgs),
	(
	keyed(Name,NArgs,NArgs) -> true
	;
	declare(key(Name/NArgs,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,NKey),
	index_list(NArgs,IdList),
	separate_key_val(ToArgs,NKey,ToKeys,_),
	key_name(Name,IdList,KName),
	dbname(KName,DBKName),
	Keys =.. [DBKName|ToKeys],
	getlist(Keys,FromPred,KList),
	insertdblist(KName,KList),
	(
	NArgs = NKey -> true
	;
	NVal is NArgs - NKey,
	val_name(Name,IdList,VName),
	VPred =.. [VName|ToArgs],
	getlist(VPred,FromPred,VList),
	insert_val(NKey,NVal,VList)
	).	

bulk_del(Pred) :-
	Pred =.. [Name|Args],
	length(Args,NArgs),
	keyed(Name,NArgs,NKey),
	index_list(NArgs,IdList),
	separate_key_val(Args,NKey,Keys,_),
	key_name(Name,IdList,KName),
	deletedname(KName,DName),
	dbname(KName,DBKName),
	KeyPred =.. [DBKName|Keys],
	bulk_erase(KeyPred,DName),
	(
	NArgs = NKey -> true
	;
	val_name(Name,IdList,VName),
	VPred =.. [VName|Args],
	delete_all(VPred)).


key_name(BeforeName,IdList,KeyName) :-
	name(BeforeName,NList),
	append(IdList,NList,IdNList),
	append("key_",IdNList,VList),
	name(KeyName,VList).

val_name(Before,IdList,ValName) :-
	name(Before,NList),
	append(IdList,NList,IdNList),
	append("val_",IdNList,VList),
	name(ValName,VList).

insertvlist(L) :- insertlist(L).
insertvlist(L) :- deletelist(L), !, fail.
deletevlist(L) :- deletelist(L).
deletevlist(L) :- insertlist(L), !, fail.

insertlist([]).
insertlist([H|L]) :-
	assert(H),
	insertlist(L).


delete_all(Value) :-
	getlist(Value,Value,VList),
	deletelist(VList).

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

do_assign_val(ToName,Args,TestPred,NArgs,NKey) :-
	separate_key_val(Args,NKey,Keys,_),
	index_list(NArgs,IdList),
	key_name(ToName,IdList,KeyName),	
	dbname(KeyName,DBKName),
	KPred = [DBKName|Keys],
	(
	NArgs = NKey -> assign(KPred,TestPred)
	;
	NVal is NArgs - NKey,
	val_name(ToName,IdList,ValName),
	ValPred =.. [ValName|Args],
	getlist(ValPred,TestPred,ValList), !,
	assign(KPred,TestPred),	
	delete_all(ValPred),
	insert_val(NKey,NVal,ValList)
	).	

insert_val(_,_,[]).
insert_val(NKey,NVal,[Val|Rest]) :-
	Val =.. [ValName|Args],
	separate_key_val(Args,NKey,Keys,_),
	createpreds(NVal,FreeArgs),
	append(Keys,FreeArgs,TestArgs),
	TestArg =.. [ValName|TestArgs], !,
	(
	TestArg -> true
	;
	inserting(Val)),
	insert_val(NKey,NVal,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_counter(N,Delta) :-
	counter(N),
	M is N+Delta,
	set(counter,[M]).



% 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).
