:- export insertdblist/2, bulk_erase/2, 
	  bulkins/2, bulkdel/1, assign/2, simple_assign/5.
:- import insertnewdbrule/5, do_insert/2, do_delete/2
	  from tr_basics2.
:- import insertedname/2, deletedname/2, dbname/2, inserting/1, deleting/1,
	  getlist/3  from basic_funs2.

:- op(850,xfy,[from]).
:- op(900,xfy,[assign_to]).

% bulk insertion (always true, i.e. weak)
%
bulkins(FromFun,ToFun) :- 
	ToFun =.. [ToName|ToArgs],
	dbname(ToName,DBName),
	insertedname(ToName,IName),
	deletedname(ToName,DName), 
	DBPred =.. [DBName|ToArgs],
	(
	predicate_property(DBPred,(dynamic)) ->
		do_bulkinsert(FromFun,IName,DName,DBName,ToFun)
	;
	not predicate_property(DBPred,(dynamic)),
	functor(DBPred,DBName,NArgs),
	insertnewdbrule(ToName,DBName,IName,DName,NArgs), !,
	deleting(tr),
	do_bulkinsert(FromFun,IName,DName,DBName,ToFun),
	inserting(tr)).

do_bulkinsert(FromFun,IName,DName,DBName,ToFun) :-
	getlist(ToFun,FromFun,List),!,
	do_insertlist(IName,DName,DBName,List).

% weak insert all predicates in the list
do_insertlist(_,_,_,[]).
do_insertlist(IName,DName,DBName,[ToFun|Rest]) :-
	ToFun =.. [_|Args],
	do_weakinsert(IName,DName,DBName,Args),
	do_insertlist(IName,DName,DBName,Rest).

% weak insert, i.e. it succeeds if Pred is already in the database
do_weakinsert(_,_,DBName,Args) :-
	DBPred =.. [DBName|Args],
	call(DBPred).
do_weakinsert(IName,DName,_,Args) :-
	IPred =.. [IName|Args],
	do_insert(IPred,DName).

% bulk deletion (always true)
%
bulkdel(X) :-
	X =.. [Name|Args],
	dbname(Name,DBName),
	deletedname(Name,DName),
	DBPred =.. [DBName|Args],
	(predicate_property(DBPred,(dynamic)) -> bulk_erase(DBPred,DName)
	;
	not predicate_property(DBPred,(dynamic))).


% Unlike bulkins, there is only one term for bulk_erase, so database(Term)
% works the same as removing tr flag first.
bulk_erase(DBTerm,DName) :-
	getlist(DBTerm,DBTerm,List), !,
	do_deletelist(List,DName).

% Delete all predicate in the list.
% Note: We can use strong delete because these predicates should already be
% in the database. 
do_deletelist([],_).
do_deletelist([Pred|Rest],DName) :-
        do_delete(Pred,DName),
        do_deletelist(Rest,DName).


% assignments
% For example,  assign q(X,Y) from p(X,Y)
% syntax:       assign_to(q, from([X,Y],p(X,Y))
%           or  assign_to(q, p(X,Y))
assign(OutPred,TestPred) :-
	OutPred =.. [OutName|ArgList],
	dbname(OutName,DBName),
	deletedname(OutName,DName),
	insertedname(OutName,IName),
	DBPred =.. [DBName|ArgList],
	(
	predicate_property(DBPred,(dynamic)) ->
		simple_assign(DBName,IName,DName,ArgList,TestPred)
	;
	not(predicate_property(DBPred,(dynamic))),
	functor(DBPred,DBName,NArgs),
	insertnewdbrule(OutName,DBName,IName,DName,NArgs),
	simple_assign(DBName,IName,DName,ArgList,TestPred)).
	
% bulk delete OutPred first and then bulk insert from TestPred to OutPred
simple_assign(DBName,IName,DName,ArgList,TestPred) :-
	Buffer =.. [IName|ArgList],
	deleting(tr),
	getlist(Buffer,TestPred,BufferList), % copy output to buffer
	inserting(tr),
	OutPred =.. [DBName|ArgList],
	bulk_erase(OutPred,DName),
	do_insertlist(IName,DName,DBName,BufferList).




insertdblist(Name,List) :-
	dbname(Name,DBName),
	insertedname(Name,IName),
	deletedname(Name,DName), 
	do_insertlist(IName,DName,DBName,List).	
