

:- use_module(library(each_call_cleanup)).


test(0):- each_call_cleanup(writeln(start),(between(1,3,X),writeln(X)), writeln(end)),fail. 

% todo - fix so ref is bound
test(1):- each_call_cleanup(asserta(scce0,REF),(between(1,3,X),writeln(REF:X)),erase(REF)),fail. 


:- listing(test(_)).


% ===================================================================
%  TESTING
% ===================================================================

:- abolish(scce_test/1).
:- dynamic(scce_test/1).
:- retractall(scce_test(_)).

w0(X):- setup_call_cleanup_each(writeln(start),(between(1,3,X),writeln(X)), writeln(end)).
w0(REF,X):-
 flag(scce_test_flag,_,1),
 setup_call_cleanup_each(
         (flag(scce_test_flag,F,F+1),asserta(scce_test(F),REF),nl,nl,wdmsg(enter(REF:F:X))),
         (between(1,3,X),wdmsg(goal(REF:F:X))),
         (erase(REF),wdmsg(cleanup(REF:F:X)),nl)),
 \+ call(scce_test(_)),
 flag(scce_test_flag,FWas,FWas),
 FWas is F + 1,
 wdmsg(success(REF:F=FWas:X)),
 nl,nl.


% Could current predicates such as:   profile/1  quietly/1 with_output_to_*/2  PL_call()  (possibly ignore/1)  benefit as well like with_output_to/2 does?

% we wanted to code this
:- meta_predicate with_output_to_scc(*,0).
with_output_to_scc(D,G):- current_output(W), setup_call_cleanup(set_output(D),G,set_output(W)).

% However it doesn't work with didnt work with setup_call_cleanup/3 
% becasue "hi" was sent to 'user_error' 2 times!
scce_sad:- with_output_to_scc(user_error,( between(1,3,M),wdmsg(M))),  wdmsg("hi"), fail.

% So we ended up lowering out expectations:
:- meta_predicate with_output_to_wa(*,0).
with_output_to_wa(D,G):- current_output(W), setup_call_cleanup(set_output(D),once(G),set_output(W)).

% Fixed, since "hi" was no longer sent to 'user_error' !    (However 2 and 3 were no longer sent!?)
scce_sadder:- with_output_to_scc(user_error,( between(1,3,M),wdmsg(M))),  wdmsg("hi"), fail.

% But really all along I assumed we wanted this:
:- meta_predicate with_output_to_scce(*,0).
with_output_to_scce(D,G):- current_output(W),scce_orig(set_output(D),G,set_output(W)).

% *Still* Fixed since "hi" was no longer sent to 'user_error' !   (However *this time* 2 and 3 *are* sent as expected)
scce_good:- with_output_to_scce(user_error,( between(1,3,M),wdmsg(M))), wdmsg("hi"), fail.

% ===================================================================
%  SCCE_V4
% ===================================================================
:- meta_predicate scce_idea(0,0,0).

scce_idea(S,G,C):-
  b_setval(setup_e_4,v(S,G,C)),
  nb_linkval(setup_e_4,v(S,G,C)),
  setup_call_cleanup(setup_f_4,
   (((G,deterministic(Det),true) *->
     (Det == true -> ! ; (cleanup_4;(setup_e_4,fail))))),
   cleanup_4), 
   (exit_4(S,G,C)).
  
exit_4(S,G,C):-nb_getval(cleanup_4,v(S1,G1,C1)),ignore(S=S1),ignore(G=G1),ignore(C=C1).

cleanup_4:- nb_getval(cleanup_4,v(_S1,_G1,C1)),call(C1).
setup_f_4:- 
  nb_getval(setup_e_4,Orig),Orig=v(S,_G,_C),
  copy_term(Orig,Copy),Copy=v(S0,G0,C0),  
  call(S0),nb_setval(cleanup_4,v(S,G0,C0)).
setup_e_4:- 
  nb_getval(setup_e_4,Orig),
  copy_term(Orig,v(S0,G0,C0)),
  call(S0),nb_setval(cleanup_4,v(S0,G0,C0)).

% :- set_prolog_flag(scce,pure).
% :- set_prolog_flag(scce,scce_orig).
% :- set_prolog_flag(scce,setup_call_cleanup).















% ===================================================================
%  Now unused versions
% ===================================================================

end_of_file.



setup0:-  nb_getval(in,IN),
	  IN  =  v(S1,G1,C1),
	  copy_term(S1,S2),
	  call(S1),	  
	  NEXT = v(S2,G1,C1),
	  nb_setval(in,NEXT).


setup2:-  nb_getval(in,IN),
	  IN  =  v(S1,G1,C1),
	  copy_term(S1,S2),
	  call(S1),	  
	  NEXT = v(S2,G1,C1),
	  nb_setval(in,NEXT).


scce2(S0,G0,C0):-
 IN = v(S0,G0,C0),
 ((quietly((
  nb_setval(orig,IN),
  nb_setval(blank_orig, BLANK_orig),  
  make_nb_setter(IN  , _, nb_setarg, BLANK_orig),
  nb_setval(in,IN),
  IN = v(S0,G0,C0),
  make_nb_setter(IN  , _, nb_setarg, BLANK_in),
  nb_setval(blank_in, BLANK_in))))),
    copy_term(S0+G0+C0,S9+_G9+_C9),
  % make_nb_setter(G0+S9+IN+C9+G9+C0+S0,UnsetSetup),
  setup2(S9),
  call(call,G0),
  ignore(cleanup2),
  setup2(S0),
  ignore(call(call,C0)).

cleanup2:- quietly(nb_getval(in,v(_,_,C))),call(C).
setup2(S0):- 
          quietly((nb_getval(in,IN),
	  IN  =  v(S0,G0,C0),
	  NX  =  v(S1,_G1,_C1),
	  copy_term(IN,NX))),
	  call_gvar(blank_in),
	  call(S0),
	  nb_setval(in,v(S1,G0,C0)).
	  


scce1(S0,G0,C0):- !,
  IN = v(S0,G0,C0,Vs),
  nop((UnsetSetup0,UnsetSetup1,UnsetSetup2)),
  term_variables(scce1(S0,G0,C0),Vs),
  nb_setval(in,IN),
  make_nb_setter(IN, BLANK_in),
  nb_setval(blank_in, BLANK_in),
  shared_vars(S0,(G0+C0),SGCVs), 
  copy_term(SGCVs,VC0), make_nb_setter5(SGCVs,VC0,nb_setarg,S0,UnsetSetup0),
  copy_term(SGCVs,VC1), make_nb_setter5(SGCVs,VC1,nb_setarg,(S0+G0),UnsetSetup1),
  copy_term(SGCVs,VC2), make_nb_setter5(SGCVs,VC2,nb_setarg,(S0+G0),UnsetSetup2),
  S = call(S0),
  G = (call(call,G0),quietly(UnsetSetup0)),
  C = (call(call,C0),quietly(UnsetSetup1)),
     catch((
        call((once(S0),G,deterministic(Det),true))
        *->
        (Det == true
         -> (once(C0),!)
          ; (once(C0);(once((UnsetSetup2,S))),fail))
     ; (once(C0),!,fail)),
     E, (ignore(once(C)),throw(E))).


scce1(S0,G0,C0):-
  IN = v(S0,G0,C0,Vs),
  term_variables(IN,Vs),
  nb_setval(in,IN),
  make_nb_setter(IN, BLANK_in),
  nb_setval(blank_in, BLANK_in),
  shared_vars(S0,(G0+C0),SGCVs), 
  copy_term(SGCVs,VC0),
  copy_term(SGCVs,VC1),
  make_nb_setter5(SGCVs,VC0,nb_setarg,IN,UnsetSetup0),
  make_nb_setter5(SGCVs,VC1,nb_setarg,IN,UnsetSetup1),
  !,
  setup1(true,S0),
  call(G0),
  ignore(C0),
  UnsetSetup0,
  setup1(UnsetSetup1,S0),
  call(C0).

  
cleanup1:- quietly(nb_getval(in,v(_,_,C,_))),call(C).

setup1(UnsetSetup,S0):-
        quietly((
	  nb_getval(in,IN),
	  IN  =  v(S0,G0,C0),
	  NX  =  v(S1,_G1,_C1),
	  copy_term(IN,NX))),
	  quietly(call_gvar(blank_in)),	
	  once(S0),
	  quietly(UnsetSetup),
	  nb_setval(in,v(S1,G0,C0)).


scce_idea(S0,G0,C0):-
    S = call(throw(sss)),
    G = call(throw(ggg)),
    C = call(throw(uuu)),
    MergeVars = ignore((arg(1,C,C0),arg(1,G,G0),arg(1,S,S0))),   
    S2 = ((\+ \+ ((nb_setarg(1,S,S0),nb_setarg(1,G,G0),nb_setarg(1,C,C0) )))),
    scce_orig(S2,(S2,MergeVars),(call(call,S),call(call,G)),(MergeVars,call(call,C))).

scce_idea(S0,G0,C0):-
    G = call(throw(ggg)),
    C = call(throw(uuu)),
    S = ((\+ \+ ((S0,nb_setarg(1,G,G0),nb_setarg(1,C,C0) ))),MergeVars = (arg(1,G,G0),MergeC), MergeC = arg(1,C,C0)),
    scce_orig(S,(nop(wdmsg(G)),nl,call(call,G)),(wdmsg(C),call(call,C),MergeVars,wdmsg(MergeVars))),MergeVars,nl.

scce_idea(S0,G0,C0):-
    S = call(S0),
    G = call(throw(ggg)),
    C = call(throw(uuu)),
    _MergeVars = ignore((arg(1,C,C0),arg(1,G,G0),arg(1,S,S0))),
    SU = ((\+ \+ ((nb_setarg(1,S,S0),nb_setarg(1,G,G0),nb_setarg(1,C,C0) )))),
    scce_orig(call(call,S),(SU,S),call(call,G),call(call,C)).


scce_idea(S,G,C):-
       term_variables(v(S,G,C),Vs),
       duplicate_term(v(S,G,C),v(SD,GD,CD)),
       gather_nb_setargs_goals(Vs,v(SD,GD,CD),NBSetargClosure),
       SEach = (\+ \+ ((SD,NBSetargClosure))),
       scce_orig(SEach,GD,CD).


scce_idea(S0,G0,C0):- fail,
     make_lkey(scc1(S0,G0,C0),Key),
     copy_term(scc1(S0,G0,C0),scc1(S1,G1,C1)),
     MergeVars = ignore((C1=C0,G1=G0,S1=S0)),
     S2 = ((\+ \+ ((nb_setarg(1,S,S0),nb_setarg(1,G,G0),nb_setarg(1,C,C0) )))),
     S = call(S2),
     G = call(G1),
     C = call(C1),
     S1,!,
     call((G,deterministic(Det),true))
        *->
        (Det == true
         -> (once(C),!)
          ; (once(C);(once(S),fail)))
     ; (once(C),!,fail)),
     E, (ignore(once(C)),throw(E)).


end_of_file.


get_vars:- nb_getval(setup,S),nb_getval(goal,G),nb_getval(cleanup,C),term_variables(v(S,G,C),Vs),nb_setval(sgcvars,Vs).
set_vars:- nb_getval(setup,S),nb_getval(goal,G),nb_getval(cleanup,C),term_variables(v(S,G,C),Vs),nb_getval(sgcvars,VVs),must(Vs=VVs).

merge_vars:- nb_getval(merge_vars,MV),call(MV).

call_gvar(Var):- nb_getval(Var,C),must(call(call,C)).

% goal_saved:- call_gvar(goal_saved).

use_undoer:- call_gvar(undoer).

% :- nb_setval(query_result,sol(0,1,false,false)).
with_no_dupies(G,List):-S=v([]),G,arg(1,S,Was),List=[CG|Was],copy_term(G,CG),nb_setarg(1,S,List).

:- dynamic(scce0/0).





  
/*


scce3(S0,G0,C0):- fail,
    G = call(throw(ggg)),
    C = call(throw(uuu)),

    shared_vars(S0,G0,SGvs),
    copy_term(S0+G0+SGvs,_CS0+_CG0+CSGvs),

    make_nb_setter(SGvs,CSGvs,G0,nb_setarg,SubSGs),

    S = ((\+ \+ ((S0,nb_setarg(1,G,G0),nb_setarg(1,C,C0) ))),

      scce_orig(S,(SubSGs,S),(call(call,G)),(call(call,C),UNSET)).
*/

scce3(S0,G0,C0):- !,

 quietly(( S = call(call,S0),
  G = call(call,G0),
  C = call(call,C0),
  UnSU = (UnS,nb_setarg(2,G,G0)),
  make_nb_setter(scce3(S,G,C),UnS))),

 quietly((

  nb_setval(orig,IN),
  IN = v(S0,G0,C0),
  nb_setval(blank_orig, BLANK_orig),  
  make_nb_setter(IN  , _, nb_setarg, BLANK_orig),

  nb_setval(in,IN),
  IN = v(S0,G0,C0),
  nb_setval(blank_in, BLANK_in),  
  make_nb_setter(IN  , _, nb_setarg, BLANK_in))),

     setup1,!,
       (call((G,deterministic(Det),true))
        *->
        (Det == true
         -> (once(C),!)
          ; (once(C);(once((UnSU,setup1)),fail)))
     ; (once(C),!,fail)).



scce11(S0,G0,C0):- 
  IN  =  v(S0,G0,C0),
  nb_setval(in,IN),  
  make_nb_setter(IN  , _BLANK, nb_setarg, BLANK_IN),
  nb_setval(blank_in,BLANK_IN),
  setup1,
  scce_orig(setup2,call_goal_saved_nd,cleanup).
  
call_scc1:- create_undoer,use_undoer,once(setup1),fail.
call_scc1:- call_goal_saved_nd *-> (cleanup ,(was_det->!;(setup2,fail))) ; (cleanup,!,fail).
% call_scc1:- repeat, once(setup2), call_goal_saved_nd *->cleanup; setupup2.

create_undoer:-
  nb_setval(in,v(S0,G0,C0)),
  make_nb_setter(v(S0,G0,C0),_,nb_setarg,Undoer),
  nb_setval(undoer,Undoer).











	

end_of_file.
scce1(S0,G0,C0):-
 quietly((
  nb_setval(orig,IN),
  nb_setval(blank_orig,BLANK_IN),  
    IN = v(S0,G0,C0),
  COPY = v(S1,G1,C1),
  NEXT = v(S2,G2,C2),
  make_nb_setter(IN  , _BLANK, nb_setarg, BLANK_IN),  
  copy_term(IN,COPY),
  copy_term(IN,NEXT) )),
  setup_call_cleanup(S0, G0 ,C0),
  ignore(IN = COPY),
  ignore(IN = NEXT).


scce_idea(_S2,G1,_C1):-
  (G1 *-> (cleanup ; (setup1,fail)) ; (cleanup,fail)).

scce_idea(S0,G0,C0):- 
  IN  =  v(S0,G0,C0),
  nb_setval(in,IN),  
  make_nb_setter(IN  , _BLANK, nb_setarg, BLANK_IN),
  nb_setval(blank_in,BLANK_IN),
  setup1,
  scce_orig(setup2,call_goal_saved_nd,cleanup).

  
/*
          OUT =  v(S0,G0,C0),
	     
	  make_nb_setter(IN  ,NEXT, nb_setarg, NEXT_TO_IN),
	  make_nb_setter(NEXT, OUT , nb_setarg,OUT_TO_NEXT),
	  make_nb_setter(IN  , OUT , arg,OUT_ARG_IN),


setup2:-  nb_getval(setup2,v(S1,G1,C1)),call(S1),nb_setval(in,v(S1,G1,C1)).

*/

  make_nb_setter(v(S0,G0,C0),_,nb_setarg,Undoer),
  copy_term(v(S0,G0,C0),v(SV,GV,CV)),
  make_nb_setter(v(S0,G0,C0),v(SV,GV,CV),nb_setarg,Undoer0),
  make_nb_setter(v(SV,GV,CV),v(S0,G0,C0),nb_setarg,Redoer0),
  make_nb_setter(v(SV,GV,CV),v(S0,G0,C0),arg,FillerIn),
  asserta((setup1:-  nb_getval(setup,S1),call(S1),get_vars,nb_setval(goal,G1),nb_setval(cleanup,C1))),
  asserta((setup2:-  nb_getval(setup,S2),call(S2),true,   ,nb_setval(goal,G2),nb_setval(cleanup,C2))),
  G = call(G0),
  nb_setval(goal_saved,G),
  scce_orig(in,setup2,goal_saved,cleanup).
  FillerIn.

  
  


  term_variables(scc1(S0,G0,C0),Vs0),
  copy_term(scc1(S0,G0,C0),scc1(SV,GV,CV)),
  term_variables(scc1(SV,GV,CV),VsV),
  nb_setval(merge_vars,Vs0=VsV),
  
  asserta((cleanup:- nb_getval(cleanup,C),merge_vars,call(C))),
  asserta((setup2:- nb_getval(setup,S2),S2,nb_setval(goal,G2),nb_setval(cleanup,C2))),

  scce_orig(in,call1,cleanup).

     make_lkey(scc1(S0,G0,C0),Key),
     copy_term(scc1(S0,G0,C0),scc1(S1,G1,C1)),
     MergeVars = ignore((C1=C0,G1=G0,S1=S0)),
     S2 = ((\+ \+ ((nb_setarg(1,S,S0),nb_setarg(1,G,G0),nb_setarg(1,C,C0) )))),
     S = call(S2),
     G = call(G1),
     C = call(C1),
     S1,!,     
    


scce(S,G,C):-
     scce_key(scce(S,G,C),Key),
     setup_call_cleanup_each(key_call(Key,1),key_call(Key,2),key_call(Key,3)).

key_call(Key,Arg):- nb_current(Key,In),arg(Arg,In,Goal),Goal,nb_setval(Key,In).
scce_key(In,Key):- format(atom(Key),'~q',[In]),nb_setval(Key,In).

% :- '$set_source_module'(system_scce).

