% This code is for running from built-in main() in ws.prova.tests.ProvaRunner3.
% This code is completely conversation-safe, i.e., multiple jobs can be running interleaved started by mystr_start/2.
% ProvaRunner3 in tandem with this rulebase is used to show a disciplined way to use asynchronous Communicator to
% submit multiple jobs running in parallel to rulebases.
% Note that the agent only runs one message at a time but multi-message conversations can be interleaved which is
% exactly what we are referring to by the words "in parallel".

handle_exception(JobID) :- 
	exception(Ex), 
	println([Ex]),
	runner(Runner), 
	% All exceptions are prefixed by JobID for the client to be able to discriminate them
	Runner.results_ready([JobID,Ex]),
	fail().

mylim(5).
mylim(1).

set_runner(Runner) :-
	runner(Runner),
	!.
set_runner(Runner) :-
	assert(runner(Runner)).

mytr_start(Runner,JobID) :-
	set_runner(Runner),
	% Note how we make JobID available to the exception handler 
	on_exception(java.lang.Exception, handle_exception(JobID)), 
	mytr_start_2(Runner,JobID).

mytr_start_2(Runner,JobID) :-
	% This clause demonstrates an exception occurring inside the Prova code
	Ex = java.lang.Exception("Prova exception raised."),
	raise(Ex).
mytr_start_2(Runner,JobID) :-
	println(["launch mytr"]),
	% Just to acquire a unique conversation-id and signal the start of the whole protocol
	iam(Me),
	sendMsg(XID, self, Me, start, [], []),
	assert(first(XID)),
	mylim(N),
	mytr(XID,N,JobID).

mytr(XID,M,JobID) :-
	iam(Me),
	sendMsg(XID, self, Me, a, a(1,M), JobID),
	rcvMult(XID, _, Me, b, b(B,M), JobID),
	println([result, XID, " ", b(B,M)]),
	% Make the result available asynchronously in the results thread of Java
	runner(Runner),
	% All results are prefixed by JobID for the client to be able to discriminate them
	Runner.results_ready([JobID,b(B,M)]),
	first(XID),
	retractall(first(XID)),
	% Must be XID: the same conversation-id as that in the above messages
	got(XID, b(B1,M1)),
	println([lost, b(XID1,B1,M1)]),
	Ex = java.lang.Exception("DISASTER!"),
	raise(Ex).

rcvMsg(XID, P, Ag, a, a(A,M), JobID) :-
	tr(A, B), B <= M,
	println([process, tr(A,B,M)]),
	sendMsg(XID, P, Ag, b, b(B,M), JobID),
	fail().
rcvMsg(XID, P, Ag, a, a(A,M), JobID) :-
	% Note that it is b(A,M) we are completing here
	sendMsg(XID, P, Ag, end_of_transmission, b(A,M), JobID).

rcvMsg(XID, _, _, _, X, JobID) :-
	first(XID),
	println([got(XID,X)," asserted."]),
	assert(got(XID, X)).

rcvMsg(XID, P, Ag, end_of_transmission, b(A,M), JobID) :-
	println(["Prova: the message ",JobID, b(A,M)," processing complete."]),
	runner(Runner),
	Runner.results_ready([JobID,"processing complete."]).

tr(1, 1).
tr(1, 2).
tr(1, 3).
tr(1, 4).
tr(1, 5).
tr(1, 6).
tr(1, 7).
tr(1, 8).
tr(1, 9).
tr(1, 10).
tr(1, 11).
tr(1, 12).
tr(1, 13).
tr(1, 14).
tr(1, 15).
tr(1, 16).
tr(1, 17).
tr(1, 18).
tr(1, 19).
tr(1, 20).
tr(1, 21).
tr(1, 22).
tr(1, 23).
tr(1, 24).
tr(1, 25).
tr(1, 26).
tr(1, 27).
tr(1, 28).
tr(1, 29).

% :- eval(mytr()).
