% Must be run with prova test023.prova -t -1 for infinite message loop
% Demonstrate how to
% - send messages to self including
%      inform, queryref, queryref_acc, eval, and rexec;
% - write and use reaction rules
%      to intercept incoming messages based on patterns.
% - introduce an indefinite timeout for the Prova processor
% - intercept the message "return"  
%      and the 10 sec timer.
% - use rcvMsg to intercept a message inside a rule body (inline)
% - use rcvMult to intercept multiple messages inside a rule body (inline)

:- eval(test023()).

% Example data
data(3.141592).

parent(cell,intracellular).

% Send out messages
test023() :-
	println(["==========test023=========="]),
	iam(Me),

	% Use a regular timer
	sendMsg(XID1,self,Me,rexec,[java.lang.Thread,sleep,3000],"timer",0),

	% Update the mental state by way of a message 'inform'
	% Note: one extra "parent" record will be added
	sendMsg(XID2,self,Me,inform,parent(cellular_component,cell)),

	% Send a queryref message with replies to be sent back to the agent
	sendMsg(XID3,self,Me,queryref,parent(X,Y),id0),
	rcvMult(XID3,self,Me,reply,parent(X,Y),id0),
	println(["Inline reaction ",rcvMult(self,Me,reply,parent(X,Y),id0)]),

	% Use queryref to submit a query and collect the result inline
	sendMsg(XID4,self,Me,queryref,data(Value),id1),
	rcvMsg(XID4,self,Me,reply,data(Value),id1),
	println(["Inline reaction ",rcvMsg(self,Me,reply,data(Value),id1)]),
	println(["Value=",Value]),

	% Submit a goal by way of a message
	% Note that it is processed after the above messages
	sendMsg(XID5,self,Me,eval,print_data(D)).
test023() :-
	iam(Me),
	% Send a queryref_acc message with all replies combined in Accumulator
	% Note that there are no query results for "sibling"
	%    so the returned Accumulator wll be empty.
	sendMsg(XID1,self,Me,queryref_acc,sibling(X,Y),id2),
	rcvMsg(XID1,self,Me,reply,[Accumulator.Acc],id2),
	println(["Inline reaction ",rcvMsg(self,Me,reply,Accumulator.Acc,id2)]),
	member(sibling(A,B),Accumulator.Acc),
	println(["sibling(A,B)=",A,",",B]).
test023() :-
	iam(Me),
	% Send a queryref_acc message with all replies combined in Accumulator
	sendMsg(XID1,self,Me,queryref_acc,parent(X,Y),id3),
	rcvMsg(XID1,self,Me,reply,[Accumulator.Acc],id3),
	println(["Inline reaction ",rcvMsg(self,Me,reply,Accumulator.Acc,id3)]),
	println(["Accumulator=",Accumulator.Acc]),
	element(parent(A,B),Accumulator.Acc),
	println(["parent(",A,",",B,")"]).

rcvMsg(XID,Protocol,From,rexec,[Object,Method|Args]|LocalContext) :-
	println(["Rule reaction ",rcvMsg(XID,From,rexec,[Object,Method|Args]|LocalContext)]),
	iam(Me),
	spawn(XID1,Object,Method|Args),
println(["<== spawn XID=",XID1]),
	rcvMsg(XID1,Protocol,Me,return,[Ret]),
println(["==> return XID=",XID1]),
	sendMsg(XID,Protocol,From,return,[Ret,Object,Method|Args]|LocalContext).

% Reaction to inform
rcvMsg(XID,Protocol,From,inform,[X|Xs]) :-
	println(["Rule reaction ",rcvMsg(XID,Protocol,From,inform,[X|Xs])]),
	retractall([X|Xs]),
	assert([X|Xs]).

% Reaction to the reply to the previously sent queryref
rcvMsg(XID,Protocol,From,reply,parent(X,Y)) :-
	println(["Rule reaction ",rcvMsg(XID,Protocol,From,inform,[X|Xs])]),
	println(["parent(",X,",",Y,")"]).

% Reaction to the timer
rcvMsg(XID,Protocol,From,return,[Ret,Timer,sleep,Millisec],"timer",Count0) :-
	println(["Rule reaction ",rcvMsg(XID,Protocol,From,return,[Ret,Timer,sleep,Millisec],timer,Count0)]),
	println(["Timer expired:",Count0]," "),
	iam(Me),
	Count=Count0+1,
	% Start the timer again
	sendMsg(XID,Protocol,Me,rexec,[Timer,sleep,Millisec],"timer",Count).

% Reaction rule to general queryref
rcvMsg(XID,Protocol,From,queryref,[X|Xs]|LocalContext) :-
	println(["Rule reaction 1 ",rcvMsg(XID,Protocol,From,queryref,[X|Xs]|LocalContext)]),
	derive([X|Xs]),
	sendMsg(XID,Protocol,From,reply,[X|Xs]|LocalContext).
rcvMsg(XID,Protocol,From,queryref,[X|Xs]|LocalContext) :-
	println(["Rule reaction 2 ",rcvMsg(XID,Protocol,From,queryref,[X|Xs]|LocalContext)]),
	sendMsg(XID,Protocol,From,end_of_transmission,[X|Xs]|LocalContext).

% Reaction rule to general queryref_acc
rcvMsg(XID,Protocol,From,queryref_acc,[X|Xs]|LocalContext) :-
	println(["Rule reaction 1 ",rcvMsg(XID,Protocol,From,queryref_acc,[X|Xs]|LocalContext)]),
	findall([X|Xs],[X|Xs],L),
	sendMsg(XID,Protocol,From,reply,[L]|LocalContext).
rcvMsg(XID,Protocol,From,queryref_acc,[X|Xs]|LocalContext) :-
	println(["Rule reaction 2 ",rcvMsg(XID,From,queryref_acc,[X|Xs]|LocalContext)]),
	sendMsg(XID,Protocol,From,end_of_transmission,[Accumulator.L]|LocalContext).

% Goal to be called via eval message
print_data(D) :-
	data(D),
	println(["D=",D]).

member(X,[X|Xs]).
member(X,[_|Xs]) :-
	member(X,Xs).
