/* ************************************************************
        module for basic transaction functions
************************************************************* */
:- export inserted/1, deleted/1, checkconj/2, checkanddefine/1.
:- export insertnewdbrule/5, changefunctor/3.
:- export createpreds/2, ins/1, del/1.
:- export do_insert/2, do_delete/2.
:- export dbase/1.
:- import newpred/1 from query2.
:- import retract/1, assert/1, asserta/1 from assert.
:- import deletedname/2, insertedname/2, dbname/2,
	  inserting/1, deleting/1, on_backtracking/1 from basic_funs2.


:- op(450,fx,[ins,del]).
:- op(710,fx,[not]).

% basic strong insertion
%
ins(X) :- 
	X =.. [Name|Args],
	dbname(Name,DBName), 
	DBPred =.. [DBName|Args], 
	functor(X,Name,NArgs), 
	(
	predicate_property(DBPred,(dynamic)) -> 
		do_insert_withoutnewrule(Name,Args)
	;
	not(predicate_property(DBPred,(dynamic))),
	do_insert_withnewrule(Name,DBName,NArgs,Args)).

do_insert_withoutnewrule(Name,Args) :-
	insertedname(Name,IName),
	deletedname(Name,DName), 
	IPred =.. [IName|Args], !,
	do_insert(IPred,DName).

do_insert_withnewrule(Name,DBName,NArgs,Args) :-
	insertedname(Name,IName),
	deletedname(Name,DName), 
	insertnewdbrule(Name,DBName,IName,DName,NArgs), 
	IPred =.. [IName|Args], !,
	do_insert(IPred,DName).

% For initial inserts, assert the insert tag.
do_insert(IPred,_) :-
	not IPred,	% note : IPred should be defined if the DB rule exist
	assert(IPred),
%	checkconj(i,IPred),
	undo_ins1(IPred).

% For all subsequent inserts, simply remove the delete tag.
do_insert(IPred,DName) :-
	IPred,
	changefunctor(IPred,DName,DPred),
	retract(DPred),
%	checkconj(d,DPred),
	undo_ins2(DPred).

undo_ins1(_).
undo_ins1(IPred) :- 
	retract(IPred), !, fail.
undo_ins2(_).
undo_ins2(DPred) :- 
	asserta(DPred), !, fail.

% basic strong delete
%
del(X) :- 
	X =.. [Name|Args],
	dbname(Name,DBName), 
	DBPred =.. [DBName|Args], !,
%	predicate_property(DBPred,(dynamic)),
	deletedname(Name,DName),
	!,
	do_delete(DBPred,DName).

% strong delete, so insert a delete tag
do_delete(DBPred,DName) :- 
	call(DBPred),
	changefunctor(DBPred,DName,DPred),
	assert(DPred),
%	checkconj(i,DPred),
	undo_del(DPred).

undo_del(_).
undo_del(DPred) :- retract(DPred), !, fail.


% create a list of N unique and uninstantiated args
%
createpreds(0,[]).
createpreds(N,[_|L]) :-
	N>0, M is N-1, createpreds(M,L).

% define not
%
not(X) :- X, !, fail
	  ;
	  true.


checkconj(Info,Data) :-
        tracking, !, savetrack(Info,Data)
        ;
        not(tracking), true.
savetrack(Info,Data) :-
        retract(track(L)), assert(track([(Info,Data)|L])),
        on_backtracking((retract(track(_)), assert(track(L)))).



changefunctor(Pred,Name,NewPred) :-
	Pred =.. [_|Args],
	NewPred =.. [Name|Args].

insertnewdbrule(TrName,DBName,IName,DName,NArgs) :-
	createpreds(NArgs,L), 
	TrPred =.. [TrName|L],
	DBPred =.. [DBName|L],
	InsPred =.. [IName|L],
	DelPred =.. [DName|L],
	dynamic(TrPred),
	dynamic(DBPred),
	dynamic(InsPred),
	dynamic(DelPred),
	newpred(DelPred),
	assert((TrPred :- DBPred)),
	assert((DBPred :- InsPred, not(DelPred))).

dbase(Pred) :-
	deleting(tr),
	call(Pred),
	inserting(tr).

