% Since version 2.0 RC2
% Demonstrate the Petri net example from http://is.tm.tue.nl/research/patterns/download/pi-hype.pdf.
% Note that each sendMsg/rcvMsg pair models a long-running activity that is triggered by a sendMsg
%    and is complete when the message matching the pattern in rcvMsg.
% The exact order in which the tasks are completed is irrelevant so that one branch could progress faster than another.
% However, at synchronisation joins, the processes meet each other.

:- eval(consult("utils.prova")).

:- eval(process_join_Aalst()).

process_join_Aalst() :-
	println(["==========process_join_van_der_Aalst=========="]),
	iam(Me),
	% A more or less useless message to signal the start of the conversation. It may do something useful in a real application. 
	sendMsg(XID,self,Me,start,[]),
	% The result of the above is that we now have the conversation-id XID initialised.
	% Create join predicates join_1 and join_2 with lists of required input patterns in the last arguments.
	init_join(XID,join_1,[c(),e()]),
	init_join(XID,join_2,[d(),g()]),

	sendMsg(XID,self,Me,reply,a()),
	rcvMsg(XID,self,Me,reply,a()),
	% This will create two parallel processing streams.
	% Note that Prova does not run them in separate threads but they are independent and can communicate
	%    with other agents asynchronously effectively allowing for parallel processing.
	fork_b_e(Me,XID).

fork_b_e(Me,XID) :-
	sendMsg(XID,self,Me,reply,b()),
	rcvMsg(XID,self,Me,reply,b()),
	sendMsg(XID,self,Me,reply,c()),
	rcvMsg(XID,self,Me,reply,c()),
	join(Me,XID,join_1,c()),
	sendMsg(XID,self,Me,reply,d()),
	rcvMsg(XID,self,Me,reply,d()),
	join(Me,XID,join_2,d()).
fork_b_e(Me,XID) :-
	sendMsg(XID,self,Me,reply,e()),
	rcvMsg(XID,self,Me,reply,e()),
	% Tell the join join_1 that a new pattern is ready
	join(Me,XID,join_1,e()).

% The following rule will be invoked by join once all the inputs for join1 are assembled
join_1(Me,XID,Inputs) :-
	Inputs.contains([c]),
	Inputs.contains([e]),
	println(["Joined for XID=",XID," with inputs: ",[c(),e()]]),
	sendMsg(XID,self,Me,reply,g()),
	rcvMsg(XID,self,Me,reply,g()),
	join(Me,XID,join_2,g()).

% The following rule will be invoked by join once all the inputs for join2 are assembled
join_2(Me,XID,Inputs) :-
	Inputs.contains([d]),
	Inputs.contains([g]),
	println(["Joined for XID=",XID," with inputs: ",[d(),g()]]),
	sendMsg(XID,self,Me,reply,h()),
	rcvMsg(XID,self,Me,reply,h()),
	println(["All done"]).

% Prints:
% ==========process_join_van_der_Aalst==========
% Joined for XID=prova@mymachine with inputs: [["c"],["e"]]
% Joined for XID=prova@mymachine with inputs: [["d"],["g"]]
% All done