%% Son Tran's translator program - b2s.pl
%%
%% input:  a Prolog program representing an
%%         action theory in Language B
%% output: a lp-program in Lparse/Smodels syntax 
%%	   which can be used for planning or RAC 
%%
%% The b2s translator is currently capable of handling
%% the following features:
%%	
%% a. Dynamic Causal Laws of the form:
%%    causes(A,F,P) iff action A causes fluent literal F 
%%		        to be true if preconditions P hold.
%%
%& b. Static Causal Laws:
%%    caused(G,F) iff set of fluent literals G causes fluent  
%%	              literal F to be true.
%%
%% c. Executability conditions:
%%    executable(A,G) - A can be executed iff G holds
%%
%% d. Initial state:
%%    initially(F) iff fluent literal F holds in the initial state.  
%%
%% e. Goal state:
%%    goal(F) iff fluent literal F holds in the final state.
%%
%% Notice that b2s will only work correctly if the following
%% predicates are defined in the domain description input file:
%% 1. fluent(F) iff F is a fluent.
%% 2. action(A) iff A is an action.
%%

:- use_module(library(lists)).
:- use_module(library(system)).

unknown_predicate_handler(_,_,fail).

%%%
%%% Collecting the fluents and actions names
%%% and repeating them in the output file
%%%

pr_generals(Id) :-
	findall(X, fluent(X), L),
	findall(Y, action(Y), L1),
	nl(Id),
	write(Id,'%%% Fluents %%%%'),
        nl(Id), nl(Id),
	pr_fluents(L,Id), nl(Id),nl(Id),
	write(Id,'%%% Actions %%%%'),
        nl(Id),nl(Id),
	pr_actions(L1,Id),nl(Id).

pr_fluents([],Id) :-
	nl(Id),write(Id,'%%% End of Fluents %%%'),nl(Id).
pr_fluents([X|Y],Id) :-
	write(Id,fluent(X)),write(Id,'.'),nl(Id),
	pr_fluents(Y,Id).

pr_actions([],Id) :-
	nl(Id),write(Id,'%%% End of Actions %%%'),nl(Id).
pr_actions([X|Y],Id) :-
	write(Id,action(X)),write(Id,'.'),nl(Id),
	pr_actions(Y,Id).


%%%
%%% Collecting static causal laws
%%% and translating them into rules suitable for SMODELS
%%%

pr_static_causal(Id):-
        findall((X,Y),caused(X,Y),L),
        nl(Id),  
        write(Id, '%%% Section: static causal laws %%%%'), 
        nl(Id), 
        pr_static_causal(L, Id).

pr_static_causal([], Id):-
        nl(Id),  
        write(Id, '%%% End section: static causal laws %%%%'), nl(Id).

pr_static_causal([(L,C)|T], Id):-
	write(Id,'holds('), 
        write(Id,L), write(Id,', T):-  time(T), '),
        pr_causal_list(Id,C),
	nl(Id),
        pr_static_causal(T, Id).

pr_causal_list(Id,[]):- write(Id, '.').
pr_causal_list(Id,[H|T]):-
        write(Id,'holds('), 
        write(Id,H), write(Id,', T)'),
        length(T, N),
        (N > 0 -> write(Id,', ') | write(Id, '')),
        pr_causal_list(Id,T).

%%%
%%% Collecting dynamic causal laws 
%%% and translating them into rules suitable for SMODELS
%%%

pr_dynamic_causal(Id) :-
        findall((A,X,Y), causes(A,X,Y), Z),
        nl(Id),  
        write(Id, '%%% Section: dynamic causal laws %%%%'), 
        nl(Id),
        pr_dynamic_causal(Z, Id).

pr_dynamic_causal([], Id):-
        nl(Id),  
        write(Id, '%%% End section: dynamic causal laws %%%%'), nl(Id).

pr_dynamic_causal([(A,L,C)|T], Id):-
	write(Id,'holds('), 
        write(Id,L), write(Id,', T+1):- time(T), possible('),
        write(Id,A), write(Id,', T), '), 
        write(Id,'occ('), write(Id,A), write(Id,',T)'), 
        pr_condition_list(Id,C),
	nl(Id),
        pr_dynamic_causal(T, Id).

pr_condition_list(Id,[]):- write(Id, '.').
pr_condition_list(Id,[H|T]):-
        write(Id,', holds('), 
        write(Id,H), write(Id,', T)'),
        pr_condition_list(Id,T).


%%%
%%% Generating rules for each executability condition
%%%
%%%

pr_impossible(Id):-
        nl(Id), nl(Id),
        write(Id, '%%% Section: Executability Conditions %%'),
        findall((X,Y), executable(X,Y), Z),
        nl(Id),nl(Id),
        pr_item_executable(Z,Id).

pr_item_executable([],Id):-
        nl(Id),  
        write(Id, '%%% End of section: Executability Conditions %%%%'),
        nl(Id).

pr_item_executable([(A,L)|T],Id):-
        write(Id, 'possible('), write(Id, A), write(Id, ', T):- time(T)'),
        pr_condition_list(Id, L), nl(Id),
        pr_item_executable(T, Id).

%%%
%%% Generating initial rules for fluent literals
%%% one rule per fluent literal
%%%

pr_initial(Id) :-
        findall(X, (fluent(X),is_inertial(X)), Z),
     %   remove_dups(Z1, Z),
        nl(Id), 
        write(Id, '%%% Section: initial conditions are exogenous %%%%'),
        nl(Id), 
        pr_initial(Z, Id).

pr_initial([], Id):-
        nl(Id), 
        write(Id, '%%% End section: initial conditions are exogenous %%%%'),
        nl(Id).

pr_initial([L|T], Id):-
        pri_line(L, Id), nl(Id), 
        pri_line(neg(L), Id),nl(Id), 
        pr_initial(T, Id).

pri_line(H, Id):-
        fluent(H),
        add_time(H, '0', Id),
        write(Id, '  :-  not '),
        add_time(neg(H), '0', Id),
        write(Id, '.').

pri_line(neg(H), Id):-
        fluent(H),
        add_time(neg(H),'0', Id),
        write(Id, '  :-  not '),
        add_time(H, '0', Id),
        write(Id, '.').


%%%
%%% Generating rules for 'actions are exogenous'
%%% two rules for each action
%%%

pr_ex_action(Id):-
        findall(A, action(A), Z),
        nl(Id), 
        write(Id, '%%% Section: actions are exogenous %%%%'),
        nl(Id), 
        pr_ex_action(Z, Id).

pr_ex_action([], Id):-
        nl(Id), 
        write(Id, '%%% End of section: actions are exogenous %%%%'),
        nl(Id).

pr_ex_action([A|T], Id):-
        add_time(A, 'T', Id),
        write(Id, ' :-  time(T), not '),
        add_time(neg(A), 'T', Id),
        write(Id, '.'), nl(Id),
        add_time(neg(A), 'T', Id),
        write(Id, ' :-  time(T), not '),
        add_time(A, 'T', Id),
        write(Id, '.'), nl(Id),
        pr_ex_action(T, Id).



%%%
%%% Generating rules for section 'no actions are executed at last time'
%%% one per action
%%%

pr_no_action(Id):-
        findall(A, action(A), Z),
        nl(Id), nl(Id),
        write(Id, '%%% Section: no actions are executed at last time %%'),
        nl(Id),nl(Id),
        pr_no_action(Z, Id).

pr_no_action([], Id):-
        nl(Id),  
        write(Id, '%%% End of section: no actions are executed at last time %%%%'),
        nl(Id).

pr_no_action([A|T], Id):-
        write(Id, ':- '),
	write(Id, 'occ('),
	write(Id, A),write(Id,',lasttime).'),
        nl(Id),
        pr_no_action(T, Id).


%%%
%%% Adding the two auxiliary predicates to the domain file
%%%

pr_auxiliary(Id):-
	nl(Id),
        write(Id, '%%% Auxiliary predicates '),
        nl(Id), nl(Id),
        write(Id, 'time(0..lasttime).'),
        nl(Id),
        write(Id, 'next(T,T1):- time(T), time(T1), T1 = T + 1.'),
        nl(Id),
	write(Id, '1 { occ(X,T): action(X) } 1 :- time(T), T < lasttime.'),
	nl(Id),
	write(Id, 'fliteral(L) :- fluent(L).'),nl(Id),
	write(Id, 'fliteral(neg(L)) :- fluent(L).'),nl(Id).

%%%
%%% Generating rules for each constraint
%%%
%%%

pr_constraint(Id):-
        findall(X, constraint(X), Z),
        nl(Id), 
        write(Id, '%%% Section: Constraints %%'),
        nl(Id),
        pr_constraint(Z,Id).

pr_constraint([],Id):-
        nl(Id),  
        write(Id, '%%% End of section: Constraints %%%%'),
        nl(Id).

pr_constraint([A|T],Id):-
        write(Id, ':- time(T), '),
        add_time_list(A, 'T',Id),
        write(Id, '.'), nl(Id),
        pr_constraint(T,Id).


%%%
%%% Generating problem output file which includes
%%% the initial situation 
%%%

pr_initsit(Id) :-
	findall(I, initially(I), Z),
	nl(Id),
	write(Id, '%%% Initial Conditions %%%'),
	nl(Id), 
	pr_initsituation(Z,Id).

pr_initsituation([],Id):-
	nl(Id).

pr_initsituation([G|T],Id) :-
	write(Id,'holds('),
	write(Id,G),
	write(Id,',0).'),nl(Id),
	pr_initsituation(T,Id).


%%%
%%% Generating problem output file which includes
%%% the initial situation 
%%%

pr_goal(Id) :-
	findall(I, finally(I), Z),
	nl(Id),
	write(Id, '%%% Goal %%%'),
	nl(Id), 
	pr_finalsituation(Z,Id).

pr_finalsituation([],Id):-
        nl(Id),
	write(Id, '%%% End Goal %%%'),
	nl(Id).

pr_finalsituation([G|T],Id) :-
	write(Id,':- not holds('),
	write(Id,G),
	write(Id,',length).'),nl(Id),
	pr_finalsituation(T,Id).

eq(X,X).
neq(X,Y):- \+ eq(X,Y).

%%%
%%% for SICStus program 
%%%


gen:-
        write(' Enter domain description file name: '),
     	read(S),
	name(S,Chars),
	name(smo,Chars1),
	append(Chars,[46|Chars1],Chars2),
	name(S1,Chars2),
	absolute_file_name(S, Source), %%% get the source file name
	consult(Source),
	absolute_file_name(S1, FileDescr), %%% get the domain output file name
        write(' Generating .... '),
        open(FileDescr, write , X),
	write(X,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'),
        nl(X),
	write(X,'%%%%    Domain Description               %%%%%'),
        nl(X),
	write(X,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%'),
        nl(X),
        pr_generals(X),
        pr_static_causal(X),
        pr_dynamic_causal(X),
	pr_impossible(X),
	pr_initsit(X),
        pr_goal(X),
        close(X).

