% Updated for Prova version 1.7.2
% Demonstrate how to
% - use a reaction rule with performative as variable to intercept all messages
% - implement "distributed" message-based data integration
% - use shutdown predicate to intercept program termination
%   (try running this with "prova test035.prova -t -1" and press Ctrl-C
%    when the message exchange is complete.)
%   Shutdown can be used to send messages to inform about the agent's death
%      or to release resources.

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

:- eval(test035()).

% Shutdown procedure
shutdown() :-
	println(["Shutdown complete."]).

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

	% Update the mental state by way of 'inform' messages
	sendMsg(XID1,self,Me,inform,cs(employee(
													[first_name,"Joe"],
													[last_name,"Chung"],
													[title,professor],
													["reports_to","John Hennessy"]
												 ))),
	sendMsg(XID2,self,Me,inform,whois(person(
													[name,"Joe Chung"],
													[dept,cs],
													[status,employee],
													[email,"chung@cs.mega.edu"]
												 ))),
	sendMsg(XID3,self,Me,inform,whois(person(
													[name,"Chris Chang"],
													[dept,cs],
													[status,employee],
													[email,"chang@cs.mega.edu"]
												 ))),
	sendMsg(XID,self,Me,queryref,integrate(cs_person(R|Rs)),id0),
	rcvMult(XID,self,Me,reply,integrate(cs_person(R|Rs)),id0),

	println(["Inline reaction ",rcvMult(self,Me,reply,integrate(cs_person(R|Rs)),id0)]),
	println(["cs_person(R|Rs)=",R|Rs]," ").


integrate(cs_person(R|Rs)) :-
	println(["Integration rule ",integrate(cs_person(R|Rs))]),
	iam(Me),
	sendMsg(XID1,self,Me,queryref_acc,whois(person([name,N],[dept,cs],[status,S]|R1)),ida),
	rcvMsg(XID1,self,Me,reply,[List],ida),
	element(whois(person([name,N],[dept,cs],[status,S]|R1)),List),
	tokenize_list(N," ",[FN,LN]),
	println(["FN=",FN]),
	sendMsg(XID2,self,Me,queryref,cs(S([first_name,FN],[last_name,LN]|R2)),idb),
	rcvMult(XID2,self,Me,reply,cs(S([first_name,FN],[last_name,LN]|R2)),idb),
	append(R1,R2,[R|Rs]).

%====================================
% HELPER PREDICATES (part of toolkit)
%====================================

% 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 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,Protocol,From,queryref_acc,[X|Xs]|LocalContext)]),
	sendMsg(XID,Protocol,From,end_of_transmission,[L]|LocalContext).

append([],L,L).
append([X|L1],L2,[X|L3]):-
	append(L1, L2, L3).

