?- op(500, xfx, '##'). % For parallel % Was '||'
?- op(500, xfx, '>>'). % For triangle  % Was '|>'
?- op(500, xfx, '++' ). % For sequence % Was '}}'
?- op(500, xfx, '::' ). % For blocking wait 
?- op(500, xfx, ':' ).  % For checking wait
%% Had some different operators for the previous version. Work out how to unify these. 

reduce(N, State) :- reduce(N, State, full, []). 

% reduce(_, state(B, G), _Output_Type, _Events) :-
%         (G = []), 
%  	format("Nothing more to execute.~n", []),
%  	output_state(state(B,[])), nl.

reduce(N, state(B,G), Output_Type, Events) :- 
%  	G \= [],
	% output_state(state(B,G)), 
	revise(N, state(B,G), Events, NewEvents, Output_Type, RevisedState, Status), !, 
	% format("Revised state is ", []), writeln(RevisedState), 
	N1 is N+1, 
	proceed_or_halt(N1, RevisedState, NewEvents, Output_Type, Status).

revise(N, state(B,G), Events, NewEvents, full, state(NewB, NewG), Status) :-
        Events = [], !, NewEvents = [], 
        format("-----------------------------------------------------~n", []), 
        format("~d: Events? ([]. for no change, [halt]. to halt): ", [N]), ttyflush, 
       	read(Term), process(Term, List), 
        process_events(List, state(B,G), state(NewB, NewG), Status).

revise(N, state(B,G), Events, NewEvents, minimal, state(NewB, NewG), Status) :-
        Events = [], !, NewEvents = [], 
        format("-----------------------------------------------------~n", []), 
        format("~d: Events? ([]. for no change, [halt]. to halt): ", [N]), ttyflush, 
       	read(Term), process(Term, List), 
        process_events(List, state(B,G), state(NewB, NewG), Status).

revise(N, state(B,G), Events, NewEvents, full, state(NewB, NewG), Status) :-
        Events = none, !, NewEvents = none, 
        format("-----------------------------------------------------~n", []), 
        format("~d: No events~n", [N]), 
        process_events([], state(B,G), state(NewB, NewG), Status).

revise(N, state(B,G), Events, NewEvents, minimal, state(NewB, NewG), Status) :-
        Events = none, !, NewEvents = none, 
        format("-----------------------------------------------------~n", []), 
        format("~d: No events~n", [N]), 
        process_events([], state(B,G), state(NewB, NewG), Status).

revise(N, state(B,G), Events, NewEvents, full, state(NewB, NewG), Status) :-
        Events = [Term|NewEvents], process(Term, Next), !, 
        format("-----------------------------------------------------~n", []), 
        format("~d: Events are ", [N]), write(Term), nl, 
        process_events(Next, state(B,G), state(NewB, NewG), Status).

revise(_N, state(B,G), Events, NewEvents, minimal, state(NewB, NewG), Status) :-
        Events = [Term|NewEvents], process(Term, Next), 
        Term = [], !, 
        process_events(Next, state(B,G), state(NewB, NewG), Status).

revise(N, state(B,G), Events, NewEvents, minimal, state(NewB, NewG), Status) :-
        Events = [Term|NewEvents], process(Term, Next), Term \== [], !, 
        format("-----------------------------------------------------~n", []), 
        format("~d: Events are ", [N]), write(Term), nl, 
        process_events(Next, state(B,G), state(NewB, NewG), Status).

process_events([], State, State, continue).
process_events([ev(halt)|_Rest], state(B,G), state(B, G), halt).
process_events([ev(Event)|Rest], state(B,G), state(NewB, NewG), Status) :-
	Event \= halt, 
	% format("Processing event ~k~n", [Event]), writeln(B), writeln(G),  
        process_event(Event, state(B,G), state(NB,NG)),
	% format("Processed event ~k~n", [Event]), ttyflush, 
        process_events(Rest, state(NB,NG), state(NewB, NewG), Status).

process_event(Event, state(B,G), state(NewB,NewG)) :-
        % format("Searching for event ~k~n", [Event]), 
        event(Event, Belief_Updates, Goal_Additions), % format("Event ~k found~n", [Event]), 
        update_beliefs(B, Belief_Updates, NewB), % format("Beliefs updated ~n", []), 
        append(Goal_Additions, G, NewG), % format("New Goals are ", []), writeln(NewG),
        true.  

prioritise(P,P). % To allow for altering order in which these are done. 

process([],[]).  % To allow for more sophisticated processing. 
process([Event|Rest],[ev(Event)|Others]) :- 
	process(Rest, Others). 

proceed_or_halt(_, State, _Events, _, halt) :-
        format("Halt event detected~n", []), !, 
	output_state(State), nl.
proceed_or_halt(N, State, Events, Output_Type, Status):-
	Status \= halt, 
	( Output_Type == full -> output_state(nores, State); true ), 
	
	% format("Reducing ... ~n", []), 
	reduce_goals(State, TempState1), !,  % Replace with stub if not wanted
	% format("Planning goals ... ", []),  % TempState1 = state(_, Plans1), writeln(Plans1), 
	plan_goals(TempState1, TempState2), !,  % format("Planned to ", []), TempState2 = state(_, Plans2), writeln(Plans2),
	% format("Executing ... ~n", []), % TempState2 = state(_, Plans2), writeln(Plans2),
	execute_state(N, TempState2, NewState), !,   
	
	status_update(NewState), %% Include Output_Type here?? 

	!, 
        reduce(N, NewState, Output_Type, Events). 

reduce_goals(state(B,G), NewState) :-
	reduce_goal(B, [], G, NewG, NewB, nochange, Status), 
	reduce_or_halt(NewB, NewG, Status, NewState).

reduce_or_halt(B, G, nochange, state(B,G)) :-
	format("No more goal changes~n", []). 

reduce_or_halt(B, G, update, NewState) :-
	% format("Reducing again ... ~n", []), output_state(nores, state(B,G)), 
	!, 
	reduce_goals(state(B,G), NewState). 

% Each element in Remainder is a Plan Step, and hence needs to be generalised to this .... 

reduce_goal(B, SoFar, [], SoFar, B, Status, Status) :-
    % format("Finished reducing ", []), writeln(SoFar),
    true. 
reduce_goal(B, SoFar, [Plan|Others], NewPlans, NewB, Status, NewStatus) :-
    % format("Now reducing ", []), writeln(Plan), 
    reduce_goal1(B, Plan, NB, NewPlan, PlanStatus), % format("Reduced step ", []), write(Plan), format(" to ", []), writeln(NewPlan), 
    update_status(PlanStatus, Status, NStatus), 
    append(SoFar, [NewPlan], NewSoFar), % format("Calling reduce_goal with ", []), writeln(Others),    
    % writeln(NB), write(NewSoFar), format("+", []), write(Others), 
    % write(NewPlans), write(NewB), write(NStatus), write(NewStatus), nl, 
    reduce_goal(NB, NewSoFar, Others, NewPlans, NewB, NStatus, NewStatus), % format("Done~n", []), 
    true. 

update_status(nochange, nochange, nochange). 
update_status(nochange, update, update). 
update_status(update, nochange, update). 
update_status(update, update, update). 

reduce_goal1(B, Step, B, Step, nochange) :- 
	Step \= g(_,_,_), % Step is not a goal
	(member(Step, [nil, fail, ask(_), add(_), del(_), ev(_),abort(_),suspend(_),resume(_),failed(_),active(_),suspended(_)]); is_action(Step); plan(Step, _, _)), 
	true. % Means it can't contain any goals, so no change.

reduce_goal1(B, Step, NewB, NewStep, Status) :- 
	Step \= g(_,_,_), % Step is not a goal
	Step = Guard::Body, %% Body is a list of plan steps ... 
	reduce_goal(B, [], Body, NewBody, NewB, nochange, Status),
	NewStep = Guard::NewBody. 

reduce_goal1(B, Step, NewB, NewStep, Status) :- 
	Step \= g(_,_,_), % Step is not a goal
	Step = Guard:Body, %% Body is a list of plan steps ... 
	reduce_goal(B, [], Body, NewBody, NewB, nochange, Status),
	NewStep = Guard:NewBody. 

reduce_goal1(B, Step, NewB, NewStep, Status) :- 
	Step \= g(_,_,_), % Step is not a goal
	Step = (P1 ++ P2), %% P1, P2 are lists of plan steps ... 
	reduce_goal(B, [], P1, NewP1, NB1, nochange, Status1),
	reduce_goal(NB1, [], P2, NewP2, NB2, Status1, Status2),
	NewStep = (NewP1 ++ NewP2),
	NewB = NB2,
	Status = Status2. 

reduce_goal1(B, Step, NewB, NewStep, Status) :- 
	Step \= g(_,_,_), % Step is not a goal
	Step = (P1 ## P2), %% P1, P2 are lists of plan steps ... 
	reduce_goal(B, [], P1, NewP1, NB1, nochange, Status1),
	reduce_goal(NB1, [], P2, NewP2, NB2, Status1, Status2),
	NewStep = (NewP1 ## NewP2),
	NewB = NB2,
	Status = Status2. 

reduce_goal1(B, Step, NewB, NewStep, Status) :- 
	Step \= g(_,_,_), % Step is not a goal
	Step = (P1 >> P2), %% P1, P2 are lists of plan steps ... 
	reduce_goal(B, [], P1, NewP1, NB1, nochange, Status1),
	reduce_goal(NB1, [], P2, NewP2, NB2, Status1, Status2),
	NewStep = (NewP1 >> NewP2),
	NewB = NB2,
	Status = Status2. 

reduce_goal1(B, Step, NewB, NewStep, Status) :- 
	Step \= g(_,_,_), % Step is not a goal
	Step = select(Plans), %% Plans is a list of plan steps ... 
	reduce_goal(B, [], Plans, NewPlans, NewB, nochange, Status),
	NewStep = select(NewPlans). 

% Step is now a goal for the cases below. 

reduce_goal1(B, Step, NewB, NewStep, update) :- 
        Step = g(Name, Status, _Plan),
	goal(Name, Goal, _, _, Rules, _Plans), 
	goal_type(Goal, GoalType), 
	goal_action(Name, GoalType, Status, B, NewB, Rules, Action),
	member(Action, [drop]), % rule 7
	format("Goal ~k ~k: ~k -> ~k~n", [Name, Action, Status, dropped]), !, 
	NewStep = nil, 
	true. 

reduce_goal1(B, Step, NewB, NewStep, update) :- 
        Step = g(Name, Status, _Plan),
	goal(Name, Goal, _, _, Rules, _Plans), 
	goal_type(Goal, GoalType), 
	goal_action(Name, GoalType, Status, B, NewB, Rules, Action),
	member(Action, [abort]), % rule 7  % In case we want to differentiate between dropping and aborting
	format("Goal ~k ~k: ~k -> ~k~n", [Name, Action, Status, aborted]), !, 
	NewStep = nil, 
	true. 

reduce_goal1(B, Step, NewB, NewStep, update) :- 
        Step = g(Name, pending, Plan),
	goal(Name, Goal, _, _, Rules, _Plans), % format("(achieve) Step is ", []), writeln(Step), 
        goal_type(Goal, GoalType), member(GoalType, [perform, achieve]), 
        % format("Reduce goal state achieve 2~n", []), ttyflush,  
	goal_action(Name, GoalType, pending, B, NewB, Rules, Action), 
	member(Action, [activate]),	% format("Action is activate~n", []), ttyflush, 
	format("Goal ~k ~k: ~k -> ~k~n", [Name, Action, pending, active]), ttyflush, !, 
	NewStep = g(Name, active, Plan),  % rule 1
	true. 

reduce_goal1(B, Step, NewB, NewStep, update) :- 
        Step = g(Name, pending, Plan),
	goal(Name, Goal, _, _, Rules, _Plans), % format("Step is ", []), writeln(Step), 
        % format("Reduce goal state 3~n", []),  ttyflush, 
        % format("Checking goal type~n", []),  ttyflush, 
        goal_type(Goal, GoalType), member(GoalType, [maintain]), 
	goal_action(Name, GoalType, pending, B, NewB, Rules, Action),
        % format("Activating maintain goal~n", []),  ttyflush, 
	member(Action, [activate]),
	format("Goal ~k ~k: ~k -> ~k~n", [Name, Action, pending, monitoring]), !, 
	NewStep = g(Name, monitoring, Plan), % rule ?
	true. 

reduce_goal1(B, Step, NewNewB, NewStep, update) :- 
        Step = g(Name, monitoring, _Plan),
	goal(Name, Goal, _, _, Rules, _Plans), % format("Step is ", []), writeln(Step), 
        goal_type(Goal, GoalType), member(GoalType, [maintain]), 
        % format("Reduce goal state 4~n", []), 
	goal_action(Name, GoalType, monitoring, B, NewB, Rules, Action),
	member(Action, [respond]),
        % format("Responding~n", []), 
 	Goal = maintain(_Condition, MC, Recover, Prevent, _Succ, _Fail), 
        choose_goal(B, MC, Recover, Prevent, Chosen), 
	format("Goal ~k ~k: ~k -> ~k~n", [Name, Action, monitoring, active]), !, 
%%% New stuff is below ... 
        format("Chosen goal is ", []), writeln(Chosen), 
	update_beliefs(NewB, [add(activate(Chosen))], NewNewB), 
	NewStep = g(Name, active, [goal(Chosen)]),
	true. 

reduce_goal1(B, Step, NewB, NewStep, update) :- 
        Step = g(Name, active, _Plan),
	goal(Name, Goal, _, _, Rules, _Plans), % format("Step is ", []), writeln(Step), 
        goal_type(Goal, GoalType), member(GoalType, [maintain]), 
	goal_action(Name, GoalType, active, B, NewB, Rules, Action),
	member(Action, [reactivate]),
	format("Goal ~k ~k: ~k -> ~k~n", [Name, Action, active, monitoring]), 
	NewStep = g(Name, monitoring, empty),
	true. 

reduce_goal1(B, Step, NewB, NewStep, update) :- 
        Step = g(Name, suspended, Plan),
	goal(Name, Goal, _, _, Rules, _Plans), % format("Step is ", []), writeln(Step), 
        goal_type(Goal, GoalType), member(GoalType, [maintain]), 
	goal_action(Name, GoalType, suspended, B, NewB, Rules, Action),
	member(Action, [reactivate]),
	format("Goal ~k ~k: ~k -> ~k~n", [Name, Action, suspended, monitoring]), 
	NewStep = g(Name, monitoring, Plan), % rule ?
	true. 

reduce_goal1(B, Step, NewB, NewStep, update) :- 
        Step = g(Name, suspended, Plan),
	goal(Name, Goal, _,  _, Rules, _Plans), % format("Step is ", []), writeln(Step), 
        goal_type(Goal, GoalType), member(GoalType, [perform, achieve]), 
	goal_action(Name, GoalType, suspended, B, NewB, Rules, Action),
	member(Action, [reactivate]),
	format("Goal ~k ~k: ~k -> ~k~n", [Name, Action, suspended, active]), !, 
	NewStep = g(Name, active, Plan), % rule ?
	true. 

reduce_goal1(B, Step, NewB, NewStep, update) :- 
        Step = g(Name, suspended, Plan),
	goal(Name, Goal, _, _, Rules, _Plans), % format("Step is ", []), writeln(Step), 
        goal_type(Goal, GoalType), member(GoalType, [perform, achieve]), 
	goal_action(Name, GoalType, suspended, B, NewB, Rules, Action),
	member(Action, [reconsider]),
	format("Goal ~k ~k: ~k -> ~k~n", [Name, Action, suspended, pending]), !, 
	NewStep = g(Name, pending, Plan), % rule ?
	true. 

reduce_goal1(B, Step, NewB, NewStep, update) :- 
        Step = g(Name, Status, Plan),
	goal(Name, Goal, _, _, Rules, _Plans), % format("Step is ", []), writeln(Step), 
	member(Status, [pending,active]), 
        goal_type(Goal, GoalType), member(GoalType, [perform, achieve]), 
	goal_action(Name, GoalType, Status, B, NewB, Rules, Action),
	member(Action, [suspend]),
	format("Goal ~k ~k: ~k -> ~k~n", [Name, Action, Status, suspended]), !, 
        % rec_rules(Name, Status, Rules, Rules2), 
	NewStep = g(Name, suspended, Plan), % rule ?
	true. 

reduce_goal1(B, Step, B, NewStep, update) :- 
        Step = goal(Name), %% Need to start goal ... 
	format("Goal ~k made pending~n", [Name]), 
	NewStep = g(Name, pending, empty), !, 
	true. 

reduce_goal1(B, Step, NewB, Step, nochange) :- 
        Step = g(Name, Status, _Plan), Status \= active, 
	goal(Name, Goal, _, _, Rules, _Plans), % format("Step is ", []), writeln(Step), 
	goal_type(Goal, GoalType), 
	% format("Step is ", []), writeln(Step), 
	goal_action(Name, GoalType, Status, B, NewB, Rules, Action), 
	member(Action, [no_action]), !, 
        % format("~k stable ~n", [Name]), 
	true. 

reduce_goal1(B, Step, NewB, Step, nochange) :- 
        Step = g(Name, active, empty),
	goal(Name, Goal, _, _, Rules, _Plans), % format("Step is ", []), writeln(Step), 
	goal_type(Goal, GoalType), 
	% format("Step is ", []), writeln(Step), 
	goal_action(Name, GoalType, active, B, NewB, Rules, Action), % format("Goal action is ~k for ~k in state ~k~n", [Action,Name,active]),
	member(Action, [no_action]), !, 
        % format("~k stable ~n", [Name]), 
	true. 

reduce_goal1(B, Step, NewB, NewStep, Status) :- 
        Step = g(Name, active, Plan), Plan \= empty,
	goal(Name, Goal, _, _, Rules, _Plans), % format("Step is ", []), writeln(Step), 
	goal_type(Goal, GoalType), 
	goal_action(Name, GoalType, active, B, NB, Rules, Action), 
	member(Action, [no_action]), % No change for this goal, but there may be for subgoals ... 
	% format("Reducing subgoals of active goal~k ", [Name]), writeln(Plan), 
	reduce_goal(NB, [], Plan, NewPlan, NewB, nochange, Status),
	% format("Reduced subgoals ", []), write(Plan), format(" to ", []), writeln(NewPlan), 
	NewStep = g(Name, active, NewPlan), !, 
	true. 

% reduce_goal(B, SoFar, [], State, nochange) :-
% 	format("All goals stable~n", []),
% 	State = state(B,SoFar). 

%% Need to add rules for stopping plans executing when there is a goal change. (8a,8b,9,10). 

choose_goal(B, MC, _Recover, Prevent, Prevent) :- implies(B, MC).
choose_goal(B, MC, Recover, _Prevent, Recover) :- \+ implies(B, MC).

goal_action(Name, GoalType, Status, B, NewB, Rules, Action) :-
	member(act(Cond,Action), Rules),
	member(C, Cond), convert(C, Condition), 
	implies(B, Condition),
	applicable_action(GoalType, Status, Action),
        % format("Applying action ~k to ~k in state ~k because of ", [Action,Name,Status]), writeln(Cond),
        % writeln(B), 
        update_action_beliefs(Name, GoalType, B, Action, NewB).         

goal_action(_Name, GoalType, Status, B, B, Rules, no_action) :-
 	\+ (member(act(Cond,Action), Rules), member(C, Cond), implies(B, C), applicable_action(GoalType, Status, Action)). 

convert(C, C) :- C = [_|_]. % Already a list 
convert(C, [C]) :- C \= [_|_]. 

% applicable(GoalType, Status, Action)
applicable_action(_, _, drop). 
applicable_action(_, _, abort). 
applicable_action(_, pending, activate). 
applicable_action(_, pending, suspend). 
applicable_action(_, active, suspend). 
applicable_action(maintain, monitoring, suspend). 
applicable_action(maintain, monitoring, respond). 
applicable_action(maintain, suspended, rerespond). 
applicable_action(maintain, active, reactivate). 
applicable_action(_, suspended, reactivate). 
applicable_action(_, suspended, reconsider). 
% See four-state diagram

update_action_beliefs(Name, GoalType, B, Action, NewB) :- 
	update_action_beliefs1(Name, B, Action, NB1), % deal with events
	update_goal_beliefs(Name, GoalType, NB1, Action, NewB), % keep track of goal state changes,
	true. 

update_action_beliefs1(Name, B, Action, NewB) :-
       member(Action, [drop, abort, suspend, activate, reactivate, reconsider]),
       Bel =.. [Action,Name], 
       % format("Deleting ~k(~k)~n", [Action,Name]), 
       update_beliefs(B, [del(Bel)], NewB).

update_action_beliefs1(_Name, B, Action, B) :-
       \+ member(Action, [drop, abort, suspend, activate, reactivate, reconsider]).

% Bit of a hack ... could be done nore simply ... 
update_goal_beliefs(Name, achieve, B, activate, NewB) :-
	update_beliefs(B, [add(active(Name))], NewB).
update_goal_beliefs(Name, achieve, B, suspend, NewB) :-
	update_beliefs(B, [del(active(Name)), add(suspended(Name))], NewB).
update_goal_beliefs(Name, achieve, B, Action, NewB) :-
	member(Action, [drop]), 
	% Bit of a hack, but will do for now ... 
	update_beliefs(B, [del(active(Name)), del(suspended(Name)), add(completed(Name))], NewB).
update_goal_beliefs(Name, achieve, B, Action, NewB) :-
	member(Action, [abort]), 
	update_beliefs(B, [del(active(Name)), del(suspended(Name))], NewB).
update_goal_beliefs(Name, achieve, B, reactivate, NewB) :-
	update_beliefs(B, [del(suspended(Name)), add(active(Name))], NewB).
update_goal_beliefs(Name, achieve, B, reconsider, NewB) :-
	update_beliefs(B, [del(suspended(Name))], NewB).
update_goal_beliefs(_Name, achieve, B, Action, B) :-
	\+ member(Action, [drop, abort, suspend, activate, reactivate, reconsider]). 

update_goal_beliefs(Name, maintain, B, respond, NewB) :-
	update_beliefs(B, [add(active(Name))], NewB). 
update_goal_beliefs(Name, maintain, B, suspend, NewB) :-
	update_beliefs(B, [add(suspended(Name)), del(active(Name))], NewB). 
update_goal_beliefs(Name, maintain, B, reactivate, NewB) :-
	update_beliefs(B, [del(active(Name)), del(suspended(Name))], NewB). 
update_goal_beliefs(Name, maintain, B, reconsider, NewB) :-
	update_beliefs(B, [del(suspended(Name))], NewB). 
update_goal_beliefs(Name, maintain, B, Action, NewB) :-
	member(Action, [drop, abort]), 
	update_beliefs(B, [del(active(Name)), del(suspended(Name))], NewB).
update_goal_beliefs(_Name, maintain, B, Action, B) :-
	\+ member(Action, [drop, abort, suspend, respond, reactivate, reconsider]). 

% reduce_goal(B, SoFar, [], SoFar, B, Status, Status). 
% reduce_goal(B, SoFar, [Plan|Others], Result, NewB, Status, NewStatus) :-
%     reduce_goal1(B, Plan, NB, NewPlan, PlanStatus), 
%     update_status(PlanStatus, Status, NStatus), 
%     append(SoFar, [NewPlan], NewSoFar), 
%     reduce_goal(NB, NewSoFar, Others, Result, NewB, NStatus, NewStatus),
%     true. 

% Find more plans, when needed, or drop goals for which no (more) plans can be found
plan_goals(state(B,G), state(B, NewG)) :-
        plan_goals1(B, [], G, NewG).

plan_goals1(_B, SoFar, [], SoFar). 
plan_goals1(B, SoFar, [Plan|Others], NewG) :-
    plan_each_goal(B, Plan, NG), % format("Planned goal ", []), writeln(NG), 
    append(SoFar, [NG], NewSoFar), % format("Now trying ", []), writeln(Others), 
    plan_goals1(B, NewSoFar, Others, NewG). 

% Non-goal cases 
plan_each_goal(B, Step, Step) :-
        Step \= g(_Name, _Status, _Plan),
	(member(Step, [nil, fail, ask(_), add(_), del(_), ev(_),abort(_),suspend(_),resume(_),failed(_),active(_),suspended(_)]); is_action(Step); plan(Step, _, _)), 
	true. % Means it can't contain any goals, so no change.

plan_each_goal(B, Step, NewStep) :- 
	Step \= g(_,_,_), % Step is not a goal
	Step = Guard::Body, %% Body is a list of plan steps ... 
	plan_goals1(B, [], Body, NewBody),
	NewStep = Guard::NewBody. 

plan_each_goal(B, Step, NewStep) :- 
	Step \= g(_,_,_), % Step is not a goal
	Step = Guard:Body, %% Body is a list of plan steps ... 
	plan_goals1(B, [], Body, NewBody),
	NewStep = Guard:NewBody. 

plan_each_goal(B, Step, NewStep) :- 
	Step \= g(_,_,_), % Step is not a goal
	Step = (P1 ++ P2), %% P1, P2 are lists of plan steps ... 
	plan_goals1(B, [], P1, NewP1),
	plan_goals1(B, [], P2, NewP2), 
	NewStep = (NewP1 ++ NewP2),
	true. 

plan_each_goal(B, Step, NewStep) :- 
	Step \= g(_,_,_), % Step is not a goal
	Step = (P1 ## P2), %% P1, P2 are lists of plan steps ... 
	plan_goals1(B, [], P1, NewP1), % format("NewP1 is ", []), writeln(NewP1), 
	plan_goals1(B, [], P2, NewP2), % format("NewP2 is ", []), writeln(NewP2), 
	NewStep = (NewP1 ## NewP2),
	true. 

plan_each_goal(B, Step, NewStep) :- 
	Step \= g(_,_,_), % Step is not a goal
	Step = (P1 >> P2), %% P1, P2 are lists of plan steps ... 
	plan_goals1(B, [], P1, NewP1),
	plan_goals1(B, [], P2, NewP2), 
	NewStep = (NewP1 >> NewP2),
	true. 

plan_each_goal(B, Step, NewStep) :- 
	Step \= g(_,_,_), % Step is not a goal
	Step = select(Plans), %% Plans is a list of plan steps ... 
	plan_goals1(B, [], Plans, NewPlans),
	NewStep = select(NewPlans). 

% Goal cases 
plan_each_goal(_B, Step, Step) :- 
        % format("Goal step 1~n", []), 
        Step = g(_Name, Status, _Plan), Status \= active, % Do nothing to goals not in the active state. 
	true. 

plan_each_goal(B, Step, NewStep) :-
        % format("Goal step 2~n", []), 
        Step = g(Name, active, Plan), Plan \= empty, % Plan may contain subgoals, which need to be planned ... 
	plan_goals1(B, [], Plan, NewPlan), 
	NewStep = g(Name, active, NewPlan), 
	true. 

plan_each_goal(_B, Step, Step) :-
        % format("Goal step 3~n", []), 
        Step = g(Name, active, empty), 
	goal(Name, Goal, _, _, _, _), 
	goal_type(Goal, GoalType), member(GoalType, [maintain]), % Do nothing to active maintenance goals
	true. 

plan_each_goal(B, Step, NewStep) :-
        % format("Goal step 4~n", []), 
        Step = g(Name, active, empty), % Perform or achieve goal active without a plan, so if the status is not about to change, find a new plan. Why do we care about the status here? Why not just plan it? 
	goal(Name, Goal, Rules, _, _, _), 
	goal_type(Goal, GoalType), member(GoalType, [perform,achieve]), % format("FOund active empty goak ~k~n", [Name]),
        remains_active(GoalType, active, B, Rules),
	% format("Finding plan for ~k~n", [Name]), 
        find_plan(Name, Goal, B, Plan), % format("Plan found is ", []), writeln(Plan), % May need more input than this
        Plan \= empty,
	plan_goals1(B, [], Plan, NewPlan), % Plan may contain goals which need a plan ... 
	% format("Plan found is ", []), writeln(NewPlan), 
        NewStep = g(Name, active, NewPlan), 
	true. 
      
plan_goals1(B, Step, NewStep) :-
        % format("Goal step 5~n", []), 
        Step = g(Name, active, empty), % Active without a plan, so if the status is not about to change, find a new plan. 
	goal(Name, Goal, Rules, _, _, _), 
	goal_type(Goal, GoalType), 
        remains_active(GoalType, active, B, Rules),
        find_plan(Name, Goal, B, Plan), % May need more input than this
        Plan = empty,            % Cannot find a plan, so bugger it!
	NewStep = empty. 

plan_each_goal(B, Step, NewStep) :-
        Step = goal(Name), % 'Fresh' goal, inserted by looking up a plan, so convert it to a pending one ... 
	NewStep = g(Name, pending, empty). 
      
remains_active(GoalType, Status, B, Rules) :-
        findall(Action, goal_action(_, GoalType, Status, B,_, Rules,Action), List),
        subset(List, [no_action, activate]).

goal_type(Goal, GoalType) :- Goal =.. [GoalType|_Args].

subset([], _).
subset([Element|Rest], List) :-
       member(Element, List),
       subset(Rest, List).

execute_state(_, state(B,[]), state(B,[])).
execute_state(N, state(B,Goals), NewState) :-
       Goals \= [], 
       % format("Executing step ... ", []), write(Goals), nl, 
%      execute1(N, [], state(B,Goals), NewState, Status). 
       execute_step(N, B, NewB, Goals, NewGoals),
       NewState = state(NewB, NewGoals). 

execute1(_N, SoFar, state(B,[]), state(B, SoFar), finished). 
execute1(N, SoFar, state(B,Goals), NewState, Search_Status) :-
       % format("Execute 1~n", []), ttyflush, 
       Goals = [GoalContext|Others], 
       GoalContext = g(_Name, Status, _Plan), 
       % format("Goal is ~k~n", [Name]), ttyflush, 
       Status \= active, % Not active, so do not execute it. 
       % output_goals(Rest), 
       % format("~k: not executing ", [Name]), ttyflush, 
       append(SoFar, [GoalContext], NewSoFar),
       execute1(N, NewSoFar, state(B,Others), NewState, Search_Status).
execute1(N, SoFar, state(B,Goals), state(NewB, NewGoals), continue) :-
       % format("Execute 2~n", []), ttyflush, 
       Goals = [GoalContext|_Others], 
       GoalContext = g(_Name, active, Plan), 
       % format("Goal is ~k~n", [Name]), ttyflush, 
       Plan \= empty, 
       % format("Found goal to execute~n", []), ttyflush, 
       % format("Checking maintenance activity ~n", []), 	
       % append(SoFar, G, Goals), % inactive_maintenance(B,Goals), % Active, and no maintenance goal activity, so execute plan. %%% Why? Don't need this? 
       % format("~k executing ", [Name]), ttyflush, 
       % output_goals(Goals), nl, ttyflush, 
       execute_step(N, B, NewB, Goals, NGoals), 
       append(SoFar, NGoals, NewGoals). 

% Equivalences? eg nil; P??
% Check cases for ##, |>

%% Need to update all these rules for new representation ... 

% execute_step(B, B, Goals, NewGoals) :-
% 	Goals = [GoalContext|Others], 
%       GoalContext = g(Name, active, Plan), 
%       (Plan = [nil]; Plan = []),!, 
%       NewGoalContext = g(Name, active, []),
% 	NewGoals = [NewGoalContext|Others]. 

% Trivial plan success
execute_step(N, B, B, [], []) :-
        % format("Execute 0~n", []), 
	format("~n~d: Empty plan succeeded~n", [N]), 
	true. 

% Trivial plan success
execute_step(N, B, B, Plans, NewPlans) :-
        % format("Execute 1~n", []), 
	Plans = [Plan|Others], 
        Plan = nil, !, 
	format("~n~d: nil plan succeeded~n", [N]), 
	NewPlans = Others. 

% Trivial plan failure
execute_step(N, B, B, Plans, NewPlans) :-
        % format("Execute 3~n", []), 
	Plans = [Plan|_Others], 
  	Plan = fail, !, 
	format("~n~d: Plan failed~n", [N]), 
	NewPlans = [fail]. 

% Ask and succeed
execute_step(N, B, B, Plans, NewPlans) :-
        % format("Execute 4~n", []), 
	Plans = [Plan|Others], 
        Plan = ask(Phi), 
	% format("Ask plan 1~n", []), 
        implies(B, [Phi]), !, 
	format("~n~d: Ask succeeded~n", [N]), 
	NewPlans = Others. 

% Ask but fail
execute_step(N, B, B, Plans, NewPlans) :-
        % format("Execute 5~n", []), 
	Plans = [Plan|_Others], 
        Plan = ask(Phi), 
	% format("Ask plan 2~n", []),  
        \+ implies(B, [Phi]), !, 
	format("~n~d: Ask failed~n", [N]), 
	NewPlans = [fail]. 

% Add belief
execute_step(N, B, NewB, Plans, NewPlans) :-
        % format("Execute 6~n", []), 
	Plans = [Plan|Others], % format("Plans is ", []), writeln(Plans), format("Plan step (add) is ", []), write(Plan), nl, 
        Plan = add(A), % format("Adding ", []), writeln(A), 
	!, 
        update_beliefs(B, [add(A)], NewB), 
	format("~n~d: Added belief ", [N]), writeln(A), 
	NewPlans = Others. 

% Delete belief, but unnecessary
execute_step(N, B, B, Plans, NewPlans) :-
        % format("Execute 7~n", []), 
	Plans = [Plan|Others], 
        Plan = del(A), 
        \+ implies(B, [A]), !, 
	format("~n~d: Deleted belief (trivially) ", [N]), writeln(A), 
	NewPlans = Others.  

% Real delete belief
execute_step(N, B, NewB, Plans, NewPlans) :-
        % format("Execute 8~n", []), 
	Plans = [Plan|Others], 
        Plan = del(A), 
        implies(B, [A]), !, 
        delete(B, A, NewB), 
	format("~n~d: Deleted belief ", [N]), writeln(A), 
 	NewPlans = Others. 

% Perform action and succeeds
execute_step(N, B, NewB, Plans, NewPlans) :-
        % format("Execute 9~n", []), 
	Plans = [Plan|Others], 
	% (Plan = traverseaction(_,_) -> format("Trying action ~k~n", [Plan]); true), 
	action(B, Plan, PreCond, Test, Calculate, List),
	% format("Doing action ~k~n", [Plan]), 
	implies(B, PreCond), !, 
	implies(B, Test), 
	call_goals(Calculate), 
	% format("Precondition done~n", []), 
	update_beliefs(B, List, NewB),
 	NewPlans = Others,
	format("~n~d: Performed action ", [N]), writeln(Plan), 
	% format("NewPlans is ", []), writeln(NewPlans),
	true. 

% Perform action and fails
execute_step(N, B, B, Plans, NewPlans) :-
        % format("Execute 10~n", []), 
	Plans = [Plan|_Others], 
	% format("Trying action ~k~n", [A]), 
	action(B, Plan, PreCond, _Test, _Calculate, _List),
	% format("Doing action ~k~n", [A]), 
	\+ implies(B, PreCond), !, 
	% format("Precondition failed~n", []), 
	format("~n~d: Failed action ", [N]), writeln(Plan), 
	NewPlans = [fail]. 

% Named plan (like action success but simpler)
execute_step(N, B, NewB, Plans, NewPlans) :-
        % format("Execute 11~n", []), 
	Plans = [Plan|Others], 
	% plan(Plan, Body), 
	plan(Plan, Context, Body), implies(B, Context), 
	append(Body, Others, NewPlans1),
	format("Found named plan ~k ~n", [Plan]), 
	execute_step(N, B, NewB, NewPlans1, NewPlans), % do one step of the named plan
	true. 

% Wait with condition succeeding (so like action)
execute_step(N, B, NewB, Plans, NewPlans) :-
        % format("Execute 12~n", []), 
	Plans = [Plan|Others], 
	% format("Trying wait ~n", []), 
	Plan = (Guard :: Body), % Guard is a list of (conjunctive) conditions ....
	% format("Found ~n", []), 
	implies(B, Guard),!, 
	format("~n~d: Stopped waiting for guard ", [N]), writeln(Guard), 
	% Do first step of Body
	append(Body, Others, NewP), 
	execute_step(N, B, NewB, NewP, NewPlans). 

% Wait with condition failing
execute_step(_N, B, B, Plans, NewPlans) :-
        % format("Execute 13~n", []), 
        Plans = [Plan|_Others], 
	% format("Trying wait ~n", []), 
	Plan = (Guard :: _Body), 
	% format("Found again ~n", []), 
	\+ implies(B, Guard),!, 
	% format("~n~d: Still waiting for guard ", [N]), writeln(Guard), 
	% Leave it alone ... 
	NewPlans = Plans. 

% Non-blocking wait with condition succeeding (so like action)
execute_step(N, B, NewB, Plans, NewPlans) :-
        % format("Execute 12~n", []), 
	Plans = [Plan|Others], 
	% format("Trying wait ~n", []), 
	Plan = (Guard : Body), % Guard is a list of (conjunctive) conditions ....
	% format("Found ~n", []), 
	implies(B, Guard),!, 
	format("Stopped waiting for condition ", []), writeln(Guard), 
	% Do first step of Body
	append(Body, Others, NewP), 
	execute_step(N, B, NewB, NewP, NewPlans). 

% Non-blocking wait with condition failing
execute_step(N, B, B, Plans, NewPlans) :-
        % format("Execute 13~n", []), 
        Plans = [Plan|_Others], 
	% format("Trying wait ~n", []), 
	Plan = (Guard : _Body), 
	% format("Found again ~n", []), 
	\+ implies(B, Guard),!, 
	format("~d~n: Condition failed ", [N]), writeln(Guard), 
	NewPlans = [fail]. 

% Explicit sequence
execute_step(N, B, NewB, Plans, NewPlans) :-
        % format("Execute 14~n", []), 
	Plans = [Plan|Others], 
 	Plan = (P1 ++ P2), 
	% format("Explicit Sequence ", []), 
	append([P1,P2], Others, NewP), 
        execute_step(N, B, NewB, NewP, NewPlans). 

% % Parallel 1
% execute_step(N, B, B, Plans, NewPlans) :-
%         % format("Execute 15a~n", []), 
% 	Plans = [Plan|Others], 
%  	Plan = (P1 ## _P2), 
% 	P1 = [fail|_], !, 
% 	format("~d~n: Plan failed in left ## branch~n", [N]), 
% %	append([([fail] ## P2)], Others, NewPlans), 
% 	append([fail], Others, NewPlans), 
% 	true. 
% 
% % Parallel 2
% execute_step(N, B, B, Plans, NewPlans) :-
%         % format("Execute 15b~n", []), 
% 	Plans = [Plan|Others], 
%  	Plan = (P1 ## P2), 
% 	P1 \= [fail|_], P2 = [fail|_], !, 
% 	format("~d~n: Plan failed in right ## branch~n", [N]), 
% % 	append([(P2 ## [fail])], Others, NewPlans), % NewPlans = [NewPlan|Others], 
%  	append([fail], Others, NewPlans), % NewPlans = [NewPlan|Others], 
% 	true. 

% % Parallel 3
% execute_step(N, B, NewB, Plans, NewPlans) :-
%         % format("Execute 15c~n", []), 
% 	Plans = [Plan|Others], 
%  	Plan = (P1 ## P2), 
%  	P1 \= [fail|_], P2 \= [fail|_], !, 
%  	% format("Parallel ", []), 
% %        format("P1 (##) is ", []), writeln(P1), 
% %        format("P2 (##) is ", []), writeln(P2), 
% 	execute_step(N, B, NewB, P1, Plan1), 
% %         format("Plan1 (##) is ", []), writeln(Plan1), 
% 	
% 	assemble_plan(P2, Plan1, NewPlan), 
% %	format("NewPlan (##) is ", []), write(NewPlan), format("Others is ", []), writeln(Others), 
% 
% 	append(NewPlan, Others, NewPlans), % NewPlans = [NewPlan|Others], 
% %        format("NewPlans (##) is ", []), writeln(NewPlans), 
% 	true. 


% Parallel % New!
execute_step(N, B, B, Plans, NewPlans) :-
         % format("Execute 15c~n", []), 
 	Plans = [Plan|Others], 
  	Plan = (P1 ## _P2), 
 	P1 = [fail|_], !, 
 	format("~d~n: Plan failed in left ## branch~n", [N]), 
 	append([fail], Others, NewPlans).

execute_step(N, B, B, Plans, NewPlans) :-
         % format("Execute 15c~n", []), 
 	Plans = [Plan|Others], 
  	Plan = (P1 ## P2), 
 	P1 \= [fail|_], P2 = [fail|_], !, 
 	format("~d~n: Plan failed in right ## branch~n", [N]), 
 	append([fail], Others, NewPlans).

% Parallel % New!
execute_step(N, B, NewNewB, Plans, NewPlans) :-
         % format("Execute 15c~n", []), 
 	Plans = [Plan|Others], 
  	Plan = (P1 ## P2), 
 	P1 \= [fail|_], P2 \= [fail|_], !, 
  	% format("Parallel ", []), 

 	execute_step(N, B, NewB, P1, Plan1), % format("# Branch 1 done ", []), 
	execute_step(N, NewB, NewNewB, P2, Plan2), % format("# Branch 2 done~n", []), 

 	assemble_plan(Plan1, Plan2, NewPlan), 
 	append(NewPlan, Others, NewPlans), 
%        format("NewPlans (##) is ", []), writeln(NewPlans), 
 	true. 

% Triangle 1
execute_step(N, B, NewB, Plans, NewPlans) :-
        % format("Execute 16~n", []), 
	Plans = [Plan|Others], 
 	Plan = (P1 >> P2), 
	(P1 = [fail|_]), !, 
	% format("Triangle 1 ", []), 
	append(P2, Others, NewP), 
        execute_step(N, B, NewB, NewP, NewPlans).

% Triangle 2
execute_step(N, B, NewB, Plans, NewPlans) :-
        % format("Execute 17~n", []), 
	Plans = [Plan|Others], 
 	Plan = (P1 >> _P2), 
	(P1 = [nil]; P1 = []), !, 
	% format("Triangle 2 ", []), 
        execute_step(N, B, NewB, Others, NewPlans). 

% Triangle 3
execute_step(N, B, NewB, Plans, NewPlans) :-
        % format("Execute 17.5~n", []), 
	Plans = [Plan|Others], 
 	Plan = (P1 >> P2), 
	\+ (P1 = [fail|_]; P1 = [nil]; P1 = []), !, 
	% format("Triangle 3 ", []), % format("P1 is ", []), writeln(P1), format("P2 is ", []), writeln(P2), 
        execute_step(N, B, NewB, P1, Plan1),
	append([(Plan1 >> P2)], Others, NewPlans), 
        true. 

% Event
execute_step(N, B, B, Plans, NewPlans) :-
        % format("Execute 18~n", []), 
        % format("Plans: ", []), writeln(Plans), ttyflush, 
	Plans = [Plan|Others], % format("Plan: ", []), writeln(Plan), ttyflush, 
        Plan = ev(E), !, format("~n~d: Event found is ", [N]), write(E), nl, ttyflush, 
	findall(C:P, eventplan(E, C, P), PlanList), format("PlanList is ", []), write(PlanList), nl, 
	NewPlans = [select(PlanList)|Others], 
	true. 
	% NewPlans = [NewPlan|Others]. 

% select
execute_step(N, B, B, Plans, NewPlans) :-
        % format("Execute 19~n", ]), 
	Plans = [Plan|Others], 
        Plan = select(PlanList), !, % format("Select choice is ", []), write(PlanList), nl, ttyflush, 
	member(Cond:P1, PlanList), % format("Trying plan ", []), writeln(P1), 
	implies(B, [Cond]), !, format("~n~d: Selected plan is ", [N]), writeln(P1), 
	delete(PlanList, Cond:P1, RestPlanList), % format("RestPlanList is ", []), writeln(RestPlanList), 
	plan_alternatives(P1, RestPlanList, NewPlan), % format("NewP is ", []), writeln(NewP), 
 	append(NewPlan, Others, NewPlans),  % format("NewPlan is ", []), writeln(NewPlan), 
	true. 

%% Need to update the goal cases with different goal representation ... 

% New Goal 
execute_step(N, B, B, Plans, NewPlans) :-
        % format("Execute 20~n", []), 
	Plans = [Plan|Others], 
	Plan = goal(Name), 
	% format("Adding new subgoal ~k... ~n", [Name]), ttyflush, 
	format("~n~d: New goal ~k added.~n", [N,Name]), 
	% format("GoalPlan is ", []), writeln(GoalPlan), 
	NewPlans = [g(Name, pending, empty)|Others]. 

% Existing Goal success 
execute_step(N, B, B, Plans, NewPlans) :-
        % format("Execute 20~n", []), 
	Plans = [Plan|_Others], 
	Plan = g(Name, Status, _GoalPlan), Status \= active, % Only execute active goals ... 
	NewPlans = Plans. 

% Existing Goal success 
execute_step(N, B, B, Plans, NewPlans) :-
        % format("Execute 20~n", []), 
	Plans = [Plan|Others], 
	Plan = g(Name, Status, _GoalPlan), Status = active, % Only do this for active goals ... 
	% format("Trying subgoal success for ~k... ~n", [Name]), ttyflush, 
	goal(Name, _, GoalSuccess, _GoalFailure, _, _OriginalPlan), 
	implies(B, GoalSuccess), !, % Goal has succeeded, so drop it and proceed. 
	format("~n~d: Goal success for ~k. Condition is ", [N,Name]), write(GoalSuccess), nl, % writeln(Others), ttyflush, 
	% format("GoalPlan is ", []), writeln(GoalPlan), 
	NewPlans = Others. 

% Existing Goal failure
execute_step(N, B, B, Plans, NewPlans) :-
        % format("Execute 21~n", []), 
	Plans = [Plan|_Others], 
	Plan = g(Name, Status, _GoalPlan), Staus = active, % Only do this for active goals ... 
	% format("Trying subgoal failure ... ~n", []), ttyflush, 
	goal(Name, _, _GoalSuccess, GoalFailure, _, _OriginalPlan), 
	implies(B, GoalFailure), !, % Goal has failed, so drop it and any subsequent part of the plan
	format("~n~d: Goal failure for ~k. Condition is ", [N,Name]), write(GoalFailure), nl, ttyflush, 
	% format("GoalPlan is ", []), writeln(GoalPlan), 
	NewPlans = [fail]. 

% Existing Goal Plan success 
execute_step(N, B, B, Plans, NewPlans) :-
        % format("Execute 22~n", []), 
	Plans = [Plan|Others], 
	Plan = g(Name, Status, GoalPlan), Status = active, % Only do this for active goals ... 
	% format("Trying subgoal plan termination ... ~n", []), ttyflush, 
	goal(Name, _, GoalSuccess, GoalFailure, _, OriginalPlans), 
	\+ implies(B, GoalSuccess), \+ implies(B, GoalFailure),

	GoalPlan = [], !,  % Plan has successfully ended, so restart 

	format("~n~d: Plan terminated successfully for goal ~k, restarting with original plan ... ~n", [N,Name]), % format("Original Plan is ~k~n", [OriginalPlanName]), ttyflush, 
	member(OriginalPlanName, OriginalPlans), 
	plan(OriginalPlanName, Cond, OriginalPlan), %% Do I need to check the Context Condition (Cond)? Presumably, ... so what happends if it fails? 
	% NewPlan = goal(Name,OriginalPlan), % format("NewPlan is ", []), writeln(NewPlan), 
	NewPlan = g(Name, Status, OriginalPlan), % format("NewPlan is ", []), writeln(NewPlan), 
	append([NewPlan], Others, NewPlans). 

% Existing Goal Plan failure
execute_step(N, B, B, Plans, NewPlans) :-
        % format("Execute 22~n", []), 
	Plans = [Plan|Others], 
	Plan = g(Name, Status, GoalPlan), Status = active, % Only do this for active goals ... 
	% format("Trying subgoal plan termination ... ~n", []), ttyflush, 
	goal(Name, _, GoalSuccess, GoalFailure, _, OriginalPlans), 
	\+ implies(B, GoalSuccess), \+ implies(B, GoalFailure),

	GoalPlan = [fail|_], !,  % Plan has failed, so ... 

	format("~n~d: Plan failed for goal ~k, restarting with original plan ... ~n", [N,Name]), % format("Original Plan is ~k~n", [OriginalPlanName]), ttyflush, 
	member(OriginalPlanName, OriginalPlans), 
	plan(OriginalPlanName, Cond, OriginalPlan), %% Do I need to check the Context Condition (Cond)? Presumably, ... so what happends if it fails? 
	% NewPlan = goal(Name,OriginalPlan), % format("NewPlan is ", []), writeln(NewPlan), 
	NewPlan = g(Name, Status, OriginalPlan), % format("NewPlan is ", []), writeln(NewPlan), 
	append([NewPlan], Others, NewPlans). 

% Existing Goal Plan is empty ... 
execute_step(N, B, NewB, Plans, NewPlans) :-
        % format("Execute 23~n", []), 
	Plans = [Plan|Others], % format("Goal: ", []), write(Plan), nl, 
	Plan = g(Name, active, empty), 
	format("Goal: ~k, Plan: ", [Name]), writeln(empty), 
	% format("Trying subgoal generic ... ", []), writeln(GoalPlan), ttyflush, 
	goal(Name, _, GoalSuccess, GoalFailure, _, _OriginalPlan), % format("Goal found~n", []), 
	\+ implies(B, GoalSuccess), \+ implies(B, GoalFailure), % format("Still going~n", []), 
	% Do nothing ... 
	NewPlans = Plans. 

% Existing Goal Plan execution step 
execute_step(N, B, NewB, Plans, NewPlans) :-
        % format("Execute 23~n", []), 
	Plans = [Plan|Others], % format("Goal: ", []), write(Plan), nl, 
	Plan = g(Name, Status, GoalPlan), Status = active, GoalPlan \= empty, % Only do this for active goals ... 
	% format("Goal: ~k, Plan: ", [Name]), writeln(GoalPlan), 
	% format("Trying subgoal generic ... ", []), writeln(GoalPlan), ttyflush, 
	goal(Name, _, GoalSuccess, GoalFailure, _, _OriginalPlan), % format("Goal found~n", []), 
	\+ implies(B, GoalSuccess), \+ implies(B, GoalFailure), % format("Still going~n", []), 
        \+ (GoalPlan = []; GoalPlan = [fail|_]), !, % format("Not failed~n", []), % Plan hasn't ended
	% format("Goal is ~k ", [Name]), % format("GoalPlan is ", []), writeln(GoalPlan), ttyflush, 
	execute_step(N, B, NewB, GoalPlan, NewGoalPlan), % format("NewGoalPlan is ", []), writeln(NewGoalPlan),  
	NewPlan = g(Name, Status, NewGoalPlan), 
	append([NewPlan], Others, NewPlans). 

execute_step(N, B, B, Plans, Plans) :-
        % format("Execute 24~n", []), 
	Plans = [Plan|_Others], 
	format("~n~d: Unrecognised Plan:  ", [N]), write(Plan), nl, 
	true. 


% Hacky stuff to make things work. Need to do better than this!
implies(_B, []). 
implies(B, [or(List1, _List2)]) :- implies(B, List1), !.  
implies(B, [or(_List1, List2)]) :- implies(B, List2), !. 
implies(B, [F|Rest]) :-	F \== or(_,_), implies_single(B, F), implies(B, Rest).

%% implies_single(B, G) to be supplied by each example as needed ... 
% implies_single(B, G) :- specific_list(L), \+ member(G, L), member(G, B). 
% implies_single(_B, G) :- specific_list(L), \+ member(G, L), G. % For built-ins.
% implies_single(B, G) :- specific_list(L), \+ member(G, L), member(rule(Head, Body), B), Head = G, implies(B, Body).
% implies_single(B, G) :- specific_list(L), member(G, L), member(G, B). 

% % Rules for signals 
% % implies_single(B, to_abort(Context)) :- implies(B, [abortdecided(Context)]).
% implies_single(B, to_abort(Context)) :- implies(B, [abort(Context)]).
% implies_single(B, to_abort(Context)) :- context(PlanName, Context), rawplan(PlanName, _ContextCondition, InCondition, _, _, _, _, _), \+ implies(B, InCondition). 
% implies_single(B, to_abort(Context)) :- context(_, Context), append(Prefix, ParentContext, Context), Prefix \== [], implies(B, [to_abort(ParentContext)]).
% implies_single(B, to_suspend(Context)) :- implies(B, [suspend(Context)]), \+ implies(B, [resume(Context)]). 
% implies_single(B, to_suspend(Context)) :- context(_, Context), append(Prefix, ParentContext, Context), Prefix \== [], implies(B, [to_suspend(ParentContext)]).
% % implies_single(B, pause(Context)) :- implies(B, [to_suspend(Context)]), \+ implies(B, [suspended(Context)]). 
% implies_single(B, pause(Context)) :- implies(B, [to_suspend(Context)]).
% implies_single(B, pause(Context)) :- implies(B, [to_abort(Context)]).
% implies_single(B, ready(Context)) :- \+ implies(B, [pause(Context)]), \+ implies(B, [suspended(Context)]). 
% implies_single(B, inactive(Context)) :- \+ implies(B, [active(Context)]).
% implies_single(B, active_child(Context)) :- context(_, ChildContext), append(Prefix, Context, ChildContext), Prefix \== [], implies(B, [active(ChildContext)]), \+ implies(B, [suspended(ChildContext)]). 
% implies_single(B, failedcondition(Context)) :- implies(B, [failed(Context)]).
% implies_single(B, abortcondition(Context)) :- implies(B, [to_abort(Context)]), \+ implies(B, [active_child(Context)]).
% implies_single(B, suspendcondition(Context)) :- implies(B, [pause(Context)]), implies(B, [suspend(Context)]). 
% implies_single(B, suspendcondition(Context)) :- implies(B, [pause(Context)]), Context = [_|ParentContext], implies(B, [suspended(ParentContext)]). 
% implies_single(B, resumecondition(Context)) :- implies(B, [resume(Context)]). % add implies(B, [suspended(Context)])  ?? 
% implies_single(B, resumecondition(Context)) :- \+ implies(B, [suspend(Context)]), implies(B, [suspended(Context)]), Context = [_|ParentContext], \+ implies(B, [suspended(ParentContext)]).
% %% This means that suspend(Context) must remain in the beliefs until it is time to resume the task. 
% implies_single(B, abort_or_fail(Context)) :- implies(B, [abortcondition(Context)]).
% implies_single(B, abort_or_fail(Context)) :- implies(B, [failedcondition(Context)]).
% implies_single(B, suspend_or_resume(Context)) :- implies(B, [suspendcondition(Context)]).
% implies_single(B, suspend_or_resume(Context)) :- implies(B, [resumecondition(Context)]).


% active(Context), suspended(Context), failed(Context) are added or deleted by the transformed plans as appropriate. 
% abort(Context), suspend(Context), resume(Context) are signalled by events. 

% Utilities

output_state(nores, state(B,P)) :-
        % Don't output beliefs about resources .. 
        separate_beliefs(B, [], _, [], Others),
	output_state(state(Others,P)). 

output_state(state(B,P)) :-
	% format("Beliefs: ", []), output_beliefs(B),
	format("Beliefs: ", []), writeln(B),
	format("Goal and Plans: ", []), writeln(P), 
	% format("Formatted plans: ~n", []), output_plan(P),
	nl.

separate_beliefs([], ResourcesSoFar, ResourcesSoFar, OthersSoFar, OthersSoFar).
separate_beliefs([Belief|Rest], ResourcesSoFar, Resources, OthersSoFar, Others) :-
    Belief = resources(_,_), 
    append(ResourcesSoFar, [Belief], NewResourcesSoFar), 
    separate_beliefs(Rest, NewResourcesSoFar, Resources, OthersSoFar, Others). 
separate_beliefs([Belief|Rest], ResourcesSoFar, Resources, OthersSoFar,  Others) :-
    Belief \= resources(_,_), 
    append(OthersSoFar, [Belief], NewOthersSoFar), 
    separate_beliefs(Rest, ResourcesSoFar, Resources, NewOthersSoFar, Others). 

output_plan(P) :- plan_size(P, N), N =< 12, writeln(P). 
output_plan(P) :- plan_size(P, N), N > 12, output_plan1(P). 

output_plan1([]).
output_plan1([Plan|Plans]) :-
        % format("    ", []), 
	output_plan_step(0, Plan), nl, 
	output_plan1(Plans).

output_beliefs([]) :- nl. 
output_beliefs([Belief|Beliefs]) :-
	output_single_belief(Belief),
	output_beliefs(Beliefs).

output_single_belief(Belief) :-	write(Belief), format(" ",[]).

% output_plan(Plan) :- write(Plan). 

output_plan_step(Level, []) :- output_spaces(Level), format("[]"). 
output_plan_step(Level, Plan) :- member(Plan, [nil, fail, ask(_), add(_), del(_), ev(_),abort(_),suspend(_),resume(_),failed(_),active(_),suspended(_)]), output_spaces(Level), write(Plan). 
output_plan_step(Level, Plan) :- is_action(Plan), output_spaces(Level), write(Plan). 
output_plan_step(Level, Plan) :- plan(Plan, _, _), output_spaces(Level), write(Plan).  
output_plan_step(Level, Plan) :- Plan = (Guard::Body),  output_spaces(Level), write(Guard), format("::((", []), output_plan_flat(Body), format(")) ", []). 
output_plan_step(Level, Plan) :- Plan = (Guard: Body),  output_spaces(Level), write(Guard), format(":(", []), output_plan_flat(Body), format(") ", []). 
output_plan_step(Level, Plan) :- Plan = (P1++P2), Level1 is Level+1, output_plan_list(Level1, P1), nl, output_spaces(Level), format("++ ", []), nl, output_plan_list(Level1, P2). 
output_plan_step(_Level, Plan) :- Plan = (_P1##_P2), plan_step_size(Plan, Size), Size =< 6, write(Plan), format(" "), !. 
output_plan_step(Level, Plan) :- Plan = (P1##P2), plan_step_size(Plan, Size), Size > 6, Level1 is Level+1, output_plan_list(Level1, P1), nl, output_spaces(Level), format("## ", []), nl, output_plan_list(Level1, P2). 
output_plan_step(_Level, Plan) :- Plan = (_P1>>_P2), plan_step_size(Plan, Size), Size =< 6, write(Plan), format(" "), !. 
output_plan_step(Level, Plan) :- Plan = (P1>>P2), Level1 is Level+1, output_plan_list(Level1, P1), nl, output_spaces(Level), format(">> ", []), nl, output_plan_list(Level1, P2). 
output_plan_step(Level, Plan) :- Plan = select(PlanList), output_spaces(Level), format("(|", []), output_plan_list(Level, PlanList), format("|) ", []). 
output_plan_step(_Level, Plan) :- Plan = goal(GoalName, [GoalPlan]), plan(GoalPlan, _, _), !, format(" goal:~k -> ~k ", [GoalName, GoalPlan]). 
output_plan_step(_Level, Plan) :- Plan = g(Name, _Status, [GoalPlan]), plan(GoalPlan, _, _), !, format(" goal:~k -> ~k ", [Name, GoalPlan]). 
% output_plan_step(Level, Plan) :- Plan = goal(GoalName, GoalPlan), plan_step_size(Plan, Size), Size =< 6, format("goal:~k -> ", [GoalName]), write(GoalPlan), format(" "), !. 
% output_plan_step(Level, Plan) :- Plan = goal(GoalName, GoalPlan), plan_step_size(Plan, Size), Size > 6, Level1 is Level + 1, output_spaces(Level), format("goal:~k -> ~n", [GoalName]), output_spaces(Level1), output_plan_list(Level1, GoalPlan).
output_plan_step(Level, Plan) :- Plan = goal(GoalName, GoalPlan), Level1 is Level + 1, output_spaces(Level), format("goal:~k -> ~n", [GoalName]), output_spaces(Level1), output_plan_list(Level1, GoalPlan).
output_plan_step(Level, Plan) :- Plan = g(Name, _Status, GoalPlan), Level1 is Level + 1, output_spaces(Level), format("goal:~k -> ~n", [Name]), output_spaces(Level1), output_plan_list(Level1, GoalPlan).

output_plan_list(_, []). 
output_plan_list(Level, [Plan|Plans]) :-
    output_plan_step(Level, Plan), 
    output_plan_list(Level, Plans). 

output_plan_flat([]). 
output_plan_flat([Plan|Plans]) :-
    output_plan_step(0, Plan), format(" ", []), 
    output_plan_flat(Plans). 

output_spaces(0).
output_spaces(N) :- N > 0, N1 is N - 1, format("  ", []), output_spaces(N1). 

plan_size([], 0).
plan_size([Step|Rest], Size) :- plan_step_size(Step, Size1), plan_size(Rest, Size2), Size is Size1 + Size2.

plan_step_size([], 0).
plan_step_size(Step, 1) :- member(Step, [nil, fail, ask(_), add(_), del(_), ev(_),abort(_),suspend(_),resume(_),failed(_),active(_),suspended(_)]).
plan_step_size(Step, 1) :- is_action(Step). 
plan_step_size(Step, 1) :- plan(Step, _, _).
plan_step_size(Step, Size) :- Step = (_Guard:Body),   plan_size(Body, N), Size is N + 1. 
plan_step_size(Step, Size) :- Step = (_Guard::Body),  plan_size(Body, N), Size is N + 1. 
plan_step_size(Step, Size) :- Step = (P1++P2), plan_size(P1, Size1), plan_size(P2, Size2), Size is Size1 + Size2. 
plan_step_size(Step, Size) :- Step = (P1##P2), plan_size(P1, Size1), plan_size(P2, Size2), Size is Size1 + Size2. 
plan_step_size(Step, Size) :- Step = (P1>>P2), plan_size(P1, Size1), plan_size(P2, Size2), Size is Size1 + Size2. 
% plan_step_size(Step, Size) :- Step = select(PlanList), plan_size(PlanList, Size1), Size is Size1 + 1. 
plan_step_size(Step, 1) :- Step = select(_).
plan_step_size(Step, 1) :- Step = goal(_GoalName, [GoalPlan]), plan(GoalPlan, _,_), !. 
plan_step_size(Step, Size) :- Step = goal(_GoalName, GoalPlan), plan_size(GoalPlan, Size1), Size is Size1 + 1. 
plan_step_size(Step, 1) :- Step = g(_GoalName, _, [GoalPlan]), plan(GoalPlan, _,_), !. 
plan_step_size(Step, Size) :- Step = g(_GoalName, _, GoalPlan), plan_size(GoalPlan, Size1), Size is Size1 + 1. 

output_number(Value) :- numeric(Value), format("~1f%", [100*Value]).
output_number(Value) :- \+ numeric(Value), format("--", []).

numeric(Value) :- number(Value). 

plan_alternatives(ChosenPlan, [], ChosenPlan).
plan_alternatives(ChosenPlan, RestPlanList, NewPlan) :-
	RestPlanList \== [],
	NewPlan = [(ChosenPlan >> [select(RestPlanList)]) ]. 

assemble_plan(Plan1, Plan2, [])             :- empty_plan(Plan1), empty_plan(Plan2). 
assemble_plan(Plan1, Plan2, Plan1)          :- \+ empty_plan(Plan1), empty_plan(Plan2). 
assemble_plan(Plan1, Plan2, Plan2)          :- empty_plan(Plan1), \+ empty_plan(Plan2). 
assemble_plan(Plan1, Plan2, [Plan1 ## Plan2]) :- \+ empty_plan(Plan1), \+ empty_plan(Plan2). 

empty_plan([]).
empty_plan([nil]).
empty_plan(nil).

call_goals([]).
call_goals([G|Rest]) :- call(G), call_goals(Rest).

% % P is a list of guarded plans
% % A rule E: Ph <- Pl is represented as rule(E, Ph, Pl). 
% % See also Event rule below. 
% gather(E, plans(P)) :-	findall(p(Ph,Pl), rule(E, Ph, Pl), P).

update_beliefs(B, [], B).
update_beliefs(B, [del(B1)|Rest], NewB) :-
	delete_belief(B, B1, NB),
	update_beliefs(NB, Rest, NewB). 
update_beliefs(B, [add(B1)|Rest], NewB) :-
        \+ implies(B, [B1]), 
	append([B1], B, NB), 
	update_beliefs(NB, Rest, NewB). 
update_beliefs(B, [add(B1)|Rest], NewB) :-
        implies(B, [B1]), 
	update_beliefs(B, Rest, NewB). 

delete_belief(B, B1, NB) :- delete(B, B1, NB).
delete_belief(B, B1, B) :-  \+ implies(B, [B1]).

add_beliefs(B, Add, NewB) :- append(B, Add, NewB). 

success_and_failure_conditions(SubGoal, Success, Failure) :-
	SubGoal = achieve(_, Success, Failure).
success_and_failure_conditions(SubGoal, Success, Failure) :-
	SubGoal = maintain(_, _, _, _, Success, Failure).

% Given update on status. This is the mechanism for measuring goal completess. 
status_update(State) :- completeness_status(State). 

completeness_status(state(B, Plans)) :-
    format("Completeness report: ~n", []), output_state(nores, state(B, Plans)), 
    completeness_status1(B, Plans),
    % format("Completeness report complete~n", []), 
    true. 

% This is only relevant for goals, so only do things for them ... 

completeness_status1(_B, []). 
completeness_status1(_B, empty). 
completeness_status1(B,Plans) :-
        Plans = [Plan|Rest],
	(member(Plan, [nil, fail, ask(_), add(_), del(_), ev(_),abort(_),suspend(_),resume(_),failed(_),active(_),suspended(_),active(_),inactive(_)]); is_action(Plan); plan(Plan, _, _)), 
	completeness_status1(B, Rest). 

completeness_status1(B, Plans) :- 
        Plans = [Plan|Rest],
	Plan \= g(_,_,_), 
	(Plan = Guard::Body; Plan = Guard:Body), 
	completeness_status1(B, Body). 

completeness_status1(B, Plans) :- 
        Plans = [Plan|Rest],
	Plan \= g(_,_,_), 
	(Plan = (P1 ++ P2); Plan = (P1 ## P2); Plan = (P1 >> P2)), %% P1, P2 are lists of plan steps ... 
	completeness_status1(B, P1), 
	completeness_status1(B, P2), 
	true. 

completeness_status1(B, Plans) :- 
        Plans = [Plan|Rest],
	Plan \= g(_,_,_), 
	Plan = select(Plans), %% Plans is a list of plan steps ... 
	completeness_status1(B, Plans), 
	true. 

completeness_status1(B,Plans) :-
 	Plans = [Plan|Rest],
 	Plan = g(Name, Status, _Plan), 
	\+ member(Status, [active,suspended]), % Don't report completeness for these
	% format("Found goal ~k in state~n", [Name, Status]), 
	completeness_status1(B, Rest),
	true. 

completeness_status1(B,Plans) :-
 	Plans = [Plan|Rest],
 	Plan = g(Name, Status, GoalPlan),
	member(Status, [active,suspended]), % Only report completeness for these. 
	% format("Report for goal ~k~n", [Name]), 
	completeness(B, Plan, Report),
	output_report(Plan, Report),
        % format("Reporting on subgoals of ", []), writeln(GoalPlan), 
	completeness_status1(B, GoalPlan), 
        % format("Subgoals done~n", []), 
	completeness_status1(B, Rest),
	true. 

completeness(B, GoalContext, Report) :-
	resource_status(B, GoalContext, CR, DR, PR), 
	% format("Resource status done~n", []), 
	effect_status(B, GoalContext, CE, CPE, Success, DE, PE), 
	% format("Effects status done~n", []), 
	total_resources(CR, DR, DR_Value), %% Revise these ?? 
	total_resources(CR, PR, PR_Value), 
	total_effects(CE, Success, S_Value), 
	total_effects(CE, DE, DE_Value), % format("Current effects are ", []), write(CE), nl, format("Potential effects are ", []), write(PE), nl, 
	append(DE, PE, TotalE), 
	append(CE, CPE, TotalCE), 
	total_effects(TotalCE, TotalE, PE_Value), % format("PE value is ", []), output_number(PE_Value), nl,  
	Report = [res(CR,DR,PR,DR_Value,PR_Value),eff(CE, Success, DE, PE, CPE, S_Value, DE_Value, PE_Value)],
	% Report = [res(CR,DR,PR,DR_Value,PR_Value)],
	true. 
	
output_report(GoalContext, Report) :-
 	GoalContext = g(Name, _Status, _Plan),
	format("~k: ", [Name]), 
 	Report = [res(CR,DR,PR,DR_Value,PR_Value),eff(CE, Success, DE, PE, CPE, S_Value, DE_Value, PE_Value)],
 	% Report = [res(CR,DR,PR,DR_Value,PR_Value)],
	format("DRC: ", []), output_number(DR_Value), format(" ", []), 
	format(" PRC: ", []), output_number(PR_Value), 
	format(" SC: ", []), output_number(S_Value), format(" ", []), 
	format(" DE: ", []), output_number(DE_Value), format(" ", []), 
	format(" PE: ", []), output_number(PE_Value), nl,

	format(" CR: ", []), write(CR), 
	format(" DR: ", []), write(DR), 
	format(" PR: ", []), write(PR), format(" ", []), 
	nl,
	format(" CE: ", []), write(CE), 
	format("  S: ", []), write(Success), 
	format(" DE: ", []), write(DE), 
	format(" PE: ", []), write(PE), 
	format(" CPE: ", []), write(CPE), format(" ", []), 
	nl, 
	true. 

resource_status(B, GoalContext, CR, DR, PR) :-
    	GoalContext = g(Name, _Status, _Plan),
	implies(B, [completed(Name)]),
	% format("Resource summary for completed goal ~k~n", [Name]), 
	used_resources(B, Name, CR), % Goal is finished, so just provide actual resources used. 
	DR = [res(drill,0),res(memory,0),res(time,0)], 
	PR = [res(drill,0),res(memory,0),res(time,0)], 
	true. 
resource_status(B, GoalContext, CR, DR, PR) :-
    	GoalContext = g(Name, _Status, _Plan),
	\+ implies(B, [completed(Name)]), % Goal is not finished, so recursively descend through to find completion status
	% format("Resource summary for incomplete goal ~k~n", [Name]), 
	resource_summary(B, Name, CR, DR, PR),
	true. 

effect_status(B, GoalContext, CE, CPE, Success, DE, PE) :-
    	GoalContext = g(Name, _Status, _Plan),
	effect_summary(Name, Success, DE, PE), 
	current_effects(B, DE, PE, CE, CPE).

total_resources(CR, _, none) :-
    length(CR, Len), Len = 0.
total_resources(CR, Total, Value) :-
    length(CR, Len), Len > 0, 
    % assumes CR and Total are compatible and have the same length
    total_resources1(CR, Total, 0, 0, Value).

total_resources1([], _, _SoFar, N, none) :- N = 0.
total_resources1([], _, SoFar, N, Value) :- N > 0, Value is SoFar/N.  
total_resources1(CR, Total, SoFar, N, Value) :-
    CR = [Current|CurrentRest],
    Total = [Max|TotalRest],
    Current = res(Name, Amount1),
    Max = res(Name, Amount2), 
    \+ (Amount1 = 0, Amount2 = 0), 
    NewSoFar is SoFar + Amount1/(Amount1 + Amount2), NewN is N+1, 
    total_resources1(CurrentRest,TotalRest, NewSoFar,NewN,Value),
    true. 
total_resources1(CR, Total, SoFar, N, Value) :-
    CR = [Current|CurrentRest],
    Total = [Max|TotalRest],
    Current = res(Name, Amount1),
    Max = res(Name, Amount2), 
    Amount2 = 0, Amount1 = 0, % ignore this one
    total_resources1(CurrentRest,TotalRest, SoFar,N,Value),
    true. 

total_effects(CE, _, none) :-
    length(CE, Len), Len = 0.
total_effects(CE, Total, Value) :-
    length(CE, Len), Len > 0, 
    total_effects1(CE, Total, 0, 0, Value).

total_effects1([], _, _SoFar, N, none) :- N = 0.
total_effects1([], _, SoFar, N, Value) :- N > 0, Value is SoFar/N.  
total_effects1(CE, Total, SoFar, N, Value) :-
    CE = [Current|CurrentRest],
    Current = eff(Name, Amount1),
    member(eff(Name, Amount2), Total),
    delete(Total, eff(Name, Amount2), TotalRest), 
    \+ (Amount2 = 0),  
    NewSoFar is SoFar + Amount1/(Amount2), NewN is N+1, 
    total_effects1(CurrentRest,TotalRest, NewSoFar, NewN, Value),
    true. 
total_effects1(CE, Total, SoFar, N, Value) :-
    CE = [Current|CurrentRest],
    Current = eff(Name, _Amount1),
    member(eff(Name, Amount2), Total),
    delete(Total, eff(Name, Amount2), TotalRest), 
    Amount2 = 0,
    total_effects1(CurrentRest,TotalRest, SoFar, N, Value),
    true. 
total_effects1(CE, Total, SoFar, N, Value) :-
    CE = [Current|CurrentRest],
    Current = eff(Name, _Amount1),
    \+ member(eff(Name, _Amount2), Total),
    format("Ignoring effect ~k~n", [Current]), 
    total_effects1(CurrentRest,Total, SoFar, N, Value),
    true.
 

%% example specific stuff for Mars rover example: 

standard_rules(Name, Succ, Rules) :-
    append(Succ, [drop(Name)], Conds), 
    Rules = [
	act(Conds, drop), 
	act([abort(Name)], abort), 
	act([activate(Name)], activate), 
	act([suspend(Name)], suspend), 
	act([reactivate(Name)], reactivate), 
	act([reconsider(Name)], reconsider) 
    ].

rules(Name, Succ, Rules) :- standard_rules(Name, Succ, Rules). 

initial_state(state(B,G)) :- initial_beliefs(B), initial_goals(G). 
% initial_goals([g(explore(red1),pending,empty)]). % For explore 1-5. 
% initial_goals([goal(explore(red1))]). % For explore 1-5. 
% initial_goals([goal(explore(red1)) ## goal(recharge)]). % For explore 6. 
initial_goals([]). % Do  this and have appropriate event to add appropriate goals ... 

initial_beliefs([
drill_count(0),
memory_count(0), 
time_count(0),
battery_charge(32),  %% To make scenario work ... 
resources(explore(red1),          Zero),  
resources(exp(rock1),             Zero),  
resources(exp(target1),            Zero),  
resources(exp(target2),            Zero),  
resources(exp(target3),            Zero),  
resources(exp(target4),            Zero),  
resources(survey(canyon),         Zero),  
resources(id_targets(canyon),     Zero),  
resources(traverse(rock1,canyon), Zero),  
resources(position(rock1),        Zero),  
resources(position(target1),       Zero),  
resources(position(target2),       Zero),  
resources(position(target3),       Zero),  
resources(position(target4),       Zero),  
resources(measures(rock1),        Zero),  
resources(measures(target1),       Zero),  
resources(measures(target2),       Zero),  
resources(measures(target3),       Zero),  
resources(measures(target4),       Zero),  
resources(measuret(rock1),        Zero),  
resources(measuret(target1),       Zero),  
resources(measuret(target2),       Zero),  
resources(measuret(target3),       Zero),  
resources(measuret(target4),       Zero),  
resources(pauseAndRecharge,       Zero),  
resources(recharge,              Zero),    %% These should be reset on each activation of the goal .... 
resources(suspendGoals,         Zero),    
resources(memory,              Zero),    %% These should be reset on each activation of the goal .... 
at(red1),
% thermal(rock1),
% spectral(target),
activate(explore(red1)),
activate(recharge),
activate(memory),
% activate(pauseAndRecharge),
% activate(suspendGoals),
activate(exp(rock1)),
activate(position(rock1)),
activate(measuret(rock1)),
activate(traverse(rock1,canyon)), 
activate(survey(canyon)), 
activate(exp(target1)), 
activate(exp(target2)), 
activate(exp(target3)), 
activate(exp(target4)), 
activate(measures(target1)),
activate(measures(target2)),
activate(measures(target3)),
activate(measures(target4)),
activate(id_targets(canyon)),
activate(position(target1)),
activate(position(target2)),
activate(position(target3)),
activate(position(target4))

]) :-
    resource_zero(Zero). 

find_plan(Name, _Goal, B, Body) :- goal(Name, _, _, _, _, Plans), member(Plan, Plans), plan(Plan, Condition, Body), implies(B, Condition). 

% % find_plan(Name, Goal, B, Plan).
% achieve(Activation, Success, Failure)
% maintain(Activation, Condition, Recovery, Prevention, Success, Failure)
% goal(Name, Goal, Success, Failure, Rules, Plans)
% It is intended that this definition supercedes all others ...

goal(Name, Goal, Success, Failure, Rules, Plans) :- goal_info(Name, Goal, Rules, Plans), Goal = achieve(_, Success, Failure). 
goal(Name, Goal, Success, Failure, Rules, Plans) :- goal_info(Name, Goal, Rules, Plans), Goal = maintain(_, _, _, _, Success, Failure). 

goal_info(explore(red1),achieve([true], [measured(target4)], [false]), Rules, [traverseAndStudy(red1)]) :- 
    rules(explore(red1), [measured(target4)], Rules1), append(Rules1, [act([active(recharge),active(memory)],suspend), act([[inactive(recharge),inactive(memory)]], reactivate)], Rules). 
goal_info(exp(Name),achieve([true], [measured(Name)], [false]), Rules,  [spectroscope(Name),thermalImage(Name)]) :- rules(exp(Name), [measured(Name)], Rules).
goal_info(position(Name),achieve([true], [arm_positioned(Name)], [false]), Rules, [positionArm(Name)]) :- rules(position(Name), [arm_positioned(Name)], Rules).
goal_info(measures(Name),achieve([true], [spectral_profile(Name)], [false]), Rules, [measurementS(Name)]) :- rules(measures(Name), [spectral_profile(Name)], Rules).
goal_info(measuret(Name),achieve([true], [thermal_profile(Name)], [false]), Rules,  [measurementT(Name)]) :- rules(measuret(Name), [thermal_profile(Name)], Rules).
goal_info(traverse(Initial,Final),achieve([true], [at(Final)], [false]), Rules,  [traversAction(Initial,Final)]) :- rules(traverse(Initial,Final), [at(Final)], Rules). 
goal_info(survey(Name),achieve([true], [measured(target4)], [false]), Rules, [surveyPlan(Name)]) :- rules(survey(Name), [measured(target4)], Rules). 
goal_info(id_targets(Name),achieve([true], [targetlist(Name)], [false]), Rules,  [panoramicProcess(Name)]) :- rules(id_targets(Place), [targetlist(Place)], Rules). 
goal_info(recharge, maintain([away_from_base], [battery_charge(X), X >= 30], pauseAndRecharge, pauseAndRecharge, [false], [no_battery_function]), Rules, empty) :- 
    rules(recharge, [], Rules1), append(Rules1, [act([battery_low,active(memory)], respond), act([battery_charge(100)], reactivate)], Rules). 
goal_info(pauseAndRecharge, achieve([battery_low], [battery_charge(100)], [false]), Rules, [pauseAndRechargePlan]) :- rules(pauseAndRecharge, [battery_charge(100)], Rules). 

%goal_info(memory, maintain([away_from_base], [memory_high], suspendGoals, suspendGoals, [false], [no_battery_function]), Rules, empty) :- 
%    rules(memory, [], Rules1), append(Rules1, [act([memory_low], respond), act([memory_high, battery_charge(100)], reactivate)], Rules). 
goal_info(memory, maintain([battery_charge(X), X < 50], [memory_high], suspendGoals, suspendGoals, [false], [no_battery_function]), Rules, empty) :- 
    rules(memory, [], Rules1), append(Rules1, [act([[memory_low,battery_charge(X), X < 50]], respond), act([memory_high, battery_charge(100)], reactivate)], Rules). 
goal_info(suspendGoals, achieve([memory_low],[memory_high],[false]), Rules, [suspendGoalsPlan]) :- rules(suspendGoals, [memory_high], Rules). 

plan(suspendGoalsPlan, [true], [inactive(recharge)::[nil]]). 
plan(pauseAndRechargePlan, [true], [charge_battery]). 
plan(traverseAndStudy(red1), [true], [goal(exp(rock1)), goal(traverse(rock1,canyon)), goal(survey(canyon))]). 
plan(spectroscope(Name), [spectral(Name)], [goal(position(Name)), goal(measures(Name))]). 
plan(thermalImage(Name), [thermal(Name)],  [goal(position(Name)), goal(measuret(Name))]). 
plan(positionArm(Name), [true],  [positionarm(Name)]). 
plan(measurementS(Name), [true],  [measurements(Name)]). 
plan(measurementT(Name), [true],  [measurementt(Name)]). 
plan(traversAction(Initial,Final), [true],  [traverseaction(Initial,Final)]). 
% plan(surveyPlan(Name), [true],  [goal(id_targets(Name)), goal(exp(target))]). 
plan(surveyPlan(Name), [true],  [goal(id_targets(Name)), goal(exp(target1)), goal(exp(target2)), goal(exp(target3)), goal(exp(target4))]). 
plan(panoramicProcess(Name), [true],  [panoramic_process(Name)]). 

% rule(start, true, startplan). 

set_subgoalguard(exp(Name), exptest(Name)). % Need to check out what these were used for ... 
set_subgoalguard(traverse(Initial,Final), traversetest(Initial,Final)). 
set_subgoalguard(survey(Name), surveytest(Name)). 
set_subgoalguard(position(Name), positiontest(Name)). 
set_subgoalguard(measures(Name), measurestest(Name)). 
set_subgoalguard(measuret(Name), measurettest(Name)). 
set_subgoalguard(id_targets(Name), id_targetstest(Name)). 

event(Event, Actions, Goal_Additions) :- general_event(Event, Actions, Goal_Additions). 
event(Event, Actions, Goal_Additions) :- specific_event(Event, Actions, Goal_Additions). 

general_event(drop(Name), [add(drop(Name))], []). 
general_event(abort(Name), [add(abort(Name))], []). 
general_event(suspend(Name), [add(suspend(Name))], []). 
general_event(activate(Name), [add(activate(Name))], []). 
general_event(reactivate(Name), [add(reactivate(Name))], []). 
general_event(reconsider(Name), [add(reconsider(Name))], []). 

specific_event(thermal(Name), [add(thermal(Name))], []). 
specific_event(spectral(Name), [add(spectral(Name))], []). 
specific_event(start5, [], [goal(explore(red1))]). 
specific_event(start6, [], [ [goal(explore(red1))] ## [goal(recharge)] ]). 
specific_event(start7, [], [ [goal(explore(red1))] ## [ [goal(recharge)] ## [goal(memory)] ] ]). 
% specific_event(rock_seen, [add(rock_seen)], []). 
% specific_event(dusk, [add(dusk)], []). 
% specific_event(nearly_dusk, [add(nearly_dusk)], []). 
% specific_event(predict_violation, [add(predict_violation),add(suspend(exp)),add(activate(charge))], []). 

% action(Name, PreCondition, Test, Calculate, Change)
% action(positionarm(Name), [],         [time_count(X)],                   [X1 is X + 120],               [del(time_count(X)), add(time_count(X1)), add(arm_positioned(Name))]). % Make time random choice between 60 (min) and 180 (max)?

% Hack that should be improved ... 

is_action(Action) :- member(Action, [positionarm(_), measurements(_), measurementt(_), traverseaction(_,_), panoramic_process(_), charge_battery]).

action(B, positionarm(Name), [], [time_count(X),battery_charge(Y)], [X1 is X + 120, Y1 is Y - 3], Updates) :-  % Make time random choice between 60 (min) and 180 (max)?
    resource_updates(B, positionarm(Name), Updates1),
    append([del(time_count(X)), add(time_count(X1)), add(arm_positioned(Name)), del(battery_charge(Y)),add(battery_charge(Y1))], Updates1, Updates). 

action(B, measurements(Name), [],        [drill_count(X), memory_count(Y),battery_charge(Z)], [X1 is X + 1, Y1 is Y + 20, Z1 is Z - 5],   Updates) :-
    resource_updates(B, measurements(Name), Updates1),
    append([del(drill_count(X)),  del(memory_count(Y)), del(battery_charge(Z)), add(drill_count(X1)),  add(memory_count(Y1)), add(battery_charge(Z1)), add(spectral_profile(Name))], Updates1, Updates). 

action(B, measurementt(Name), [],        [memory_count(X), time_count(Y),battery_charge(Z)], [X1 is X + 50, Y1 is Y + 25, Z1 is Z - 5],   Updates) :-
    resource_updates(B, measurementt(Name), Updates1),
    append([del(memory_count(X)), del(time_count(Y)),   del(battery_charge(Z)), add(memory_count(X1)), add(time_count(Y1)),   add(battery_charge(Z1)), add(thermal_profile(Name))], Updates1, Updates). 

action(B, traverseaction(Initial, Final), [], [time_count(X), battery_charge(Y)],                  [X1 is X + 200, Y1 is Y - 25],                 Updates) :-
     resource_updates(B, traverseaction(Initial,Final), Updates1),
     append([del(time_count(X)),   add(time_count(X1)), del(battery_charge(Y)), add(battery_charge(Y1)), add(at(Final))], Updates1, Updates),
     true. 

action(B, panoramic_process(Name), [],   [memory_count(X), time_count(Y),battery_charge(Z)], [X1 is X + 100, Y1 is Y + 300, Z1 is Z - 30], Updates) :-
    resource_updates(B, panoramic_process(Name), Updates1),
    append([del(memory_count(X)), del(time_count(Y)), del(battery_charge(Z)), add(memory_count(X1)), add(time_count(Y1)), add(battery_charge(Z1)), add(targetlist(Name))], Updates1, Updates). 

action(B, charge_battery, [],   [memory_count(X), time_count(Y), battery_charge(Z)], [X1 is X + 100, Y1 is Y + 3*(100 - Z), Z1 is 100], Updates) :-
    resource_updates(B, charge_battery, Updates1),
    append([del(memory_count(X)), del(time_count(Y)), del(battery_charge(Z)), add(memory_count(X1)), add(time_count(Y1)), add(battery_charge(Z1))], Updates1, Updates). 

resource_updates(B, positionarm(rock1), Updates) :-
    used_resources(B, explore(red1), Resources1), 
    Changes = [res(drill,0), res(memory,0), res(time,120), res(energy,3)],
    resource_add(Resources1, Changes, NewResources1),
    Updates1 = [del(resources(explore(red1), Resources1)), add(resources(explore(red1), NewResources1))], 

    used_resources(B, exp(rock1), Resources2), 
    resource_add(Resources2, Changes, NewResources2),
    Updates2 = [del(resources(exp(rock1), Resources2)), add(resources(exp(rock1), NewResources2))], 

    used_resources(B, position(rock1), Resources3), 
    resource_add(Resources3, Changes, NewResources3),
    Updates3 = [del(resources(position(rock1), Resources3)), add(resources(position(rock1), NewResources3))], 

%     % format("Updating explore(red1) resources~n", []), 
%     implies(B, [resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1),res(energy,Energy1)])]), 
%     NewTime1 is Time1 + 120, NewEnergy1 is Energy1 + 3, 
%     Updates1 = [del(resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1),res(energy,Energy1)])), add(resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,NewTime1),res(energy,NewEnergy1)]))], 
%     % format("Updating exp(rock1) resources~n", []), 
%
%   implies(B, [resources(exp(rock1), [res(drill,Drill2),res(memory,Memory2),res(time,Time2),res(energy,Energy2)])]), 
%    NewTime2 is Time2 + 120, NewEnergy2 is Energy2 + 3, 
%    Updates2 = [ del(resources(exp(rock1), [res(drill,Drill2),res(memory,Memory2),res(time,Time2),   res(energy,Energy2)])), add(resources(exp(rock1), [res(drill,Drill2),res(memory,Memory2),res(time,NewTime2),res(energy,NewEnergy2)])) ], 
%
%
%    % format("Updating position(rock1) resources~n", []), 
%    implies(B, [resources(position(rock1),  [res(drill,Drill3),res(memory,Memory3),res(time,Time3),res(energy,Energy3)])]), 
%    NewTime3 is Time3 + 120, NewEnergy3 is Energy3 + 3, 
%    Updates3 = [del(resources(position(rock1), [res(drill,Drill3),res(memory,Memory3),res(time,Time3),res(energy,Energy3)])), add(resources(position(rock1), [res(drill,Drill3),res(memory,Memory3),res(time,NewTime3),res(energy,NewEnergy3)]))], 

    append(Updates1, Updates2, Temp),
    append(Temp, Updates3, Updates). 

resource_updates(B, positionarm(Target), Updates) :- 
    member(Target, [target1, target2, target3, target4]), 

    used_resources(B, explore(red1), Resources1), 
    Changes = [res(drill,0), res(memory,0), res(time,120), res(energy,3)],
    resource_add(Resources1, Changes, NewResources1),
    Updates1 = [del(resources(explore(red1), Resources1)), add(resources(explore(red1), NewResources1))], 

%    implies(B, [resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1),res(energy,Energy1)])]), 
%    NewTime1 is Time1 + 120, NewEnergy1 is Energy1 + 3, 
%    Updates1 = [ 
%	del(resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1),res(energy,Energy1)])), 
%	add(resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,NewTime1),res(energy,NewEnergy1)]))
%		], 

    used_resources(B, survey(canyon), Resources2), 
    resource_add(Resources2, Changes, NewResources2),
    Updates2 = [del(resources(survey(canyon), Resources2)), add(resources(survey(canyon), NewResources2))], 
    
%    implies(B, [resources(survey(canyon), [res(drill,Drill2),res(memory,Memory2),res(time,Time2),res(energy,Energy2)])]), 
%    NewTime2 is Time2 + 120, NewEnergy2 is Energy2 + 3, 
%    Updates2 = [del(resources(survey(canyon), [res(drill,Drill2),res(memory,Memory2),res(time,Time2),res(energy,Energy2)])), add(resources(survey(canyon), [res(drill,Drill2),res(memory,Memory2),res(time,NewTime2),res(energy,NewEnergy2)]))], 

    used_resources(B, exp(Target), Resources3), 
    resource_add(Resources3, Changes, NewResources3),
    Updates3 = [del(resources(exp(Target), Resources3)), add(resources(exp(Target), NewResources3))], 

%    implies(B, [resources(exp(Target), [res(drill,Drill3),res(memory,Memory3),res(time,Time3),res(energy,Energy3)])]), 
%    NewTime3 is Time3 + 120, NewEnergy3 is Energy3 + 3, 
%    Updates3 = [del(resources(exp(Target), [res(drill,Drill3),res(memory,Memory3),res(time,Time3),res(energy,Energy3)])), add(resources(exp(Target), [res(drill,Drill3),res(memory,Memory3),res(time,NewTime3),res(energy,NewEnergy3)]))], 

    used_resources(B, position(Target), Resources4), 
    resource_add(Resources4, Changes, NewResources4),
    Updates4 = [del(resources(position(Target), Resources4)), add(resources(position(Target), NewResources4))], 

%    implies(B, [resources(position(Target),  [res(drill,Drill4),res(memory,Memory4),res(time,Time4),res(energy,Energy4)])]), 
%    NewTime4 is Time4 + 120, NewEnergy4 is Energy4 + 3, 
%    Updates4 = [del(resources(position(Target), [res(drill,Drill4),res(memory,Memory4),res(time,Time4),res(energy,Energy4)])), add(resources(position(Target), [res(drill,Drill4),res(memory,Memory4),res(time,NewTime4),res(energy,NewEnergy4)]))], 

    append(Updates1, Updates2, Temp12),
    append(Updates3, Updates4, Temp34),
    append(Temp12, Temp34, Updates). 

resource_updates(B, measurements(rock1), Updates) :- 

    used_resources(B, explore(red1), Resources1),
    Changes = [res(drill,1), res(memory,20), res(time,60), res(energy,5)],
    resource_add(Resources1, Changes, NewResources1),
    Updates1 = [del(resources(explore(red1), Resources1)), add(resources(explore(red1), NewResources1))], 				

%    implies(B, [resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1),res(energy,Energy1)])]), 
%    NewDrill1 is Drill1 + 1, NewMemory1 is Memory1 + 20, NewTime1 is Time1 + 60, NewEnergy1 is Energy1 + 5, 
%    Updates1 = [del(resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1),res(energy,Energy1)])), add(resources(explore(red1), [res(drill,NewDrill1),res(memory,NewMemory1),res(time,NewTime1),res(energy,NewEnergy1)]))], 

    used_resources(B, exp(rock1), Resources2),
    resource_add(Resources2, Changes, NewResources2),
    Updates2 = [del(resources(exp(rock1), Resources2)), add(resources(exp(rock1), NewResources2))], 					       

%    implies(B, [resources(exp(rock1), [res(drill,Drill2),res(memory,Memory2),res(time,Time2),res(energy,Energy2)])]), 
%    NewDrill2 is Drill2 + 1, NewMemory2 is Memory2 + 20, NewTime2 is Time2 + 60, NewEnergy2 is Energy2 + 5, 
%    Updates2 = [del(resources(exp(rock1), [res(drill,Drill2),res(memory,Memory2),res(time,Time2),res(energy,Energy2)])), add(resources(exp(rock1), [res(drill,NewDrill2),res(memory,NewMemory2),res(time,NewTime2),res(energy,NewEnergy2)]))], 
    
    used_resources(B, measures(rock1), Resources3),
    resource_add(Resources3, Changes, NewResources3),
    Updates3 = [del(resources(measures(rock1), Resources3)), add(resources(measures(rock1), NewResources3))], 					       

%    implies(B, [resources(measures(rock1),  [res(drill,Drill3),res(memory,Memory3),res(time,Time3),res(energy,Energy3)])]), 
%    NewDrill3 is Drill3 + 1, NewMemory3 is Memory3 + 20, NewTime3 is Time3 + 60, NewEnergy3 is Energy3 + 5, 
%    Updates3 = [del(resources(measures(rock1), [res(drill,Drill3),res(memory,Memory3),res(time,Time3),res(energy,Energy3)])), add(resources(measures(rock1), [res(drill,NewDrill3),res(memory,NewMemory3),res(time,NewTime3),res(energy,NewEnergy3)]))], 

    append(Updates1, Updates2, Temp),
    append(Temp, Updates3, Updates). 

resource_updates(B, measurementt(rock1), Updates) :- 

    used_resources(B, explore(red1), Resources1),
    Changes = [res(drill,0), res(memory,50), res(time,25), res(energy,5)],
    resource_add(Resources1, Changes, NewResources1),
    Updates1 = [del(resources(explore(red1), Resources1)), add(resources(explore(red1), NewResources1))], 				

%    implies(B, [resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1),res(energy,Energy1)])]), 
%    NewMemory1 is Memory1 + 50, NewTime1 is Time1 + 25, NewEnergy1 is Energy1 + 5, 
%    Updates1 = [del(resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1),res(energy,Energy1)])), add(resources(explore(red1), [res(drill,Drill1),res(memory,NewMemory1),res(time,NewTime1),res(energy,NewEnergy1)]))], 

    used_resources(B, exp(rock1), Resources2),
    resource_add(Resources2, Changes, NewResources2),
    Updates2 = [del(resources(exp(rock1), Resources2)), add(resources(exp(rock1), NewResources2))], 				

%    implies(B, [resources(exp(rock1), [res(drill,Drill2),res(memory,Memory2),res(time,Time2),res(energy,Energy2)])]), 
%    NewMemory2 is Memory2 + 50, NewTime2 is Time2 + 25, NewEnergy2 is Energy2 + 5, 
%    Updates2 = [del(resources(exp(rock1), [res(drill,Drill2),res(memory,Memory2),res(time,Time2),res(energy,Energy2)])), add(resources(exp(rock1), [res(drill,Drill2),res(memory,NewMemory2),res(time,NewTime2),res(energy,NewEnergy2)]))], 

    used_resources(B, measuret(rock1), Resources3),
    resource_add(Resources3, Changes, NewResources3),
    Updates3 = [del(resources(measuret(rock1), Resources3)), add(resources(measuret(rock1), NewResources3))], 				

%    implies(B, [resources(measuret(rock1),  [res(drill,Drill3),res(memory,Memory3),res(time,Time3),res(energy,Energy3)])]), 
%    NewMemory3 is Memory3 + 50, NewTime3 is Time3 + 25, NewEnergy3 is Energy3 + 5, 
%    Updates3 = [del(resources(measuret(rock1), [res(drill,Drill3),res(memory,Memory3),res(time,Time3),res(energy,Energy3)])), add(resources(measuret(rock1), [res(drill,Drill3),res(memory,NewMemory3),res(time,NewTime3),res(energy,NewEnergy3)]))], 

    append(Updates1, Updates2, Temp),
    append(Temp, Updates3, Updates).

resource_updates(B, measurements(Target), Updates)  :- 
    member(Target, [target1,target2,target3,target4]), 

    used_resources(B, explore(red1), Resources1),
    Changes = [res(drill,1), res(memory,20), res(time,60), res(energy,5)],
    resource_add(Resources1, Changes, NewResources1),
    Updates1 = [del(resources(explore(red1), Resources1)), add(resources(explore(red1), NewResources1))], 				

%    implies(B, [resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1),res(energy,Energy1)])]), 
%    NewDrill1 is Drill1 + 1, NewMemory1 is Memory1 + 20, NewTime1 is Time1 + 60, NewEnergy1 is Energy1 + 5, 
%    Updates1 = [del(resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1),res(energy,Energy1)])), add(resources(explore(red1), [res(drill,NewDrill1),res(memory,NewMemory1),res(time,NewTime1),res(energy,NewEnergy1)]))], 

    used_resources(B, survey(canyon), Resources2),
    resource_add(Resources2, Changes, NewResources2),
    Updates2 = [del(resources(survey(canyon), Resources2)), add(resources(survey(canyon), NewResources2))], 				

%    implies(B, [resources(survey(canyon), [res(drill,Drill2),res(memory,Memory2),res(time,Time2),res(energy,Energy2)])]), 
%    NewDrill2 is Drill2 + 1, NewMemory2 is Memory2 + 20, NewTime2 is Time2 + 60, NewEnergy2 is Energy2 + 5, 
%    Updates2 = [del(resources(survey(canyon), [res(drill,Drill2),res(memory,Memory2),res(time,Time2),res(energy,Energy2)])), add(resources(survey(canyon), [res(drill,NewDrill2),res(memory,NewMemory2),res(time,NewTime2),res(energy,NewEnergy2)]))], 

    used_resources(B, exp(Target), Resources3),
    resource_add(Resources3, Changes, NewResources3),
    Updates3 = [del(resources(exp(Target), Resources3)), add(resources(exp(Target), NewResources3))], 				

%    implies(B, [resources(exp(Target), [res(drill,Drill3),res(memory,Memory3),res(time,Time3),res(energy,Energy3)])]), 
%    NewDrill3 is Drill3 + 1, NewMemory3 is Memory3 + 20, NewTime3 is Time3 + 60, NewEnergy3 is Energy3 + 5, 
%    Updates3 = [del(resources(exp(Target), [res(drill,Drill3),res(memory,Memory3),res(time,Time3),res(energy,Energy3)])), add(resources(exp(Target), [res(drill,NewDrill3),res(memory,NewMemory3),res(time,NewTime3),res(energy,NewEnergy3)]))], 

    used_resources(B, measures(Target), Resources4),
    resource_add(Resources4, Changes, NewResources4),
    Updates4 = [del(resources(measures(Target), Resources4)), add(resources(measures(Target), NewResources4))], 				

%    implies(B, [resources(measures(Target),  [res(drill,Drill4),res(memory,Memory4),res(time,Time4),res(energy,Energy4)])]), 
%    NewDrill4 is Drill4 + 1, NewMemory4 is Memory4 + 20, NewTime4 is Time4 + 60, NewEnergy4 is Energy4 + 5, 
%    Updates4 = [del(resources(measures(Target), [res(drill,Drill4),res(memory,Memory4),res(time,Time4),res(energy,Energy4)])), add(resources(measures(Target), [res(drill,NewDrill4),res(memory,NewMemory4),res(time,NewTime4),res(energy,NewEnergy4)]))], 

    append(Updates1, Updates2, Temp12),
    append(Updates3, Updates4, Temp34),
    append(Temp12, Temp34, Updates). 

resource_updates(B, measurementt(Target), Updates) :- 
    member(Target, [target1,target2,target3,target4]), 

    used_resources(B, explore(red1), Resources1),
    Changes = [res(drill,0), res(memory,50), res(time,25), res(energy,5)],
    resource_add(Resources1, Changes, NewResources1),
    Updates1 = [del(resources(explore(red1), Resources1)), add(resources(explore(red1), NewResources1))], 				

%    implies(B, [resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1),res(energy,Energy1)])]), 
%    NewMemory1 is Memory1 + 50, NewTime1 is Time1 + 25, NewEnergy1 is Energy1 + 5, 
%    Updates1 = [del(resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1),res(energy,Energy1)])), add(resources(explore(red1), [res(drill,Drill1),res(memory,NewMemory1),res(time,NewTime1),res(energy,NewEnergy1)]))], 

    used_resources(B, survey(canyon), Resources2),
    resource_add(Resources2, Changes, NewResources2),
    Updates2 = [del(resources(survey(canyon), Resources2)), add(resources(survey(canyon), NewResources2))], 				

%    implies(B, [resources(survey(canyon), [res(drill,Drill2),res(memory,Memory2),res(time,Time2),res(energy,Energy2)])]), 
%    NewMemory2 is Memory2 + 50, NewTime2 is Time2 + 25, NewEnergy2 is Energy2 + 5, 
%    Updates2 = [del(resources(survey(canyon), [res(drill,Drill2),res(memory,Memory2),res(time,Time2),res(energy,Energy2)])), add(resources(survey(canyon), [res(drill,Drill2),res(memory,NewMemory2),res(time,NewTime2),res(energy,NewEnergy2)]))], 

    used_resources(B, exp(Target), Resources3),
    resource_add(Resources3, Changes, NewResources3),
    Updates3 = [del(resources(exp(Target), Resources3)), add(resources(exp(Target), NewResources3))], 				

%    implies(B, [resources(exp(Target), [res(drill,Drill3),res(memory,Memory3),res(time,Time3),res(energy,Energy3)])]), 
%    NewMemory3 is Memory3 + 50, NewTime3 is Time3 + 25, NewEnergy3 is Energy3 + 5, 
%    Updates3 = [del(resources(exp(Target), [res(drill,Drill3),res(memory,Memory3),res(time,Time3),res(energy,Energy3)])), add(resources(exp(Target), [res(drill,Drill3),res(memory,NewMemory3),res(time,NewTime3),res(energy,NewEnergy3)]))], 

    used_resources(B, measuret(Target), Resources4),
    resource_add(Resources4, Changes, NewResources4),
    Updates4 = [del(resources(measuret(Target), Resources4)), add(resources(measuret(Target), NewResources4))], 				

%    implies(B, [resources(measuret(Target),  [res(drill,Drill4),res(memory,Memory4),res(time,Time4),res(energy,Energy4)])]), 
%    NewMemory4 is Memory4 + 50, NewTime4 is Time4 + 25, NewEnergy4 is Energy4 + 5, 
%    Updates4 = [del(resources(measuret(Target), [res(drill,Drill4),res(memory,Memory4),res(time,Time4),res(energy,Energy4)])), add(resources(measuret(Target), [res(drill,Drill4),res(memory,NewMemory4),res(time,NewTime4),res(energy,NewEnergy4)]))], 

    append(Updates1, Updates2, Temp12),
    append(Updates3, Updates4, Temp34),
    append(Temp12, Temp34, Updates). 

resource_updates(B, traverseaction(rock1,canyon), Updates) :- 
    % format("Updating explore(red1) resources~n", []), output_state(state(B,[])), 

    used_resources(B, explore(red1), Resources1),
    Changes = [res(drill,0), res(memory,0), res(time,200), res(energy,25)],
    resource_add(Resources1, Changes, NewResources1),
    Updates1 = [del(resources(explore(red1), Resources1)), add(resources(explore(red1), NewResources1))], 				
 
%   implies(B, [resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1),res(energy,Energy1)])]),
%    NewTime1 is Time1 + 200, NewEnergy1 is Energy1 + 25, 
%    Updates1 = [del(resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1),res(energy,Energy1)])), add(resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,NewTime1),res(energy,NewEnergy1)]))], 

    used_resources(B, traverse(rock1,canyon), Resources2),
    resource_add(Resources2, Changes, NewResources2),
    Updates2 = [del(resources(traverse(rock1,canyon), Resources2)), add(resources(traverse(rock1,canyon), NewResources2))], 				
%    implies(B, [resources(traverse(rock1, canyon), [res(drill,Drill2),res(memory,Memory2),res(time,Time2),res(energy,Energy2)])]), 
%    NewTime2 is Time2 + 200, NewEnergy2 is Energy2 + 25, 
%    Updates2 = [del(resources(traverse(rock1,canyon), [res(drill,Drill2),res(memory,Memory2),res(time,Time2),res(energy,Energy2)])), add(resources(traverse(rock1,canyon), [res(drill,Drill2),res(memory,Memory2),res(time,NewTime2),res(energy,NewEnergy2)]))], 

    append(Updates1, Updates2, Updates).

resource_updates(B, panoramic_process(canyon), Updates) :-
 
    used_resources(B, explore(red1), Resources1),
    Changes = [res(drill,0), res(memory,100), res(time,300), res(energy,30)],
    resource_add(Resources1, Changes, NewResources1),
    Updates1 = [del(resources(explore(red1), Resources1)), add(resources(explore(red1), NewResources1))], 				

%   implies(B, [resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1),res(energy,Energy1)])]), 
%    NewMemory1 is Memory1 + 100, NewTime1 is Time1 + 300, NewEnergy1 is Energy1 + 30,  
%    Updates1 = [
%	del(resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),   res(time,Time1)   ,res(energy,Energy1)])), 
%        add(resources(explore(red1), [res(drill,Drill1),res(memory,NewMemory1),res(time,NewTime1),res(energy,NewEnergy1)]))
%               ], 

    used_resources(B, survey(canyon), Resources2),
    resource_add(Resources2, Changes, NewResources2),
    Updates2 = [del(resources(survey(canyon), Resources2)), add(resources(survey(canyon), NewResources2))], 				

%    implies(B, [resources(survey(canyon), [res(drill,Drill2),res(memory,Memory2),res(time,Time2),res(energy,Energy2)])]), 
%    NewMemory2 is Memory2 + 100, NewTime2 is Time2 + 300, NewEnergy2 is Energy2 + 30,  
%    Updates2 = [
%	del(resources(survey(canyon), [res(drill,Drill2),res(memory,Memory2),res(time,Time2),res(energy,Energy2)])), 
%	add(resources(survey(canyon), [res(drill,Drill2),res(memory,NewMemory2),res(time,NewTime2),res(energy,NewEnergy2)]))  ], 

    used_resources(B, survey(canyon), Resources3),
    resource_add(Resources3, Changes, NewResources3),
    Updates3 = [del(resources(is_targets(canyon), Resources3)), add(resources(id_targets(canyon), NewResources3))], 				

%    implies(B, [resources(id_targets(canyon), [res(drill,Drill3),res(memory,Memory3),res(time,Time3),res(energy,Energy3)])]), 
%    NewMemory3 is Memory3 + 100, NewTime3 is Time3 + 300, NewEnergy3 is Energy3 + 30,  
%    Updates3 = [del(resources(id_targets(canyon), [res(drill,Drill3),res(memory,Memory3),res(time,Time3),res(energy,Energy3)])), add(resources(id_targets(canyon), [res(drill,Drill3),res(memory,NewMemory3),res(time,NewTime3),res(energy,NewEnergy3)]))], 

    append(Updates1, Updates2, Temp),
    append(Temp, Updates3, Updates). 

% action(B, charge_battery, [],   [memory_count(X), time_count(Y), battery_charge(Z)], [X1 is X + 100, Y1 is Y + 3*(100 - Z), Z1 is 100], Updates) :-

resource_updates(B, charge_battery, Updates) :-

    implies(B, [resources(pauseAndRecharge, [res(drill,Drill1),res(memory,Memory1),res(time,Time1),res(energy,Energy1)])]), 
    NewMemory1 is Memory1 + 100, NewTime1 is Time1 + 3*(100-Energy1), 
    Updates1 = [
	del(resources(pauseAndRecharge, [res(drill,Drill1),res(memory,Memory1),   res(time,Time1)   ,res(energy,Energy1)])), 
        add(resources(pauseAndRecharge, [res(drill,Drill1),res(memory,NewMemory1),res(time,NewTime1),res(energy,Energy1)]))
               ], 

    implies(B, [resources(recharge, [res(drill,Drill2),res(memory,Memory2),res(time,Time2),res(energy,Energy2)])]), 
    NewMemory2 is Memory2 + 100, NewTime2 is Time2 + 3*(100-Energy2), 
    Updates2 = [
	del(resources(recharge, [res(drill,Drill2),res(memory,Memory2),res(time,Time2),res(energy,Energy2)])), 
	add(resources(recharge, [res(drill,Drill2),res(memory,NewMemory2),res(time,NewTime2),res(energy,Energy2)]))  ], 

    append(Updates1, Updates2, Updates). 

%% Think some more about this

update_resources([], _, []).
update_resources([res(Name,Amount1)|Rest], DR, [res(Name,Amount1)|Result]) :-
    member(res(Name,Amount2), DR), Amount1 > Amount2,
    update_resources(Rest, DR, Result).
update_resources([res(Name,Amount1)|Rest], DR, [res(Name,Amount2)|Result]) :-
    member(res(Name,Amount2), DR), Amount1 =< Amount2,
    update_resources(Rest, DR, Result).

% resource_summary(B, Name, CR, DR, PR) :-
resource_summary(B, traverse(rock1,canyon), Zero, [res(drill,0), res(memory,0),   res(time,100),res(energy,5)], [res(drill,0),res(memory,0),   res(time,300),res(energy,10)]) :-  
    \+ implies(B, [completed(traverse(rock1,canyon))]), resource_zero(Zero).
resource_summary(B, traverse(rock1,canyon), Resources, Zero, Zero) :-  
    implies(B, [completed(traverse(rock1,canyon))]), used_resources(B, traverse(rock1,canyon), Resources), resource_zero(Zero). 
resource_summary(B, id_targets(canyon),     Zero, [res(drill,0), res(memory,100), res(time,300),res(energy,20)], [res(drill,0),res(memory,100), res(time,300),res(energy,20)]) :- 
    \+ implies(B, [completed(id_targets(canyon))]), resource_zero(Zero).
resource_summary(B, id_targets(canyon),     Resources, Zero, Zero) :- 
    implies(B, [completed(id_targets(canyon))]),  used_resources(B, id_targets(canyon), Resources), resource_zero(Zero). 

resource_summary(B, position(Name),        Zero, [res(drill,0), res(memory,0),   res(time,60),res(energy,2)],  [res(drill,0),res(memory,0),   res(time,180),res(energy,4)]) :-
    \+ implies(B, [completed(position(Name))]), resource_zero(Zero).
resource_summary(B, position(Name),        Resources, Zero, Zero) :-
    implies(B, [completed(position(Name))]),  used_resources(B, position(Name), Resources), resource_zero(Zero). 

resource_summary(B, measures(Name),        Zero, [res(drill,1), res(memory,20),  res(time,40),res(energy,4)],  [res(drill,1),res(memory,20),  res(time,80),res(energy,8)]) :- 
    \+ implies(B, [completed(measures(Name))]), resource_zero(Zero).
resource_summary(B, measures(Name),        Resources, Zero, Zero) :- 
    implies(B, [completed(measures(Name))]), used_resources(B, measures(Name), Resources), resource_zero(Zero). 
resource_summary(B, measuret(Name),        Zero, [res(drill,0), res(memory,50),  res(time,20),res(energy,4)],  [res(drill,0),res(memory,50),  res(time,30),res(energy,8)]) :-
    \+ implies(B, [completed(measuret(Name))]), resource_zero(Zero).
resource_summary(B, measuret(Name),        Resources, Zero, Zero) :-
    implies(B, [completed(measures(Name))]), used_resources(B, measuret(Name), Resources), resource_zero(Zero). 

resource_summary(B, explore(red1), Current_Resources,  Zero, Zero) :-
    implies(B, [completed(explore(red1))]), used_resources(B, explore(red1), Current_Resources), resource_zero(Zero). 
resource_summary(B, explore(red1), Current_Resources, Min_Resources, Max_Resources) :-
    \+ implies(B, [completed(explore(red1))]), 
    resource_summary_total(B, [exp(rock1), traverse(rock1,canyon), survey(canyon)], Current_Resources,  Min_Resources, Max_Resources). 

resource_summary(B, survey(canyon), Current_Resources, Zero, Zero) :-
    implies(B, [completed(survey(canyon))]), used_resources(B, survey(canyon), Current_Resources), resource_zero(Zero). 
resource_summary(B, survey(canyon), Current_Resources, Min_Resources, Max_Resources) :-
    \+ implies(B, [completed(survey(canyon))]), 
    resource_summary_total(B, [id_targets(canyon), exp(target1), exp(target2), exp(target3), exp(target4)], Current_Resources, Min_Resources, Max_Resources). 

resource_summary(B, exp(Name), Current_Resources, Zero,  Zero) :-
    implies(B, [completed(exp(Name))]), used_resources(B, exp(Name), Current_Resources), resource_zero(Zero). 
resource_summary(B, exp(Name), Current_Resources, Min_Resources, Max_Resources) :-
    \+ implies(B, [completed(exp(Name))]), %% Need to know which branch to use, and whether to use the lot or not. 
    \+ implies(B, [spectral(Name)]), \+ implies(B, [thermal(Name)]), %% Not known which branch to take, so assume no computation yet and do the lot
    format("Neither branch known for exp(~k)~n", [Name]), 
    resource_summary_total(B, [position(Name), measures(Name)], Current_Resources1, Min_Resources1, Max_Resources1),
    resource_summary_total(B, [position(Name), measuret(Name)], Current_Resources2, Min_Resources2, Max_Resources2),
    % format("Combining~n", []), ttyflush, 
    combine_resources_min(Min_Resources1, Min_Resources2, Min_Resources),
    combine_resources_max(Max_Resources1, Max_Resources2, Max_Resources),
    resource_add(Current_Resources1, Current_Resources2, Current_Resources),
    true. 
resource_summary(B, exp(Name), Current_Resources, Min_Resources, Max_Resources) :-
    \+ implies(B, [completed(exp(Name))]), %% Need to know which branch to use, and whether to use the lot or not. 
    implies(B, [spectral(Name)]), % spectral branch
    format("Spectral branch for exp(~k)~n", [Name]), 
    resource_summary_total(B, [position(Name), measures(Name)], Current_Resources, Min_Resources, Max_Resources),
    % format("Done Spectral branch~n", []), 
    true. 

resource_summary(B, exp(Name), Current_Resources, Min_Resources, Max_Resources) :-
    \+ implies(B, [completed(exp(Name))]), %% Need to know which branch to use, and whether to use the lot or not. 
    implies(B, [thermal(Name)]), % thermal branch
    format("Thermal branch for exp(~k)~n", [Name]), 
    resource_summary_total(B, [position(Name), measuret(Name)], Current_Resources, Min_Resources, Max_Resources),
    % format("Done Thermal branch~n", []), 
    true. 

resource_summary(B, recharge, Current_Resources, Zero, Zero) :-
    \+ implies(B, [active(recharge)]), used_resources(B, recharge, Current_Resources), resource_zero(Zero). 
resource_summary(B, recharge, Current_Resources, Min_Resources, Max_Resources) :-
    implies(B, [active(recharge)]), resource_summary(B, pauseAndRecharge, Current_Resources, Min_Resources, Max_Resources).

resource_summary(B, pauseAndRecharge, Current_Resources, Zero, Zero) :-
    implies(B, [completed(pauseAndRecharge)]), used_resources(B, pauseAndRecharge, Current_Resources), resource_zero(Zero). 
resource_summary(B, pauseAndRecharge, Zero, Min_Resources, Max_Resources) :-
    \+ implies(B, [completed(pauseAndRecharge)]), 
     Min_Resources = [res(drill,0), res(memory, 50),  res(time,10),  res(energy,0)],
     Max_Resources = [res(drill,0), res(memory, 150), res(time,300), res(energy,0)],
     resource_zero(Zero). 

resource_summary(B, memory, Current_Resources, Zero, Zero) :-
    \+ implies(B, [active(memory)]), used_resources(B, memory, Current_Resources), resource_zero(Zero). 
resource_summary(B, memory, Current_Resources, Min_Resources, Max_Resources) :-
    implies(B, [active(memory)]), 
    resource_summary(B, suspendGoals, Current_Resources, Min_Resources, Max_Resources). 

resource_summary(B,suspendGoals, Current_Resources, Zero, Zero) :-
    implies(B, [completed(suspendGoals)]), used_resources(B, memory, Current_Resources), resource_zero(Zero). 
resource_summary(B, suspendGoals, Current_Resources, Zero, Zero) :-
    \+ implies(B, [completed(suspendGoals)]), 
     Min_Resources = [res(drill,0), res(memory, 20), res(time,30), res(energy,0)],
     Max_Resources = [res(drill,0), res(memory, 60), res(time,70), res(energy,0)],
    resource_zero(Zero). 

resource_zero([res(drill,0), res(memory,0), res(time,0),res(energy,0)]). 
resource_summary_total(B, List, Current_Resources, Min_Resources, Max_Resources) :-
    resource_zero(Zero), 
    resource_summary_total1(B, List, Zero, Zero, Zero, Current_Resources, Min_Resources, Max_Resources).

resource_summary_total1(_B, [], CurSoFar, MinSoFar, MaxSoFar, CurSoFar, MinSoFar, MaxSoFar).
resource_summary_total1(B, [Name|Rest], CurSoFar, MinSoFar, MaxSoFar, Current_Resources, Min_Resources, Max_Resources) :-
    % format("Getting summary for ~k~n", [Name]), 
    resource_summary(B, Name, Cur_Name, Min_Name, Max_Name), 
    % format("Adding ", []), write(Min_Name), format(" and ", []), write(MinSoFar), nl, 
    resource_add(Cur_Name, CurSoFar, NewCurSoFar), 
    resource_add(Min_Name, MinSoFar, NewMinSoFar),
    % format("Adding ", []), write(Max_Name), format(" and ", []), write(MaxSoFar), nl, 
    resource_add(Max_Name, MaxSoFar, NewMaxSoFar),
    resource_summary_total1(B, Rest, NewCurSoFar, NewMinSoFar, NewMaxSoFar, Current_Resources, Min_Resources, Max_Resources). 

resource_add([res(drill,Drill1),res(memory,Memory1),res(time,Time1),res(energy,Energy1)], [res(drill,Drill2),res(memory,Memory2),res(time,Time2),res(energy,Energy2)], [res(drill,Drill3),res(memory,Memory3),res(time,Time3),res(energy,Energy3)]) :-
    Drill3 is Drill1 + Drill2, 
    Memory3 is Memory1 + Memory2, 
    Time3 is Time1 + Time2, 
    Energy3 is Energy1 + Energy2, 
    true. 

combine_resources_min(Min_Resources1, Min_Resources2, Min_Resources3) :-
    Min_Resources1 = [res(drill,Drill1),res(memory,Memory1),res(time,Time1),res(Energy1)], 
    Min_Resources2 = [res(drill,Drill2),res(memory,Memory2),res(time,Time2),res(Energy2)], 
    Drill3 is min(Drill1, Drill2), 
    Memory3 is min(Memory1, Memory2), 
    Time3 is min(Time1, Time2), 
    Energy3 is min(Energy1, Energy2), 
    Min_Resources3 = [res(drill,Drill3),res(memory,Memory3),res(time,Time3),res(Energy3)], 
    true. 

combine_resources_max(Max_Resources1, Max_Resources2, Max_Resources3) :-
    Max_Resources1 = [res(drill,Drill1),res(memory,Memory1),res(time,Time1),res(Energy1)], 
    Max_Resources2 = [res(drill,Drill2),res(memory,Memory2),res(time,Time2),res(Energy2)], 
    Drill3 is max(Drill1, Drill2), 
    Memory3 is max(Memory1, Memory2), 
    Time3 is max(Time1, Time2), 
    Energy3 is max(Energy1, Energy2), 
    Max_Resources3 = [res(drill,Drill3),res(memory,Memory3),res(time,Time3),res(Energy3)], 
    true. 

used_resources(B, Name, Resources) :- 
    % format("Finding resources for ~k~n", [Name]), 
    implies(B, [resources(Name, Resources)]), 
    true. 

current_resources(B, Resources) :- 
    implies(B, [drill_count(Drill), memory_count(Memory), time_count(Time),battery_charge(Energy)]), 
    Resources = [res(drill,Drill),  res(memory,Memory), res(time,Time),res(energy,Energy)].

% effect_summary(Name, Success, Definite, Possible). 
effect_summary(explore(red1),           [eff(targetlist(canyon),1), eff(at(canyon),1), eff(measured(rock1),1), eff(measured(target),1)],  [eff(targetlist(canyon),1), eff(at(canyon),1), eff(measured(rock1),1), eff(measured(target),1)], [eff(spectral_profile(rock1),1), eff(thermal_profile(rock1),1), eff(spectral_profile(target),1), eff(thermal_profile(target),1)]). 
effect_summary(survey(canyon),          [eff(targetlist(canyon),1), eff(measured(target),1)], [eff(targetlist(canyon),1), eff(arm_positioned(target),1), eff(measured(target),1)], [eff(spectral_profile(target),1), eff(thermal_profile(target),1)]). 
effect_summary(exp(rock1),              [eff(measured(rock1),1)], [eff(arm_positioned(rock1),1), eff(measured(rock1),1)], [eff(spectral_profile(rock1),1), eff(thermal_profile(rock1),1)]). 
effect_summary(exp(target),             [eff(measured(target),1)], [eff(arm_positioned(target),1), eff(measured(target),1)], [eff(spectral_profile(target),1), eff(thermal_profile(target),1)]). 
effect_summary(exp(target1),            [eff(measured(target1),1)], [eff(arm_positioned(target1),1), eff(measured(target1),1)], [eff(spectral_profile(target1),1), eff(thermal_profile(target1),1)]). 
effect_summary(exp(target2),            [eff(measured(target2),1)], [eff(arm_positioned(target2),1), eff(measured(target2),1)], [eff(spectral_profile(target2),1), eff(thermal_profile(target2),1)]). 
effect_summary(exp(target3),            [eff(measured(target3),1)], [eff(arm_positioned(target3),1), eff(measured(target3),1)], [eff(spectral_profile(target3),1), eff(thermal_profile(target3),1)]). 
effect_summary(exp(target4),            [eff(measured(target4),1)], [eff(arm_positioned(target4),1), eff(measured(target4),1)], [eff(spectral_profile(target4),1), eff(thermal_profile(target4),1)]). 
effect_summary(position(rock1),         [eff(arm_positioned(rock1),1)], [eff(arm_positioned(rock1),1)], []). 
effect_summary(position(target),        [eff(arm_positioned(target),1)],[eff(arm_positioned(target),1)], []). 
effect_summary(position(target1),       [eff(arm_positioned(target1),1)],[eff(arm_positioned(target1),1)], []). 
effect_summary(position(target2),       [eff(arm_positioned(target2),1)],[eff(arm_positioned(target2),1)], []). 
effect_summary(position(target3),       [eff(arm_positioned(target3),1)],[eff(arm_positioned(target3),1)], []). 
effect_summary(position(target4),       [eff(arm_positioned(target4),1)],[eff(arm_positioned(target4),1)], []). 
effect_summary(measures(rock1),         [eff(measured(rock1),1)],       [eff(measured(rock1),1), eff(spectral_profile(rock1),1)], []). 
effect_summary(measures(target),        [eff(measured(target),1)],      [eff(measured(target),1), eff(spectral_profile(target),1)], []). 
effect_summary(measures(target1),        [eff(measured(target1),1)],      [eff(measured(target1),1), eff(spectral_profile(target1),1)], []). 
effect_summary(measures(target2),        [eff(measured(target2),1)],      [eff(measured(target2),1), eff(spectral_profile(target2),1)], []). 
effect_summary(measures(target3),        [eff(measured(target3),1)],      [eff(measured(target3),1), eff(spectral_profile(target3),1)], []). 
effect_summary(measures(target4),        [eff(measured(target4),1)],      [eff(measured(target4),1), eff(spectral_profile(target4),1)], []). 
effect_summary(measuret(rock1),         [eff(measured(rock1),1)],       [eff(measured(rock1),1), eff(thermal_profile(rock1),1)], []). 
effect_summary(measuret(target),        [eff(measured(target),1)],      [eff(measured(target),1), eff(thermal_profile(target),1)], []). 
effect_summary(measuret(target1),        [eff(measured(target1),1)],      [eff(measured(target1),1), eff(thermal_profile(target1),1)], []). 
effect_summary(measuret(target2),        [eff(measured(target2),1)],      [eff(measured(target2),1), eff(thermal_profile(target2),1)], []). 
effect_summary(measuret(target3),        [eff(measured(target3),1)],      [eff(measured(target3),1), eff(thermal_profile(target3),1)], []). 
effect_summary(measuret(target4),        [eff(measured(target4),1)],      [eff(measured(target4),1), eff(thermal_profile(target4),1)], []). 
effect_summary(traverse(rock1,canyon),  [eff(at(canyon),1)], [eff(at(canyon),1)], []). 
effect_summary(id_targets(canyon),      [eff(targetlist(canyon),1)], [eff(targetlist(canyon),1)], []). 
effect_summary(recharge,                [eff(battery_charge(100),1)], [eff(battery_charge(100),1)], []). 
effect_summary(pauseAndRecharge,        [eff(battery_charge(100),1)], [eff(battery_charge(100),1)], []). 
effect_summary(memory,                  [eff(memory_high,1)], [eff(memory_high,1)], []). 
effect_summary(suspendGoals,            [eff(memory_high,1)], [eff(memory_high,1)], []). 

% discrete effects alone for now. 
current_effects(B, DE, PE, CE, CPE) :- 
    implies_which(B, DE, CE), 
    implies_which(B, PE, CPE).

implies_which(_B, [], []). % Discrete effects only ... 
implies_which(B, [Goal|Goals], [eff(G,1)| Result]) :-
    Goal = eff(G,_), 
    implies(B, [G]), 
    implies_which(B, Goals, Result). 
implies_which(B, [Goal|Goals], [eff(G,0)|Result]) :-
    Goal = eff(G,_), 
    \+ implies(B, [G]), 
    implies_which(B, Goals, Result). 

% Hacky stuff to make things work. Need to do better than this!

implies_single(B, G) :- specific_list(L), \+ member(G, L), member(G, B). 
implies_single(_B, G) :- specific_list(L), \+ member(G, L), G. % For built-ins. Yuk!
implies_single(B, G) :- specific_list(L), \+ member(G, L), member(rule(Head, Body), B), Head = G, implies(B, Body). 
implies_single(B, G) :- specific_list(L), member(G, L), member(G, B). 
implies_single(B,exploretest(red1)) :- implies(B, [measured((canyon))]).
implies_single(B,exploretest(red1)) :- implies(B, [drop(explore(red1))]).
implies_single(B,exploretest(red1)) :- implies(B, [abort(explore(red1))]).
implies_single(B,exptest(Name)) :- implies(B, [measured((Name))]).
implies_single(B,exptest(Name)) :- implies(B, [drop(exp(Name))]).
implies_single(B,exptest(Name)) :- implies(B, [abort(exp(Name))]).
implies_single(B,traversetest(_Initial,Final)) :- implies(B, [at(Final)]).
implies_single(B,traversetest(Initial,Final)) :- implies(B, [drop(traverse(Initial,Final))]).
implies_single(B,traversetest(Initial,Final)) :- implies(B, [abort(traverse(Initial,Final))]).
implies_single(B,surveytest(Name)) :- implies(B, [measured((Name))]).
implies_single(B,surveytest(Name)) :- implies(B, [drop(survey(Name))]).
implies_single(B,surveytest(Name)) :- implies(B, [abort(survey(Name))]).
implies_single(B,positiontest(Name)) :- implies(B, [arm_positioned((Name))]).
implies_single(B,positiontest(Name)) :- implies(B, [drop(position(Name))]).
implies_single(B,positiontest(Name)) :- implies(B, [abort(position(Name))]).
implies_single(B,measurestest(Name)) :- implies(B, [spectral_profile((Name))]).
implies_single(B,measurestest(Name)) :- implies(B, [drop(measures(Name))]).
implies_single(B,measurestest(Name)) :- implies(B, [abort(measures(Name))]).
implies_single(B,measurettest(Name)) :- implies(B, [thermal_profile((Name))]).
implies_single(B,measurettest(Name)) :- implies(B, [drop(measuret(Name))]).
implies_single(B,measurettest(Name)) :- implies(B, [abort(measuret(Name))]).
implies_single(B,id_targetstest(Name)) :- implies(B, [targetlist(Name)]).
implies_single(B,id_targetstest(Name)) :- implies(B, [drop(id_targets(Name))]).
implies_single(B,id_targetstest(Name)) :- implies(B, [abort(id_targets(Name))]).
implies_single(B,measured(Name)) :- implies(B, [spectral_profile((Name))]).
implies_single(B,measured(Name)) :- implies(B, [thermal_profile((Name))]).
implies_single(B,battery_low) :- implies(B, [battery_charge(X)]), X < 30. 
implies_single(B,inactive(Name)) :- \+ implies(B, [active(Name)]). 
implies_single(B,memory_low) :- implies(B, [memory_count(X)]), X > 150. 
implies_single(B,memory_high) :- implies(B, [memory_count(X)]), X =< 150. 

specific_list( [exploretest(_), exptest(_), traversetest(_,_),surveytest(_),positiontest(_),measurestest(_),measurettest(_),id_targetstest(_),measured(_), battery_charge(_), no_battery_function, battery_low, memory_low, memory_high] ). 

% Ugly hacks until I can think of some better way to handle built-ins in the simplistic belief-specific meta-interpreter.

eventplan(Event, Condition, Plan) :- rule(Event, Condition, PlanName), plan(PlanName, _Condition2, Plan), !. 
eventplan(Event, Condition, Plan) :- rule(Event, Condition, Plan). % Hacky, but the idea is to look up a plan name, if there is one, but otherwise just use the plan given.

drop(_) :- fail.
abort(_) :- fail.
suspend(_) :- fail.
activate(_) :- fail.
reactivate(_) :- fail.
reconsider(_) :- fail.
respond(_) :- fail.
rerespond(_) :- fail.
active(_) :- fail.
inactive(_) :- fail.
suspended(_) :- fail.
thermal(_) :- fail.
spectral(_) :- fail.
arm_positioned(_) :- fail. 
measured(_) :- fail. 
spectral_profile(_) :- fail.
thermal_profile(_) :- fail.
at(_) :- fail.
surveyed(_) :- fail.
targetlist(_) :- fail.
time_count(_) :- fail.
drill_count(_) :- fail.
memory_count(_) :- fail.
resources(_,_) :- fail.
completed(_) :- fail.
no_battery_function :- fail.

explore :- initial_state(State),  format("Exploring commences ... ~n",[]), reduce(0, State, full, none).
explore1 :- initial_state(State), format("Exploring commences ... ~n",[]), reduce(0, State, full, []).
explore2 :- initial_state(State), format("Exploring commences ... ~n",[]), reduce(0, State, full, [[],[],[],[],[],[],[],[],[],[],[],[],[],[]]).
explore3 :- initial_state(State), format("Exploring commences ... ~n",[]), reduce(0, State, full, [[thermal(rock1)],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[spectral(target)],[],[],[],[],[],[],[],[],[],[],[],[]]).
explore4 :- initial_state(State), format("Exploring commences ... ~n",[]), reduce(0, State, full, [[],[thermal(rock1)],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[spectral(target)],[],[],[],[],[],[],[],[],[],[],[],[]]).
explore5 :- initial_state(State), format("Exploring commences ... ~n",[]), reduce(0, State, full, [[start5, thermal(rock1), spectral(target1), spectral(target2),spectral(target3), spectral(target4)],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[halt]]).
explore6 :- initial_state(State), format("Exploring commences ... ~n",[]), reduce(0, State, full, [[start6, thermal(rock1), spectral(target1), spectral(target2),spectral(target3), spectral(target4)],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[halt]]).
explore7 :- initial_state(State), format("Exploring commences ... ~n",[]), reduce(0, State, full, [[start7, thermal(rock1), spectral(target1), spectral(target2),spectral(target3), spectral(target4)],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[halt]]).
test1 :- tell('test1.txt'), explore, told. 
test3 :- tell('test3.txt'), explore3, told. 
test4 :- tell('test4.txt'), explore4, told. 
test5 :- tell('test5.txt'), explore5, told. 
test6 :- tell('test6.txt'), explore6, told. 
test7 :- tell('test7.txt'), explore7, told. 

% Relevant steps are 3, 5, 9, 11, 14, 16, 19, 21, 23, 27, 29, 31, 36, 38.
% Map tp steps       1, 2, 3, 4,   5,  6,  7,  8,  9, 10, 11, 12, 13, 14


