:- export init/0.
:- export instrans/1.
:- export tracking/0, track/1.
:- export conj/2, if/3.
:- export cleanup/0, key/1.
:- export inserted/1, deleted/1.
:- export loadtran/1 , loadbase/1.
:- import scanVars/3 from basic_funs1.
:- import assert/1, retract/1 from assert.
:- import initdbmode/0 from parser1.
:- import getfreetemp/1 from upload1.
:- import initkey/0, declare/1, create/2 from keys_basics1.
:- import init_basic/0, on_backtracking/1, insertbase/1, deletebase/1 from basic_funs1.
:- import dbase/1,basicsinit/0 from tr_basics1.

:- op(1150,fx,[instrans,insbase,delbase]).
:- op(800,xfy,[while,for]).
:- op(800,fx,[while,for,if]).
:- op(750,fx,[with]).
:- op(750,xfy,[do,then,else]).
:- op(720,xfy,[in]).
:- op(1000,xfy,[sc]).
:- op(1000,xfy,[conj]).
:- op(1130,xfy,[<-]).  


init :- 
	reconsult(tr_basics1),
	reconsult(tr_appl1),
	reconsult(keys_basics1),
	reconsult(keys_appl1),
	reconsult(query1),
	reconsult(upload1),
	reconsult(parser1),
	reconsult(basic_funs1),
	initdbmode, init_basic,
	basicsinit, initkey,
	dynpred(tracking), dynamic(tr),
	dynpred(track([])), 
	dynpred(loop(_,_)), dynpred(temp(_,_)),
	declare(key(count/1,0)),
	declare(tr/0),
	create(count,[1]).



/* ***************************************************************** 
	Insert clause to transaction base
 ***************************************************************** */

instrans('<-'(Lhs,Rhs)) :-
	dotransbody(Rhs,Pro),
	assert((Lhs :- (tr, Pro))),
	checknewrule.

instrans( Pred ) :-
	not(Pred = '<-'(_,_)),
	assert((Pred :- tr)).

dotransbody(sc(A,B),(Pro1,Pro2)) :-
	dotransbody(A,Pro1),
	dotransbody(B,Pro2).
dotransbody(while(with(Varlist),do(Cond,Body)),Temp) :-
	getfreetemp(TempName),
	Temp =.. [TempName|Varlist],
	dotransbody(Body,BPro),
	insertbase(whileclause(Temp,Cond,BPro)).

dotransbody(while(do(Cond,Body)),Temp) :-
	getfreetemp(Temp),
	dotransbody(Body,BPro),
	insertbase(whileclause(Temp,Cond,BPro)).

dotransbody(for(with(Varlist),do(in(List,Cond),Body)),Temp) :-
	getfreetemp(TempName),
	getfreetemp(LoopName),
	Temp = (assign_to(TempName,from(List,dbase(Cond))), LoopName),
	LoopBuffer =.. [TempName|List],
	LoopPred =.. [LoopName|Varlist],
	dotransbody(Body,BPro),
	insertbase(forclause(LoopPred,LoopBuffer,BPro)).

dotransbody(for(do(in(List,Cond),Body)),Temp) :-
	getfreetemp(TempName),
	getfreetemp(LoopName),
	Temp = (assign_to(TempName,from(List,Cond)), LoopName),
	LoopBuffer =.. [TempName|List],
	dotransbody(Body,BPro),
	insertbase(forclause(LoopName,LoopBuffer,BPro)).

dotransbody(if(then(Cond,else(Alpha,Beta))),VarName) :-
	scan3(Cond,Alpha,Beta,Varlist),
	getfreetemp(Temp),
	VarName =.. [Temp|Varlist],
	dotransbody(Alpha,AlphaPro),
	dotransbody(Beta,BetaPro),
	insertbase(ifthenelse(VarName,Cond,AlphaPro,BetaPro)).

dotransbody(if(then(Cond,Alpha)),VarName) :-
	scan3(Cond,Alpha,true,Varlist),
	getfreetemp(Temp),
	VarName =.. [Temp|Varlist],
	dotransbody(Alpha,AlphaPro),
	insertbase(ifthenelse(VarName,Cond,AlphaPro,true)).

dotransbody(Body,Body) :-
	not Body = sc(_,_),
	not Body = if(_,_),
	not Body = else(_,_),
	not Body = while(_),
	not Body = while(_,_),
	not Body = for(_,_),
	not Body = for(_).

checknewrule :-					% check while loop
	deletebase(whileclause(Temp,Cond,BPro)),
	insertbase((Temp :- tr, dbase(Cond),BPro,Temp)),
	insertbase((Temp :- tr, not(dbase(Cond)))),
	checknewrule.
checknewrule :- checknewrulefor.
checknewrulefor :-
	deletebase(forclause(Loopname,Temp,BPro)),
	insertbase((Loopname :- tr, dbase(Temp), del(Temp), BPro, Loopname)),
	insertbase((Loopname :- tr, not(dbase(Temp)))),
	checknewrulefor.
checknewrulefor :- checknewruleif.
checknewruleif :-
	deletebase(ifthenelse(VarName,Cond,AlphaPro,BetaPro)),
	insertbase((VarName :- tr, dbase(Cond), AlphaPro)),
	insertbase((VarName :- tr, not(dbase(Cond)), BetaPro)),
	checknewruleif.
checknewruleif.

/* ***************************************************************** */

conj(A,B) :-	totrack, 
		A, forceback(Tr),
		B, track(Tr2), compare(Tr,Tr2), endconj.


totrack	 :- assert(tracking), on_backtracking(retract(tracking)),
	    assert(track([])), on_backtracking(retract(track([]))).

forceback(X) :- retract(track(X)),
		undotrack(X),  assert(track([])).

endconj :-	
	retract(tracking), on_backtracking(assert(tracking)),
	retract(track(X)), on_backtracking(assert(track(X))).

undotrack([]).
undotrack([(i,Data)|Tr]) :-
	deletebase(Data), undotrack(Tr).
undotrack([(d,Data)|Tr]) :-
	insertbase(Data), undotrack(Tr).

compare([],[]).

compare([(X,D)|Tr1],[(X,D)|Tr2]) :-
		compare(Tr1,Tr2).

dynpred(X) :- dynamic(X).
/*
inserteq(Lhs,Rhs) :-
	Lhs =.. [Name|Args],
	dbname(Name,DBName),
	DBPred =.. [DBName|Args],
	(
	predicate_property(DBPred,(dynamic)) ->
		assert((DBPred :- Rhs))
	;
	not (predicate_property(DBPred,(dynamic))),
	assert((Lhs :- DBPred)),
	assert((DBPred :- Rhs))
	).		
*/

if(X,Y,_) :- call(X),  call(Y).
if(X,_,Z) :- not(X), call(Z).




scan3(Phi,Alpha,Beta,VarList) :-
	Phi =.. [_|PhiVars],
	Alpha =.. [_|AlphaVars],
	Beta =.. [_|BetaVars],
	scanVars(PhiVars,[],List1),
	scanVars(AlphaVars,List1,List2),
	scanVars(BetaVars,List2,VarList).

