% :- include(can). % CAN rules
% :- include(goals). % Goal state rules

?- op(500, xfx, '||'). % For parallel 
?- op(500, xfx, '|>'). % For triangle 
?- op(500, xfx, '}}' ). % For sequence
?- op(500, xfx, '::' ). % For wait

reduce(N, State) :- reduce(N, State, []). 

reduce(_, state(B, []), _Events) :-
	format("No more goals to execute for the agent in this state~n", []),
	output_state(state(B,[])), nl.

reduce(N, state(B,G), Events) :- 
	G \= [],
	output_state(state(B,G)), 
	revise(N, state(B,G), Events, NewEvents, RevisedState, Status),
	N1 is N+1, 
	proceed_or_halt(N1, RevisedState, NewEvents, Status).

proceed_or_halt(_, State, _Events, halt) :-
        format("Halt event detected~n", []), 
	output_state(State), nl.
proceed_or_halt(N, State, Events, Status):-
	Status \= halt, 
	% format("Checking goals for state changes ... ~n", []), 
	% output_state(State), 
        % Change goal states if appropriate
	reduce_goals(State, TempState1),
        % format("State is ", []), display(TempState1), nl, 
	% TempState1 = state(_, Goals1), format("Goals: ", []), output_goals(Goals1), 
	% format("Managing active goals~n", []), 
        % format("State is ", []), display(TempState1), nl, 
        % Find plans for active goals 
        plan_goals(TempState1, TempState2), 
        % format("State is ", []), display(TempState2), nl, 
	% TempState2 = state(_, Goals2), format("Goals: ", []), output_goals(Goals2), 
	% format("Executing~n", []), 
	% output_state(TempState2), 
        % Execute plans for active goals 
	execute_state(TempState2, NewState, _Result), nl, 
	status_update(NewState), % Outputs completness report, and possibly more
        reduce(N, NewState, Events). 

reduce_goals(state(B,G), NewState) :-
	reduce_goal(B, [], G, state(NewB,NewG), Status), 
	reduce_or_halt(NewB, NewG, Status, NewState).

reduce_or_halt(B, G, nochange, state(B,G)) :-
	% format("No more goal changes~n", []). 
	true. 
reduce_or_halt(B, G, update, NewState) :-
	reduce_goals(state(B,G), NewState). 

reduce_goal(B, SoFar, Remainder, state(NewB,Result), update) :- 
        % format("Reduce goal state 1~n", []), ttyflush, 
	Remainder = [GoalContext|Rest],
        % format("Reduce goal state 1~n", []),  ttyflush, 
	GoalContext = g(Name, Goal, Rules, Status, _Plan),
        % format("Calling goal_action ...~n", []),  ttyflush, 
	goal_type(Goal, GoalType), 
	goal_action(Name, GoalType, Status, B, NewB, Rules, Action),
	member(Action, [drop,abort]), % rule 7
	format("Goal ~k ~k: ~k -> ~k~n", [Name, Action, Status, dropped]), 
	append(SoFar, Rest, Result).

reduce_goal(B, SoFar, Remainder, state(NewB, Result), update) :- 
        % format("Reduce goal state 2~n", []), ttyflush,  
	Remainder = [GoalContext|Rest],
	GoalContext = g(Name, Goal, Rules, pending, Plan),
        goal_type(Goal, GoalType), member(GoalType, [perform, achieve]), 
        % format("Reduce goal state 2~n", []), ttyflush,  
	goal_action(Name, GoalType, pending, B, NewB, Rules, Action),
	% format("Action is activate~n", []), ttyflush, 
	member(Action, [activate]),
	format("Goal ~k ~k: ~k -> ~k~n", [Name, Action, pending, active]), ttyflush, 
	NewGoalContext = g(Name, Goal, Rules, active, Plan),  % rule 1
	append(SoFar, [NewGoalContext|Rest], Result). 

reduce_goal(B, SoFar, Remainder, state(NewB, Result), update) :- 
        % format("Reduce goal state 3~n", []),  ttyflush, 
	Remainder = [GoalContext|Rest],
        % format("Reduce goal state 3~n", []),  ttyflush, 
	% format("Goal is ", []), output_single_goal(GoalContext), nl, 
        % format("Checking goal context~n", []),  ttyflush, 
	GoalContext = g(Name, Goal, Rules, pending, Plan),
        % 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]), 
	NewGoalContext = g(Name, Goal, Rules, monitoring, Plan), % rule ?
	append(SoFar, [NewGoalContext|Rest], Result). 

reduce_goal(B, SoFar, Remainder, state(NewB, Result), update) :- 
	Remainder = [GoalContext|Rest],
        % format("Reduce goal state 4~n", []), 
	GoalContext = g(Name, Goal, Rules, monitoring, _Plan),
        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(MC, _Predict, 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 ", []), display(Chosen),nl, 
	NewGoalContext = g(Name, Goal, Rules, active, subgoal(Chosen)),
	append(SoFar, [NewGoalContext|Rest], Result).

reduce_goal(B, SoFar, Remainder, state(NewB, Result), update) :- 
	Remainder = [GoalContext|Rest],
	% format("Reduce goal state 5~n", []), 
	GoalContext = g(Name, Goal, Rules, active, _Plan),
        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]), 
	NewGoalContext = g(Name, Goal, Rules, monitoring, empty),
	append(SoFar, [NewGoalContext|Rest], Result). 

reduce_goal(B, SoFar, Remainder, state(NewB, Result), update) :- 
        Remainder = [GoalContext|Rest],
	% format("Reduce goal state 6~n", []), 
	GoalContext = g(Name, Goal, Rules, suspended, Plan),
        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]), 
	NewGoalContext = g(Name, Goal, Rules, monitoring, Plan), % rule ?
	append(SoFar, [NewGoalContext|Rest], Result). 

reduce_goal(B, SoFar, Remainder, state(NewB, Result), update) :- 
        Remainder = [GoalContext|Rest],
        % format("Reduce goal state 7~n", []), 
	GoalContext = g(Name, Goal, Rules, suspended, Plan),
        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]), 
	NewGoalContext = g(Name, Goal, Rules, active, Plan), % rule ?
	append(SoFar, [NewGoalContext|Rest], Result). 

reduce_goal(B, SoFar, Remainder, state(NewB, Result), update) :- 
	Remainder = [GoalContext|Rest],
        % format("Reduce goal state 8~n", []), 
	GoalContext = g(Name, Goal, Rules, suspended, Plan),
        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]), 
	NewGoalContext = g(Name, Goal, Rules, pending, Plan), % rule ?
	append(SoFar, [NewGoalContext|Rest], Result). 

reduce_goal(B, SoFar, Remainder, state(NewB, Result), update) :- 
	Remainder = [GoalContext|Rest],
        % format("Reduce goal state 9~n", []), 
	GoalContext = g(Name, Goal, Rules, Status, Plan), 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), 
	NewGoalContext = g(Name, Goal, Rules, suspended, Plan), % rule ?
	append(SoFar, [NewGoalContext|Rest], Result). 

reduce_goal(B, SoFar, Remainder, NewState, Status) :- 
	Remainder = [GoalContext|Rest],
        % format("Reduce goal state 10~n", []), 
	GoalContext = g(Name, Goal, Rules, State, _Plan),
	goal_type(Goal, GoalType), 
	% format("Goal is ", []), output_single_goal(GoalContext), nl, 
	goal_action(Name, GoalType, State, B, NewB, Rules, Action), 
	member(Action, [no_action]),
        % format("~k stable, ", [Name]), 
	append(SoFar, [GoalContext], NewSoFar), 
	% format("~nCalling reduce_goal with ~nSoFar:", []), display(NewSoFar), nl, format("Rest: ", []), display(Rest), nl, 
	reduce_goal(NewB, NewSoFar, Rest, NewState, Status).

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, Goal), 
	implies(B, Goal),
	applicable_action(GoalType, Status, Action),
        % format("Applying action ~k to ~k because of ", [Action,Name]), display(Goal), nl, 
        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 \= [_|_]. % Already a list 

% 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]). 

% Find more plans, when needed, or drop goals for which no (more) plans can be found
plan_goals(state(B,G), state(NewB, NewG)) :-
        plan_goals1(B, [], G, NewB, NewG).

plan_goals1(B, SoFar, [], B, SoFar). 
plan_goals1(B, SoFar, Rest, NewB, NewG) :-
        Rest = [GoalContext|Others],
        GoalContext = g(_Name, _Goal, _Rules, Status, _Plan), Status \= active, % Do nothing to goals not in the active state. 
        append(SoFar, [GoalContext], NewSoFar),
        plan_goals1(B, NewSoFar, Others, NewB, NewG).

plan_goals1(B, SoFar, Rest, NewB, NewG) :-
        Rest = [GoalContext|Others],
        GoalContext = g(_Name, _Goal, _Rules, active, Plan), Plan \= empty, % Do nothing to goals which already have a plan 
        append(SoFar, [GoalContext], NewSoFar),
        plan_goals1(B, NewSoFar, Others, NewB, NewG).

%% Need to rethink this case. Why is it here exactly?
plan_goals1(B, SoFar, Rest, NewB, NewG) :-
        Rest = [GoalContext|Others],
        GoalContext = g(_Name, Goal, _Rules, active, empty), 
	goal_type(Goal, GoalType), member(GoalType, [maintain]), % Do nothing to active maintenance goals
        append(SoFar, [GoalContext], NewSoFar),
        plan_goals1(B, NewSoFar, Others, NewB, NewG).

plan_goals1(B, SoFar, Rest, NewB, NewG) :-
        Rest = [GoalContext|Others],
        GoalContext = g(Name, Goal, Rules, active, empty), % Perform or achieve goal active without a plan, so if the status is not about to change, find a new plan. 
	goal_type(Goal, GoalType), member(GoalType, [perform,achieve]),
        remains_active(GoalType, active, B, Rules),
	% format("Finding plan for ~k~n", [Name]), 
        find_plan(Name, Goal, B, Plan), % May need more input than this
        Plan \= empty,
	% format("Plan found~n", []), 
        NewGoalContext = g(Name, Goal, Rules, active, Plan), 
        append(SoFar, [NewGoalContext], NewSoFar),
        plan_goals1(B, NewSoFar, Others, NewB, NewG).
      
plan_goals1(B, SoFar, Rest, NewB, NewG) :-
        Rest = [GoalContext|Others],
        GoalContext = g(Name, Goal, Rules, active, empty), % Active without a plan, so if the status is not about to change, find a new plan. 
	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!
        plan_goals1(B, SoFar, Others, NewB, NewG).
      
remains_active(GoalType, Status, B, Rules) :-
        findall(Action, goal_action(_, GoalType, Status, B,_, Rules,Action), List),
        subset(List, [no_action, activate]).

output_state(state(B,G)) :-
	format("Beliefs: ", []), output_beliefs(B),
	format("Goals: ", []), output_goals(G).

output_goals([]) :- nl. 
output_goals([Goal|Goals]) :-
	output_single_goal(Goal),
	output_goals(Goals).

output_single_goal(Goal) :-
	Goal = g(Name, _GC, _Rules, Status, Plan),
	format("~k: ~k ", [Name, Status]),
        output_plan(Plan),
        format(" || ", []). 

output_beliefs([]) :- nl. 
output_beliefs([Goal|Goals]) :-
	output_single_belief(Goal),
	output_beliefs(Goals).

output_single_belief(Belief) :-
	% format("~k ", [Belief]).
	write(Belief), format(" ",[]).

output_plan(Plan) :-
	Plan = subgoal(Name),
	write(g(Name)).
output_plan(Plan) :-
	Plan \= subgoal(_), 
	write(Plan). 

subset([], _).
subset([Element|Rest], List) :-
       member(Element, List),
       subset(Rest, List).

execute_state(state(B,[]), state(B,[]), finished).
execute_state(state(B,G), NewState, Status) :-
       G \= [], 
       % update_waits([], state(B,G), NewState1), %% This allows 'eager' updating of waits. To be lazy, just omit this step. 
       NewState1 = state(B,G), % omit wait processing for now ... 
       execute1([], NewState1, NewState, Status).

%%% Need to think how to incorporate wait features. 
execute1(SoFar, state(B,[]), state(B, SoFar), finished). 
execute1(SoFar, state(B,Goals), NewState, Search_Status) :-
       % format("Execute 1~n", []), ttyflush, 
       Goals = [GoalContext|Others], 
       % Rest = [GoalContext|Others], 
       GoalContext = g(Name, _Goal, _Rules, 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(NewSoFar, state(B,Others), NewState, Search_Status).
execute1(SoFar, state(B,Goals), state(NewB, NewGoals), continue) :-
       % format("Execute 2~n", []), ttyflush, 
       Goals = [GoalContext|_Others], 
       GoalContext = g(Name, _Goal, _Rules, 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(B, NewB, Goals, NGoals), 
       append(SoFar, NGoals, NewGoals). 

update_waits(SoFar, state(B,[]), state(B, SoFar)). 
update_waits(SoFar, state(B,G), NewState) :-
       G = [GoalContext|Others], 
       GoalContext = g(Name, _Goal, _Rules, Status, _Plan), Status \= active, % Not active, so do not execute it. 
       format("~k: not active ", [Name]), 
       append(SoFar, [GoalContext], NewSoFar),
       update_waits(NewSoFar, state(B,Others), NewState).
update_waits(SoFar, state(B,G), state(B, NewGoals)) :-
       G = [GoalContext|Others], 
       GoalContext = g(Name, _Goal, _Rules, active, Plan), update_plan(B, Plan, Plan, no_change), % Plan is not wait, or it is but condition is not true. Leave it alone. 
       format("~k: no change ", [Name]), 
       append(SoFar, [GoalContext], NewSoFar), 
       update_waits(NewSoFar, stat(B,Others), NewGoals).
update_waits(SoFar, state(B,G), state(B, NewGoals)) :-
       G = [GoalContext|Others], 
       GoalContext = g(Name, Goal, Rules, active, Plan), update_plan(B, Plan, NewPlan, change), % Plan is wait, and condition is true, so update it. 
       format("~k: changing ", [Name]), 
       NewGoalContext = g(Name, Goal, Rules, active, NewPlan), 
       append(SoFar, [NewGoalContext], NewSoFar), 
       update_waits(NewSoFar, stat(B,Others), NewGoals).

%% Might have to traverse entire plan to find 'wait frontier' due to }}, || and |> ... 	
update_plan(_B, Plan, Plan, no_change) :- Plan \= _Guard :: _Body. 
update_plan(B, Plan, Plan, no_change) :- 
	Plan == Guard :: _Body,
	\+ implies(B, Guard).
update_plan(B, Plan, NewPlan, change) :- 
	Plan == Guard :: Body, 
	implies(B, Guard),
	NewPlan = Body. 

inactive_maintenance(B, Goals) :-
      \+ ( member(GoalContext, Goals), 
           GoalContext = g(_Name, Goal, Rules, Status, _Plan),
           goal_type(Goal, GoalType), member(GoalType, [maintain]), 
           goal_action(_, GoalType, Status, B, _NewB, Rules, activate)
         ). 

goal_type(Goal, GoalType) :- Goal =.. [GoalType|_Args].


% Trivial plan
execute_step(B, B, Goals, NewGoals) :-
	Goals = [GoalContext|Others], 
        GoalContext = g(Name, Goal, Rules, active, Plan), 
        (Plan = [nil]; Plan = []),!, 
        NewGoalContext = g(Name, Goal, Rules, active, []),
	NewGoals = [NewGoalContext|Others]. 

% Ask and succeed
execute_step(B, B, Goals, NewGoals) :-
	Goals = [GoalContext|Others], 
        GoalContext = g(Name, Goal, Rules, active, Plan), 
        Plan = [ask(Phi)|NewPlan], 
	% format("Ask plan 1~n", []), 
        implies(B, [Phi]), !, 
	% format("Succeeded~n", []), 
        NewGoalContext = g(Name, Goal, Rules, active, NewPlan),
	NewGoals = [NewGoalContext|Others]. 

% Ask but fail
execute_step(B, B, Goals, NewGoals) :-
	Goals = [GoalContext|Others], 
        GoalContext = g(Name, Goal, Rules, active, Plan), 
        Plan = [ask(Phi)|_NewPlan],
	% format("Ask plan 2~n", []),  
        \+ implies(B, [Phi]), !, 
	% format("Failed~n", []), 
        NewGoalContext = g(Name, Goal, Rules, active, empty),
	NewGoals = [NewGoalContext|Others]. 

% Add belief
execute_step(B, NewB, Goals, NewGoals) :-
	Goals = [GoalContext|Others], 
        GoalContext = g(Name, Goal, Rules, active, Plan), 
        Plan = [add(A)|NewPlan], !, 
        append([A], B, NewB), 
        NewGoalContext = g(Name, Goal, Rules, active, NewPlan),
	NewGoals = [NewGoalContext|Others]. 

% Delete belief, but unnecessary
execute_step(B, B, Goals, NewGoals) :-
	Goals = [GoalContext|Others], 
        GoalContext = g(Name, Goal, Rules, active, Plan), 
        Plan = [del(A)|NewPlan], 
        \+ implies(B, [A]), !, 
        NewGoalContext = g(Name, Goal, Rules, active, NewPlan),
	NewGoals = [NewGoalContext|Others].  

% Real delete belief
execute_step(B, NewB, Goals, NewGoals) :-
	Goals = [GoalContext|Others], 
        GoalContext = g(Name, Goal, Rules, active, Plan), 
        Plan = [del(A)|NewPlan], 
        implies(B, [A]), !, 
        delete(B, A, NewB), 
        NewGoalContext = g(Name, Goal, Rules, active, NewPlan),
	NewGoals = [NewGoalContext|Others]. 

% Perform action and succeeds
execute_step(B, NewB, Goals, NewGoals) :-
	Goals = [GoalContext|Others], 
        GoalContext = g(Name, Goal, Rules, active, Plan), 
	Plan = [A|NewPlan], 
	% format("Trying action ~k~n", [A]), 
	action(B, A, PreCond, Test, Calculate, List),
	% format("Doing action ~k~n", [A]), 
	implies(B, PreCond), !, 
	% format("Precondition done~n", []), 
	implies(B, Test),
	% Calculate, 
	call_goals(Calculate), 
	% format("Test and calculation done~n", []), 
	% format("List is ", []), write(List), nl, 
	update_beliefs(B, List, NewB),
	% format("Updated beliefs: ", []), output_beliefs(NewB), 
	% format("Beliefs updated~n", []), 
        NewGoalContext = g(Name, Goal, Rules, active, NewPlan),
	NewGoals = [NewGoalContext|Others]. 

% Perform action and fails
execute_step(B, B, Goals, NewGoals) :-
	Goals = [GoalContext|Others], 
        GoalContext = g(Name, Goal, Rules, active, Plan), 
	Plan = [A|_NewPlan], 
	% format("Trying action ~k~n", [A]), 
	action(B, A, PreCond, _Test, _Calculate, _List),
	% format("Doing action ~k~n", [A]), 
	\+ implies(B, PreCond), !, 
	% format("Precondition failed~n", []), 
        NewGoalContext = g(Name, Goal, Rules, active, empty),
	NewGoals = [NewGoalContext|Others]. 

% Wait with condition succeeding (so like action)
execute_step(B, B, Goals, NewGoals) :-
	Goals = [GoalContext|Others], 
        GoalContext = g(Name, Goal, Rules, active, Plan), 
	% format("Trying wait ~n", []), 
	Plan = [(Guard :: Body)|RestPlan], 
	% format("Found ~n", []), 
	implies(B, [Guard]),
	% format("Stop waiting ~n", []), 
	append(Body, RestPlan, NewPlan), 
	NewGoalContext = g(Name, Goal, Rules, active, NewPlan),
	NewGoals = [NewGoalContext|Others]. 

% Wait with condition failing
execute_step(B, B, Goals, NewGoals) :-
	Goals = [GoalContext|Others], 
        GoalContext = g(_Name, _Goal, _Rules, active, Plan), 
	% format("Trying wait ~n", []), 
	Plan = [(Guard :: _Body)|_], 
	% format("Found again ~n", []), 
	\+ implies(B, [Guard]),
	% format("Still waiting ~n", []), 
	append(Others, [GoalContext], NewGoals).  %% add to the end to ensure fairness ... 

% Sequence
execute_step(B, NewB, Goals, NewGoals) :-
	Goals = [GoalContext|Others], 
        GoalContext = g(Name, Goal, Rules, active, Plan), 
	Plan = [P1|NewP], 
	% format("Sequence~n", []), 
	\+ action(B, P1, _PreCond, _Test, _Calculate, _List),

	NGoalContext = g(Name, Goal, Rules, active, P1), 
	NewishGoals = [NGoalContext|Others], 

        execute_step(B, NewB, NewishGoals, NGoals), 
	member(g(Name, Goal, Rules, active, NewPlan1), NGoals), 
	delete(NGoals, g(Name, Goal, Rules, active, NewPlan1), NGoals1), 
        append(NewPlan1, NewP, NewPlan),

        NewGoalContext = g(Name, Goal, Rules, active, NewPlan),
	NewGoals = [NewGoalContext|NGoals1]. 

% Subgoal
execute_step(B, B, Goals, NewGoals) :-
	Goals = [GoalContext|Others], 
        GoalContext = g(Name, Goal, Rules, active, Plan), 
	Plan = subgoal(SubName), !, 
	% format("Trying subgoal ... ~n", []), ttyflush, 
	goal(g(SubName, SubGoal, SubRules)), 
	% format("Executing subgoal 1~n", []), ttyflush, 
        success_and_failure_conditions(SubGoal, Success, _Failure), 

	% format("Executing subgoal 2~n", []), ttyflush, 

	% % Hack to make examples work easily!!
	% SubGoalGuard = (Success; Failure; drop(SubName); abort(SubName)), 
	set_subgoalguard(SubName, SubGoalGuard), % SubGoalGuard = goaltest; 

	% format("Executing subgoal 3~n", []), ttyflush, 
	SubGoalPlan = [SubGoalGuard :: [ask(Success)] ], 
	% format("Executing subgoal 4~n", []), ttyflush, 

	NewGoalContext = g(Name, Goal, Rules, active, SubGoalPlan), 
	% format("Executing subgoal 5~n", []), ttyflush, 
	SubGoalContext = g(SubName, SubGoal, SubRules, pending, empty), 
	% format("New Goal Plan is ", []), write(SubGoalPlan), nl, ttyflush, 
	% format("SubGoalContext is ", []), write(SubGoalContext), nl, ttyflush, 
	append([NewGoalContext, SubGoalContext], Others, NewGoals). 

execute_step(B, B, Goals, Goals) :-
	Goals = [GoalContext|_Others], 
        GoalContext = g(_Name, _Goal, _Rules, active, Plan), 
	format("Unrecognised Plan:  ", []), write(Plan), nl, 
	true. 

call_goals([]).
call_goals([G|Rest]) :- call(G), call_goals(Rest).

success_and_failure_conditions(SubGoal, Success, Failure) :-
	SubGoal = achieve(_, Success, Failure).
success_and_failure_conditions(SubGoal, Success, Failure) :-
	SubGoal = maintain(_, _, _, _, Success, Failure).

% 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).

% rule(fred, b, c).
% rule(dip, d, e).
% rule(dip, f, g).
rule(_,_,_) :- fail.
	
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) :-
	append([B1], B, NB), 
	update_beliefs(NB, Rest, NewB). 

delete_belief(B, B1, NB) :-
% 	implies(B, [B1]),
	delete(B, B1, NB).

delete_belief(B, B1, B) :-
	\+ implies(B, [B1]).

add_beliefs(B, Add, NewB) :-
	append(B, Add, NewB). 


revise(N, state(B,G), Events, NewEvents, 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, 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, state(NewB, NewG), Status) :-
        Events = [Next|NewEvents], !, 
        format("-----------------------------------------------------~n", []), 
        format("~d: Next events are ", [N]), write(Next), 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, 
        process_event(Event, state(B,G), state(NB,NG)),
        process_events(Rest, state(NB,NG), state(NewB, NewG), Status).

process_event(Event, state(B,G), state(NewB,NewG)) :-
        event(Event, Belief_Updates, Goal_Additions),
        update_beliefs(B, Belief_Updates, NewB),
        append(Goal_Additions, G, NewG).

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). 

% Converts list of concurrent plan steps into a single plan
planify([], nil).
planify([P], P) :- length([P], 1).
planify([P1|Rest], Plan) :- length([P1|Rest], N), N > 1, planify(Rest,P2), Plan = P1 '||' P2.

% Given update on status. This is the mechanism for measuring goal completess. 
status_update(State) :- completeness_status(State).

completeness_status(state(B, Goals)) :-
    format("Completeness report: ~n", []), 
    completeness_status1(B, Goals). 

completeness_status1(_B, []). 
completeness_status1(B,Goals) :-
 	Goals = [GoalContext|Rest],
 	GoalContext = g(_Name, _Goal, _Rules, Status, _Plan),
	\+ member(Status, [active,suspended]), % Only report completeness for these
	completeness_status1(B, Rest),
	true. 
completeness_status1(B,Goals) :-
 	Goals = [GoalContext|Rest],
 	GoalContext = g(_Name, _Goal, _Rules, Status, _Plan),
	member(Status, [active,suspended]), % Only report completeness for these
	completeness(B, GoalContext, Report),
	output_report(GoalContext, Report),
	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, _Goal, _Rules, _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. 

output_number(Value) :-
    numeric(Value), format("~1f%", [100*Value]).
output_number(Value) :-
    \+ numeric(Value), format("--", []).

numeric(Value) :- number(Value). 

resource_status(B, GoalContext, CR, DR, PR) :-
    	GoalContext = g(Name, _Goal, _Rules, _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, _Goal, _Rules, _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, _Goal, _Rules, _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: 

goal(g(explore(red1),achieve(true, measured(target), false), Rules)) :-  rules(explore(red1), [measured(target)], Rules).
goal(g(exp(Name),achieve(true, measured(Name), false), Rules)) :- rules(exp(Name), [measured(Name)], Rules).
goal(g(position(Name),achieve(true, arm_positioned(Name), false), Rules)) :- rules(position(Name), [arm_positioned(Name)], Rules).
goal(g(measures(Name),achieve(true, spectral_profile(Name), false), Rules)) :- rules(measures(Name), [spectral_profile(Name)], Rules).
goal(g(measuret(Name),achieve(true, thermal_profile(Name), false), Rules)) :- rules(measuret(Name), [thermal_profile(Name)], Rules).
goal(g(traverse(Initial,Final),achieve(true, at(Final), false), Rules)) :-  rules(traverse(Initial,Final), [at(Final)], Rules). 
goal(g(survey(Name),achieve(true, measured(target), false), Rules)) :-  rules(survey(Name), [measured(target)], Rules). 
goal(g(id_targets(Place),achieve(true, targetlist(Place), false), Rules)) :-  rules(id_targets(Place), [targetlist(Place)], Rules). 

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(Goals) :- 
	goal(g(explore(red1), ExpGoal, ExpRules)), Goals = [g(explore(red1), ExpGoal, ExpRules, pending, empty)].

initial_beliefs([
drill_count(0),
memory_count(0), 
time_count(0),
resources(explore(red1),          [res(drill,0),res(memory,0),res(time,0)]),  
resources(exp(rock1),             [res(drill,0),res(memory,0),res(time,0)]),  
resources(exp(target),            [res(drill,0),res(memory,0),res(time,0)]),  
resources(survey(canyon),         [res(drill,0),res(memory,0),res(time,0)]),  
resources(id_targets(canyon),     [res(drill,0),res(memory,0),res(time,0)]),  
resources(traverse(rock1,canyon), [res(drill,0),res(memory,0),res(time,0)]),  
resources(position(rock1),        [res(drill,0),res(memory,0),res(time,0)]),  
resources(position(target),       [res(drill,0),res(memory,0),res(time,0)]),  
resources(measures(rock1),        [res(drill,0),res(memory,0),res(time,0)]),  
resources(measures(target),       [res(drill,0),res(memory,0),res(time,0)]),  
resources(measuret(rock1),        [res(drill,0),res(memory,0),res(time,0)]),  
resources(measuret(target),       [res(drill,0),res(memory,0),res(time,0)]),  
at(red1),
% thermal(rock1),
% spectral(target),
activate(explore(red1)),
activate(exp(rock1)),
activate(position(rock1)),
activate(measuret(rock1)),
activate(traverse(rock1,canyon)), 
activate(survey(canyon)), 
activate(exp(target)), 
activate(measures(target)),
activate(id_targets(canyon)),
activate(position(target))
]).

% find_plan(Name, Goal, B, Plan).
find_plan(Name, Goal, B, Plan) :- find_plan1(Name, Goal, B, Plan).
find_plan(Name, Goal, B, empty) :- \+ find_plan1(Name, Goal, B, _Plan).
find_plan1(explore(red1), _, _, [subgoal(exp(rock1)), subgoal(traverse(rock1,canyon)), subgoal(survey(canyon))]).
find_plan1(exp(Name), _, B, [subgoal(position(Name)), subgoal(measures(Name))]) :- implies(B, [spectral(Name)]). 
find_plan1(exp(Name), _, B, [subgoal(position(Name)), subgoal(measuret(Name))]) :- implies(B, [thermal(Name)]). 
find_plan1(position(Name), _, _, [positionarm(Name)]).
find_plan1(measures(Name), _, _, [measurements(Name)]).
find_plan1(measuret(Name), _, _, [measurementt(Name)]).
find_plan1(traverse(Initial,Final), _, _, [traverseaction(Initial,Final)]).
find_plan1(survey(Name), _, _, [subgoal(id_targets(Name)), subgoal(exp(target))]).
find_plan1(id_targets(Name), _, _, [panoramic_process(Name)]).

set_subgoalguard(exp(Name), exptest(Name)). 
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(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)?
action(B, positionarm(Name), [],         [time_count(X)],                   [X1 is X + 120],               Updates) :-  % Make time random choice between 60 (min) and 180 (max)?
    % format("Updating positionarm(~k) resources~n", [Name]), 	ttyflush, 													
    % format("Beliefs: ", []), output_beliefs(B),
    resource_updates(B, positionarm(Name), Updates1),
    % format("Done updating positionarm() resources~n", []), ttyflush, 													
    append([del(time_count(X)), add(time_count(X1)), add(arm_positioned(Name))], Updates1, Updates). 
% action(B, measurements(Name), [],        [drill_count(X), memory_count(Y)], [X1 is X + 1, Y1 is Y + 20],   [del(drill_count(X)),  del(memory_count(Y)), add(drill_count(X1)),  add(memory_count(Y1)), add(spectral_profile(Name))]).
action(B, measurements(Name), [],        [drill_count(X), memory_count(Y)], [X1 is X + 1, Y1 is Y + 20],   Updates) :-
    resource_updates(B, measurements(Name), Updates1),
    append([del(drill_count(X)),  del(memory_count(Y)), add(drill_count(X1)),  add(memory_count(Y1)), add(spectral_profile(Name))], Updates1, Updates). 

% action(B, measurementt(Name), [],        [memory_count(X), time_count(Y)], [X1 is X + 50, Y1 is Y + 25],   [del(memory_count(X)), del(time_count(Y)),   add(memory_count(X1)), add(time_count(Y1)),   add(thermal_profile(Name))]).
action(B, measurementt(Name), [],        [memory_count(X), time_count(Y)], [X1 is X + 50, Y1 is Y + 25],   Updates) :-
    resource_updates(B, measurementt(Name), Updates1),
    append([del(memory_count(X)), del(time_count(Y)),   add(memory_count(X1)), add(time_count(Y1)),   add(thermal_profile(Name))], Updates1, Updates). 

% action(B, traverse(_Initial, Final), [], [time_count(X)],                  [X1 is X + 200],                [del(time_count(X)),   add(time_count(X1)), add(at(Final))]).
action(B, traverseaction(Initial, Final), [], [time_count(X)],                  [X1 is X + 200],                 Updates) :-
     % format("Updating traverse(~k,~k resources~n", [Initial,Final]), 	ttyflush, 													
      resource_updates(B, traverseaction(Initial,Final), Updates1),
     % format("Done updating traverse(~k,~k resources~n", [Initial,Final]), 	ttyflush, 													
     append([del(time_count(X)),   add(time_count(X1)), add(at(Final))], Updates1, Updates). 

% action(B, panoramic_process(Name), [],   [memory_count(X), time_count(Y)], [X1 is X + 100, Y1 is Y + 300], [del(memory_count(X)), del(time_count(Y)), add(memory_count(X1)), add(time_count(Y1)), add(targetlist(Name))]).
action(B, panoramic_process(Name), [],   [memory_count(X), time_count(Y)], [X1 is X + 100, Y1 is Y + 300], Updates) :-
    resource_updates(B, panoramic_process(Name), Updates1),
    append([del(memory_count(X)), del(time_count(Y)), add(memory_count(X1)), add(time_count(Y1)), add(targetlist(Name))], Updates1, Updates). 

resource_updates(B, positionarm(rock1), Updates) :-
    % format("Updating explore(red1) resources~n", []), 
    implies(B, [resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1)])]), 
    NewTime1 is Time1 + 120, 
    Updates1 = [del(resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1)])), add(resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,NewTime1)]))], 
    % format("Updating exp(rock1) resources~n", []), 
    implies(B, [resources(exp(rock1), [res(drill,Drill2),res(memory,Memory2),res(time,Time2)])]), 
    NewTime2 is Time2 + 120, 
    Updates2 = [del(resources(exp(rock1), [res(drill,Drill2),res(memory,Memory2),res(time,Time2)])), add(resources(exp(rock1), [res(drill,Drill2),res(memory,Memory2),res(time,NewTime2)]))], 
    % format("Updating position(rock1) resources~n", []), 
    implies(B, [resources(position(rock1),  [res(drill,Drill3),res(memory,Memory3),res(time,Time3)])]), 
    NewTime3 is Time3 + 120, 
    Updates3 = [del(resources(position(rock1), [res(drill,Drill3),res(memory,Memory3),res(time,Time3)])), add(resources(position(rock1), [res(drill,Drill3),res(memory,Memory3),res(time,NewTime3)]))], 

    append(Updates1, Updates2, Temp),
    append(Temp, Updates3, Updates). 

resource_updates(B, positionarm(target), Updates) :- 
    implies(B, [resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1)])]), 
    NewTime1 is Time1 + 120, 
    Updates1 = [del(resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1)])), add(resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,NewTime1)]))], 

    implies(B, [resources(survey(canyon), [res(drill,Drill2),res(memory,Memory2),res(time,Time2)])]), 
    NewTime2 is Time2 + 120, 
    Updates2 = [del(resources(survey(canyon), [res(drill,Drill2),res(memory,Memory2),res(time,Time2)])), add(resources(survey(canyon), [res(drill,Drill2),res(memory,Memory2),res(time,NewTime2)]))], 

    implies(B, [resources(exp(target), [res(drill,Drill3),res(memory,Memory3),res(time,Time3)])]), 
    NewTime3 is Time3 + 120, 
    Updates3 = [del(resources(exp(target), [res(drill,Drill3),res(memory,Memory3),res(time,Time3)])), add(resources(exp(target), [res(drill,Drill3),res(memory,Memory3),res(time,NewTime3)]))], 

    implies(B, [resources(position(target),  [res(drill,Drill4),res(memory,Memory4),res(time,Time4)])]), 
    NewTime4 is Time4 + 120, 
    Updates4 = [del(resources(position(target), [res(drill,Drill4),res(memory,Memory4),res(time,Time4)])), add(resources(position(target), [res(drill,Drill4),res(memory,Memory4),res(time,NewTime4)]))], 

    append(Updates1, Updates2, Temp12),
    append(Updates3, Updates4, Temp34),
    append(Temp12, Temp34, Updates). 

resource_updates(B, measurements(rock1), Updates) :- 
    implies(B, [resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1)])]), 
    NewDrill1 is Drill1 + 1, NewMemory1 is Memory1 + 20, NewTime1 is Time1 + 60, 
    Updates1 = [del(resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1)])), add(resources(explore(red1), [res(drill,NewDrill1),res(memory,NewMemory1),res(time,NewTime1)]))], 

    implies(B, [resources(exp(rock1), [res(drill,Drill2),res(memory,Memory2),res(time,Time2)])]), 
    NewDrill2 is Drill2 + 1, NewMemory2 is Memory2 + 20, NewTime2 is Time2 + 60, 
    Updates2 = [del(resources(exp(rock1), [res(drill,Drill2),res(memory,Memory2),res(time,Time2)])), add(resources(exp(rock1), [res(drill,NewDrill2),res(memory,NewMemory2),res(time,NewTime2)]))], 

    implies(B, [resources(measures(rock1),  [res(drill,Drill3),res(memory,Memory3),res(time,Time3)])]), 
    NewDrill3 is Drill3 + 1, NewMemory3 is Memory3 + 20, NewTime3 is Time3 + 60, 
    Updates3 = [del(resources(measures(rock1), [res(drill,Drill3),res(memory,Memory3),res(time,Time3)])), add(resources(measures(rock1), [res(drill,NewDrill3),res(memory,NewMemory3),res(time,NewTime3)]))], 

    append(Updates1, Updates2, Temp),
    append(Temp, Updates3, Updates). 

resource_updates(B, measurementt(rock1), Updates) :- 
    implies(B, [resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1)])]), 
    NewMemory1 is Memory1 + 50, NewTime1 is Time1 + 25, 
    Updates1 = [del(resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1)])), add(resources(explore(red1), [res(drill,Drill1),res(memory,NewMemory1),res(time,NewTime1)]))], 

    implies(B, [resources(exp(rock1), [res(drill,Drill2),res(memory,Memory2),res(time,Time2)])]), 
    NewMemory2 is Memory2 + 50, NewTime2 is Time2 + 25, 
    Updates2 = [del(resources(exp(rock1), [res(drill,Drill2),res(memory,Memory2),res(time,Time2)])), add(resources(exp(rock1), [res(drill,Drill2),res(memory,NewMemory2),res(time,NewTime2)]))], 

    implies(B, [resources(measuret(rock1),  [res(drill,Drill3),res(memory,Memory3),res(time,Time3)])]), 
    NewMemory3 is Memory3 + 50, NewTime3 is Time3 + 25, 
    Updates3 = [del(resources(measuret(rock1), [res(drill,Drill3),res(memory,Memory3),res(time,Time3)])), add(resources(measuret(rock1), [res(drill,Drill3),res(memory,NewMemory3),res(time,NewTime3)]))], 

    append(Updates1, Updates2, Temp),
    append(Temp, Updates3, Updates).

resource_updates(B, measurements(target), Updates)  :- 
    implies(B, [resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1)])]), 
    NewDrill1 is Drill1 + 1, NewMemory1 is Memory1 + 20, NewTime1 is Time1 + 60, 
    Updates1 = [del(resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1)])), add(resources(explore(red1), [res(drill,NewDrill1),res(memory,NewMemory1),res(time,NewTime1)]))], 

    implies(B, [resources(survey(canyon), [res(drill,Drill2),res(memory,Memory2),res(time,Time2)])]), 
    NewDrill2 is Drill2 + 1, NewMemory2 is Memory2 + 20, NewTime2 is Time2 + 60, 
    Updates2 = [del(resources(survey(canyon), [res(drill,Drill2),res(memory,Memory2),res(time,Time2)])), add(resources(survey(canyon), [res(drill,NewDrill2),res(memory,NewMemory2),res(time,NewTime2)]))], 

    implies(B, [resources(exp(target), [res(drill,Drill3),res(memory,Memory3),res(time,Time3)])]), 
    NewDrill3 is Drill3 + 1, NewMemory3 is Memory3 + 20, NewTime3 is Time3 + 60, 
    Updates3 = [del(resources(exp(target), [res(drill,Drill3),res(memory,Memory3),res(time,Time3)])), add(resources(exp(target), [res(drill,NewDrill3),res(memory,NewMemory3),res(time,NewTime3)]))], 

    implies(B, [resources(measures(target),  [res(drill,Drill4),res(memory,Memory4),res(time,Time4)])]), 
    NewDrill4 is Drill4 + 1, NewMemory4 is Memory4 + 20, NewTime4 is Time4 + 60, 
    Updates4 = [del(resources(measures(target), [res(drill,Drill4),res(memory,Memory4),res(time,Time4)])), add(resources(measures(target), [res(drill,NewDrill4),res(memory,NewMemory4),res(time,NewTime4)]))], 

    append(Updates1, Updates2, Temp12),
    append(Updates3, Updates4, Temp34),
    append(Temp12, Temp34, Updates). 

resource_updates(B, measurementt(target), Updates) :- 
    implies(B, [resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1)])]), 
    NewMemory1 is Memory1 + 50, NewTime1 is Time1 + 25, 
    Updates1 = [del(resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1)])), add(resources(explore(red1), [res(drill,Drill1),res(memory,NewMemory1),res(time,NewTime1)]))], 

    implies(B, [resources(survey(canyon), [res(drill,Drill2),res(memory,Memory2),res(time,Time2)])]), 
    NewMemory2 is Memory2 + 50, NewTime2 is Time2 + 25, 
    Updates2 = [del(resources(survey(canyon), [res(drill,Drill2),res(memory,Memory2),res(time,Time2)])), add(resources(survey(canyon), [res(drill,Drill2),res(memory,NewMemory2),res(time,NewTime2)]))], 

    implies(B, [resources(exp(target), [res(drill,Drill3),res(memory,Memory3),res(time,Time3)])]), 
    NewMemory3 is Memory3 + 50, NewTime3 is Time3 + 25, 
    Updates3 = [del(resources(exp(target), [res(drill,Drill3),res(memory,Memory3),res(time,Time3)])), add(resources(exp(target), [res(drill,Drill3),res(memory,NewMemory3),res(time,NewTime3)]))], 

    implies(B, [resources(measuret(target),  [res(drill,Drill4),res(memory,Memory4),res(time,Time4)])]), 
    NewMemory4 is Memory4 + 50, NewTime4 is Time4 + 25, 
    Updates4 = [del(resources(measuret(target), [res(drill,Drill4),res(memory,Memory4),res(time,Time4)])), add(resources(measuret(target), [res(drill,Drill4),res(memory,NewMemory4),res(time,NewTime4)]))], 

    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", []), 
    implies(B, [resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1)])]), 
    NewTime1 is Time1 + 200, 
    Updates1 = [del(resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1)])), add(resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,NewTime1)]))], 
    % format("Updating traverse(rock1,canyon) resources~n", []), 
    implies(B, [resources(traverse(rock1, canyon), [res(drill,Drill2),res(memory,Memory2),res(time,Time2)])]), 
    NewTime2 is Time2 + 200, 
    Updates2 = [del(resources(traverse(rock1,canyon), [res(drill,Drill2),res(memory,Memory2),res(time,Time2)])), add(resources(traverse(rock1,canyon), [res(drill,Drill2),res(memory,Memory2),res(time,NewTime2)]))], 

    append(Updates1, Updates2, Updates).

resource_updates(B, panoramic_process(canyon), Updates) :-
    implies(B, [resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1)])]), 
    NewMemory1 is Memory1 + 100, NewTime1 is Time1 + 300, 
    Updates1 = [del(resources(explore(red1), [res(drill,Drill1),res(memory,Memory1),res(time,Time1)])), add(resources(explore(red1), [res(drill,Drill1),res(memory,NewMemory1),res(time,NewTime1)]))], 

    implies(B, [resources(survey(canyon), [res(drill,Drill2),res(memory,Memory2),res(time,Time2)])]), 
    NewMemory2 is Memory2 + 100, NewTime2 is Time2 + 300, 
    Updates2 = [del(resources(survey(canyon), [res(drill,Drill2),res(memory,Memory2),res(time,Time2)])), add(resources(survey(canyon), [res(drill,Drill2),res(memory,NewMemory2),res(time,NewTime2)]))], 

    implies(B, [resources(id_targets(canyon), [res(drill,Drill3),res(memory,Memory3),res(time,Time3)])]), 
    NewMemory3 is Memory3 + 100, NewTime3 is Time3 + 300, 
    Updates3 = [del(resources(id_targets(canyon), [res(drill,Drill3),res(memory,Memory3),res(time,Time3)])), add(resources(id_targets(canyon), [res(drill,Drill3),res(memory,NewMemory3),res(time,NewTime3)]))], 

    append(Updates1, Updates2, Temp),
    append(Temp, Updates3, 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), [res(drill,0),res(memory,0),res(time,0)], [res(drill,0), res(memory,0),   res(time,100)], [res(drill,0),res(memory,0),   res(time,300)]) :-  
    \+ implies(B, [completed(traverse(rock1,canyon))]).
resource_summary(B, traverse(rock1,canyon), Resources, [res(drill,0), res(memory,0), res(time,0)], [res(drill,0),res(memory,0), res(time,0)]) :-  
    implies(B, [completed(traverse(rock1,canyon))]), used_resources(B, traverse(rock1,canyon), Resources). 
resource_summary(B, id_targets(canyon),     [res(drill,0),res(memory,0),res(time,0)], [res(drill,0), res(memory,100), res(time,300)], [res(drill,0),res(memory,100), res(time,300)]) :- 
    \+ implies(B, [completed(id_targets(canyon))]).
resource_summary(B, id_targets(canyon),     Resources, [res(drill,0),res(memory,0),res(time,0)], [res(drill,0),res(memory,0),res(time,0)]) :- 
    implies(B, [completed(id_targets(canyon))]),  used_resources(B, id_targets(canyon), Resources). 

resource_summary(B, position(Name),        [res(drill,0),res(memory,0),res(time,0)], [res(drill,0), res(memory,0),   res(time,60)],  [res(drill,0),res(memory,0),   res(time,180)]) :-
    \+ implies(B, [completed(position(Name))]).
resource_summary(B, position(Name),        Resources, [res(drill,0), res(memory,0),   res(time,0)],  [res(drill,0),res(memory,0),   res(time,0)]) :-
    implies(B, [completed(position(Name))]),  used_resources(B, position(Name), Resources). 

resource_summary(B, measures(Name),        [res(drill,0),res(memory,0),res(time,0)], [res(drill,1), res(memory,20),  res(time,40)],  [res(drill,1),res(memory,20),  res(time,80)]) :- 
    \+ implies(B, [completed(measures(Name))]).
resource_summary(B, measures(Name),        Resources, [res(drill,0), res(memory,0),  res(time,0)],  [res(drill,0),res(memory,0),  res(time,0)]) :- 
    implies(B, [completed(measures(Name))]), used_resources(B, measures(Name), Resources). 
resource_summary(B, measuret(Name),        [res(drill,0),res(memory,0),res(time,0)], [res(drill,0), res(memory,50),  res(time,20)],  [res(drill,0),res(memory,50),  res(time,30)]) :-
    \+ implies(B, [completed(measuret(Name))]).
resource_summary(B, measuret(Name),        Resources, [res(drill,0), res(memory,0),  res(time,0)],  [res(drill,0),res(memory,0),  res(time,0)]) :-
    implies(B, [completed(measures(Name))]), used_resources(B, measuret(Name), Resources). 

resource_summary(B, explore(red1), Current_Resources,  [res(drill,0),res(memory,0),res(time,0)],  [res(drill,0),res(memory,0),res(time,0)]) :-
    implies(B, [completed(explore(red1))]), used_resources(B, explore(red1), Current_Resources). 
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, [res(drill,0),res(memory,0),res(time,0)],  [res(drill,0),res(memory,0),res(time,0)]) :-
    implies(B, [completed(survey(canyon))]), used_resources(B, survey(canyon), Current_Resources). 
resource_summary(B, survey(canyon), Current_Resources, Min_Resources, Max_Resources) :-
    \+ implies(B, [completed(survey(canyon))]), 
    resource_summary_total(B, [id_targets(canyon), exp(target)], Current_Resources, Min_Resources, Max_Resources). 

resource_summary(B, exp(Name), Current_Resources, [res(drill,0),res(memory,0),res(time,0)],  [res(drill,0),res(memory,0),res(time,0)]) :-
    implies(B, [completed(exp(Name))]), used_resources(B, exp(Name), Current_Resources). 
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_zero([res(drill,0), res(memory,0), res(time,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(drill,Drill2),res(memory,Memory2),res(time,Time2)], [res(drill,Drill3),res(memory,Memory3),res(time,Time3)]) :-
    Drill3 is Drill1 + Drill2, 
    Memory3 is Memory1 + Memory2, 
    Time3 is Time1 + Time2, 
    true. 

combine_resources_min(Min_Resources1, Min_Resources2, Min_Resources3) :-
    Min_Resources1 = [res(drill,Drill1),res(memory,Memory1),res(time,Time1)], 
    Min_Resources2 = [res(drill,Drill2),res(memory,Memory2),res(time,Time2)], 
    Drill3 is min(Drill1, Drill2), 
    Memory3 is min(Memory1, Memory2), 
    Time3 is min(Time1, Time2), 
    Min_Resources3 = [res(drill,Drill3),res(memory,Memory3),res(time,Time3)], 
    true. 

combine_resources_max(Max_Resources1, Max_Resources2, Max_Resources3) :-
    Max_Resources1 = [res(drill,Drill1),res(memory,Memory1),res(time,Time1)], 
    Max_Resources2 = [res(drill,Drill2),res(memory,Memory2),res(time,Time2)], 
    Drill3 is max(Drill1, Drill2), 
    Memory3 is max(Memory1, Memory2), 
    Time3 is max(Time1, Time2), 
    Max_Resources3 = [res(drill,Drill3),res(memory,Memory3),res(time,Time3)], 
    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)]), 
    Resources = [res(drill,Drill),  res(memory,Memory), res(time,Time)].

% 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(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(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(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(traverse(rock1,canyon),  [eff(at(canyon),1)], [eff(at(canyon),1)], []). 
effect_summary(id_targets(canyon),      [eff(targetlist(canyon),1)], [eff(targetlist(canyon),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(_B, []). 
implies(B, [F|Rest]) :-
	implies_single(B, F),
	implies(B, Rest).

implies_single(B, G) :- \+ member(G, [exploretest(_), exptest(_), traversetest(_,_),surveytest(_),positiontest(_),measurestest(_),measurettest(_),id_targetstest(_),measured(_)]), member(G, B). 
implies_single(_B, G) :- \+ member(G, [exploretest(_), exptest(_), traversetest(_,_),surveytest(_),positiontest(_),measurestest(_),measurettest(_),id_targetstest(_),measured(_)]), G. % For built-ins.
implies_single(B, G) :- \+ member(G, [exploretest(_), exptest(_), traversetest(_,_),surveytest(_),positiontest(_),measurestest(_),measurettest(_),id_targetstest(_),measured(_)]), member(rule(Head, Body), B), Head = G, implies(B, Body).
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))]).


% Ugly hacks until I can think of some better way to handle built-ins in the simplistic belief-specific meta-interpreter.

drop(_) :- fail.
abort(_) :- fail.
suspend(_) :- fail.
activate(_) :- fail.
reactivate(_) :- fail.
reconsider(_) :- fail.
respond(_) :- fail.
rerespond(_) :- fail.
active(_) :- 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.

explore :- initial_state(State), format("Exploring commences ... ~n",[]), reduce(0, State, none).
explore1 :- initial_state(State), format("Exploring commences ... ~n",[]), reduce(0, State, []).
explore2 :- initial_state(State), format("Exploring commences ... ~n",[]), reduce(0, State, [[],[],[],[],[],[],[],[],[],[],[],[],[],[]]).
explore3 :- initial_state(State), format("Exploring commences ... ~n",[]), reduce(0, State, [[ev(thermal(rock1))],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[ev(spectral(target))],[],[],[],[],[],[],[],[],[],[],[],[]]).
explore4 :- initial_state(State), format("Exploring commences ... ~n",[]), reduce(0, State, [[],[ev(thermal(rock1))],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[ev(spectral(target))],[],[],[],[],[],[],[],[],[],[],[],[]]).

test1 :- tell('test1.txt'), explore, told. 
test3 :- tell('test3.txt'), explore3, told. 
test4 :- tell('test4.txt'), explore4, 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

% B = [resources(explore(red1),[res(drill,0),res(memory,0),res(time,0)]), resources(exp(rock1),[res(drill,0),res(memory,0),res(time,0)]), resources(position(rock1),[res(drill,0),res(memory,0),res(time,0)]) ]
% resources(exp(target),[res(drill,0),res(memory,0),res(time,0)]) 
% resources(survey(canyon),[res(drill,0),res(memory,0),res(time,0)]) 
% resources(id_targets(canyon),[res(drill,0),res(memory,0),res(time,0)]) 
% resources(position(rock1),[res(drill,0),res(memory,0),res(time,0)]) 
% resources(position(target),[res(drill,0),res(memory,0),res(time,0)]) 
% resources(measures(rock1),[res(drill,0),res(memory,0),res(time,0)]) 
% resources(measures(target),[res(drill,0),res(memory,0),res(time,0)]) 
% resources(measuret(rock1),[res(drill,0),res(memory,0),res(time,0)]) 
% resources(measuret(target),[res(drill,0),res(memory,0),res(time,0)]) 
