/*
mest :-
	[multi], tell( mout ), multi25(a,1/2,P), write( P ), told, halt.
    */

% pdf_demo
% 
% Start the pdf meta-interpreter.
%
pfd_demo :-
	write_pfd_messages,
	catch( 
	 	demo1,
		Exception,
		demo_exception(Exception)  
		).

demo1 :-
	% prompt( _Old, 'pfd | ?- ' ),
	% read_term( user, Term, [variable_names(Vars)]  ),
	on_pl( yap(_Asics1),
		( write( user_error, 'pfd | ?- ' ),
		  read_term( Term, [variable_names(Vars)])) ),
	on_pl( sicstus(_Asics2),
		( write( user_error, 'pfd | ?- ' ),
		  read_term( Term, [variable_names(Vars)])) ),
	on_pl( swi(_Any), 
		read_history( hist, '!h', [], 'pfd | ?- ', Term, Vars ) ),
	demo1( Term, Vars ).

demo1 :-
	nl, write( nope ), nl,
	demo1.

demo1( Term, _Vars ) :-
	shell_built_in( Term ),
	!,
	demo1.
demo1( Term, Vars ) :-
	aux_goal_tuple_to_list( Term, TermList ),
	bb_put( vars_with_mass_loss_fun, [] ),
	store_built( [vs(Vars)], StoreInit ), 
	demo(TermList,StoreInit),
	nl, write( yea ), nl, demo1.

pfd_demo( Goals ) :-
	store_built( [], StoreInit ),
	demo( Goals, StoreInit ).

demo( Goals, InitStore ) :-
	demo( Goals, InitStore, FinalStore ),
	store_enquire( FinalStore, [vs(Vars),act(Active)] ),
	aux_map_variables( Vars, Active, PfdVars ),
	aux_solution( PfdVars ).

demo_on_empty( Goals ) :-
	store_built( [], StoreInit ), 
	demo( Goals, StoreInit, _NoRrqd ).
	
demo( [], Store, Store  ) :-
	!.
demo( Goals, InStore, OutStore ) :-
	aux_goal_select( Goals, Goal, RestGoals ),
    debug( pfd(demo), 'Demo selected goal: ~w', [Goal] ),
	% dbg( goal(Goal) ),
	( shell_built_in( Goal ) -> 
		NxGoals = RestGoals, NxStore = InStore
		;
	% 	( \+ \+ pfd_rule(Goal,_NBcBody) ->
	 	( pfd_predicate(Goal) ->
			pfd_rule( Goal, Body ),
			aux_body_and_goals( Body, RestGoals, NxGoals ),
			NxStore = InStore
			;
			( (constraints( Constraints ),
			    memberchk( Goal, Constraints )) -> 
					constraint_to_store( Goal, InStore, NxStore ),
					NxGoals = RestGoals
					;
					prolog_predicate( Goal, InStore, NxStore, MoreGoals ),
					aux_body_and_goals( MoreGoals, RestGoals, NxGoals )
			)
		)
	),
	% dbg( nx_store ), write_store( NxStore ),
	demo( NxGoals, NxStore, OutStore ).

demo1_non_i( Term, Vars ) :-
	( bb_get(pfd_not_interactive,Old) ->
		true
		;
		Old = false
	),
	bb_put( pfd_not_interactive, true ),
	( demo1( Term, Vars ) ; (nl, write( nope ), nl) ),
	bb_put( pfd_not_interactive, Old  ).

pfd_call_once( Pred ) :-
	( pfd_predicate( Pred ) -> 
		demo_on_empty( [Pred] )
		;
		call( Pred )
	),
	!.
	
prolog_predicate( (Cond->IfTuple;ThenTuple), _Store, Goals ) :-
	!,
	( call(Cond) -> 
		aux_tuple_to_list( IfTuple, Goals )
		;
		aux_tuple_to_list( ThenTuple, Goals )
	).

prolog_predicate( findall(V, Meta, Vs), Store, Store, Goals ):-
	 !,
	 DemoMeta =.. [demo,[Meta],Store,_OutStore],
	 call( findall(V, DemoMeta, Vs) ),
	 Goals = [].

% prolog_predicate( Prb is Goal, InStore, OutStore, [] ) :-
	% write( (Prb,is,Goal) ), nl, abort
	% !,
	% demo( Goal, [], InStore, OutStore ).
% prolog_predicate( is(Prb,Goal), InStore, OutStore, [] ) :-
	% write( is(Prb,Goal) ), nl, abort
	% !,
	% demo( Goal, [], InStore, OutStore ).
prolog_predicate( call(Goal), InStore, OutStore, [] ) :-
	!,
	demo( Goal, [], InStore, OutStore ).

% prolog_predicate( V1 #\= V2, InStore, OutStore, [] ) :-
% add edges V1 <-> V2 to gr() in InSore
% call( V1 #\= V2 )
% but probably dont modify roots (rts() in InStore)
% add the extra connected to active in constraint_to_store, prob(,)

prolog_predicate( Goal, Store, Store, MoreGoals ) :-
	% catch_all
	call(Goal),
	MoreGoals = [].

copy_goal( Goal, FOGoal, NbcGoal ) :-
	\+ var(Goal), 	% Oct 25, 1999, addition.
	( Goal = meta(FOGoal) ->
		true
		;
		FOGoal = Goal
	),
	copy_term( FOGoal, NbcGoal ).

shell_built_in( h )  :- 
	shell_built_in( help ).

shell_built_in( help ) :-
	!,
	write_pfd_messages.
	% BuiltIns = ['(h)elp',restart,listing,exit,halt],
	% write( BuiltIns ), nl.

shell_built_in( restart ) :-
	retractall( (pfd_rule(_A,_B)) ).
	% clause( probabilistic_method(register(NoOfPreds)), _Body ),
	% retractall_but( (probabilistic_method(_C)), NoOfPreds ).
shell_built_in( listing ) :-
	\+ list_pfd_rule.
shell_built_in( end_of_file ) :-
    !,
    shell_built_in( exit ).
shell_built_in( exit ) :-
	nl,
	write( user_error, 'Type \'pfd_demo.\' to re-enter pfd.' ),
	nl, nl,
	throw( pfd(exit) ).
shell_built_in( halt ) :-
	write( user_error, bye_t_bye ), nl,
	throw(pfd(halt)).

list_pfd_rule :-
	pfd_rule( A, B ),
	( list_to_body( B, BList ) ->
		portray_clause( (A:-BList) )
		;
		portray_clause( A )
	),
	fail.

list_to_body( [H,S|T], (H,M) ) :-
	list_to_body( [S|T], M ).
list_to_body( [H], H ).
list_to_body( [], true ).

write_pfd_messages :-
	nl,
	pfd_message( Message ), 
	write( Message ), nl, 
	fail.
write_pfd_messages :- nl.

constraints( [
	domain_cardinality(_,_),
	static_distribution(_,_),
	label_n(_,_,_,_,_),
	label(_,_,_,_),
	label(_,_,_,_),
	% prin(_,_),
	% pin(_,_),
	~(_,_),
	% fpin(_,_),
	~~(_,_),
	% pinl(_,_),
	~-(_,_),
	% fpinl(_,_),
	~~-(_,_),
	pfd_spy(_),
	conditional(_,_,_),
	conditional(_,_),
	cond_diff(_,_,_),
	prob(_,_)
	] ).
