/* *******************************************************
	Key application
*********************************************************** */

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

init_keyappl :- 
	declare(key(counter/1,0)),
	call(create_1_counter(1)).


% bulk insert
% 1. create an insert tag for the key of the destination predicate
% 2. insert the tags and the values
bulk_ins(FromPred,ToPred) :-
	ToPred =.. [Name|Args],
	keyed(Name,NArgs,NKey),
	index_list(NArgs,IdList),
	separate_key_val(Args,NKey,Keys,_),
	inskey_name(Name,IdList,IName),	
	IPred =.. [IName|Keys],
	getlist(IPred,FromPred,IList),
	call_all_list(IList),
	(
	NArgs = NKey -> true
	;
	% if there is value predicate for the destination
	NVal is NArgs - NKey,
	val_name(Name,IdList,VName),
	VPred =.. [VName|Args],
	getlist(VPred,FromPred,VList),
	insert_val(NKey,NVal,VList)
	).

% bulk delete 
bulk_del(Pred) :-
	Pred =.. [Name|Args],
	length(Args,NArgs),
	index_list(NArgs,IdList),
	destroy_name(Name,IdList,DName),
	DPred =.. [DName|Args],
	getlist(DPred,Pred,DList), !,
	call_all_list(DList).

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

% bulk assignment FromP to ToPred, note that ToPred should have been declared.
% 1. construct general predicate for create and destroy
% 2. use getlist/3 to record the tuples which needs to create
% 3. destroy all the predicate of ToPred
% 4. create the tuples recorded
':='(ToPred,FromPreds) :-
	ToPred =.. [ToName|Args],
	length(Args,NArgs),
	keyed(ToName,NArgs,_),
	createpreds(NArgs,FreeArgs),
	index_list(NArgs,IdList),
	destroy_name(ToName,IdList,DesName),	
	DesPred =.. [DesName|FreeArgs],	
	create_name(ToName,IdList,CName),
	CPred =.. [CName|Args],
	AllPred =.. [ToName|FreeArgs],
	getlist(CPred,FromPreds,CList), !,
	destroy_all(AllPred,DesPred),
	call_all_list(CList).

destroy_all(ToPred,DesPred) :-
	getlist(DesPred,ToPred,DList), !,
	call_all_list(DList).

call_all_list([]).
call_all_list([Pred|Rest]) :- 
	call(Pred), call_all_list(Rest).


% Given the number of key and value, 
% insert the list of value predicates and with a check that
% no predicate with same key is already in the database
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
	;
	insertbase(Val)),
	insert_val(NKey,NVal,Rest).


% create the new predicate.
set_n_create(X) :- 
		X =.. [Name|Args],
		keyed(Name,NArgs,_),
		index_list(NArgs,IdList),
		create_name(Name,IdList,CName),
		Create =.. [CName|Args],
		call(Create).

/*
declare_or_clear(declare(size(Decl,Mem))) :-
		(
		  declare(size(Decl,Mem)) -> true
		  ;
		  Decl = Name/NArgs,
		  clear_old_values(Name,NArgs,NArgs)
		).
declare_or_clear(declare(size(key(KDecl,NKeys),Mem))) :-
		(
		  declare(size(key(KDecl,NKeys),Mem)) -> true
		  ;
		  KDecl = Name/NArgs,
		  clear_old_values(Name,NArgs,NKeys)  
		).

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(_,_)),
		not(NamenArgs = size(_,_)),
		(
		  declare(NamenArgs) -> true
		  ;
		  NamenArgs = Name/NArgs,
		  clear_old_values(Name,NArgs,NArgs)
		).
clear_old_values(Name,NArgs,NKeys) :-
		keyed(Name,NArgs,NKeys),
		createpreds(NArgs,ArgList),
		Pred =.. [Name|ArgList],
		bulk_del(Pred).
*/

incr_counter(N,Delta) :-
	call(counter(N)),
	M is N+Delta,
	call(set_1_counter(M)).

