% Since version 1.7.1
% Demonstrate a useful interaction pattern: First Reaction.
% When several inline reactions are waiting for incoming messages with
%    the same XID, the first reaction to receive the matching message and
%    process it can send an end_of_transmission to the same XID and, possibly,
%    indicating a correlation constant to target specific reactions.
%    In this way, the corresponding waiting reactions are discharged and sending
%    a subsequent message proves that they have disappeared.    

% This example is the first one to show multiple inline reactions waiting
%    on the same XID. The correlation constants can be used to selectively
%    target reactions with replies and end_of_transmission messages discharging
%    reactions.

% The reaction rule for intercepting 'reply' messages at the end of the code
%    shows that inline rcvMsg reactions are always processed before
%    standalone reaction rules. There is currently no provision from stopping
%    the standalone reaction rules to porcess the message.
% See example ex020.prova for the meaning and the use of CUT in inline reactins.
% We might introduce an abandon() built-in predicate to stop the processing
%    of the current message or goal, which will introduce a way of stopping further
%    processing to continue.

:- eval(ex018()).

ex018() :-
	println(["==========ex018=========="]),
	iam(Me),
	% Note the use of corr_a to provide additional correlation constant
	%    that is used to distinguish reactions to similar messages
	%    within the same conversation-id XID 
	sendMsg(XID,self,Me,reply,a(2),corr_a),
	ex018_inner(XID,Me).

ex018_inner(XID,Me) :-
	rcvMult(XID,self,Me,reply,a(1),corr_a),
	println(["Inline reaction 1: ",rcvMult(XID,self,Me,reply,a(1),corr_a)]).
ex018_inner(XID,Me) :-
	% Correlation constant corr_b is different from the one used above
	rcvMult(XID,self,Me,reply,a(1),corr_b),
	println(["Inline reaction 2: ",rcvMult(XID,self,Me,reply,a(1),corr_b)]).
ex018_inner(XID,Me) :-
	% Correlation constant corr_b is different from the one used above
	rcvMult(XID,self,Me,reply,a(1),corr_b),
	println(["Inline reaction 3: ",rcvMult(XID,self,Me,reply,a(1),corr_b)]).
ex018_inner(XID,Me) :-
	rcvMsg(XID,self,Me,reply,a(2),corr_a),
	println(["Inline reaction 4: ",rcvMsg(XID,self,Me,reply,a(2))]),
	% Terminate the other waiting reactions with correlation constant corr_a
	%  (the one in the first ex018_inner clause)
	sendMsg(XID,self,Me,end_of_transmission,[_|_],corr_a),
	% Prove that no reactions are active any more for corr_a in this XID:
	%    send a message that could have been processed in the first ex018_inner
	% clause, had the previous end_of_transmission not discharged it.
	sendMsg(XID,self,Me,reply,a(1),corr_a),

	% Prove that the reactions in the second and thrid ex018_inner clauses are
	%    still active (they will respond).  
	sendMsg(XID,self,Me,reply,a(1),corr_b),
	% Terminate the last waiting reaction with correlation constant corr_b
	%  (the one in the second ex018_inner clause)
	sendMsg(XID,self,Me,end_of_transmission,[_|_],corr_b),
	% Prove that the reaction in the third ex018_inner clause has gone
	%    (it will NOT respond).  
	sendMsg(XID,self,Me,reply,a(1),corr_b).

% A testing harness for printing incoming end_of_transmission messages.
rcvMsg(XID,Protocol,From,end_of_transmission,[X|Xs]|Extra) :-
	println(["end_of_transmission for conversation-id ",XID,": ",[X|Xs],","|Extra]).

% A testing harness for printing all incoming 'reply' messages.
rcvMsg(XID,Protocol,From,reply,[X|Xs]|Extra) :-
	println(["reply for conversation-id ",XID,": ",[X|Xs],","|Extra]).
