% Demonstrate how
%    - to implement a more standard query_ref protocol.
%    - to implement a Direct Buy protocol
%         (see http://taga.umbc.edu/taga2/doc/taga004)
%    - inline reactions simplify the programming of multiple choices.

:- eval(directbuy_buyer_0()).
:- eval(directbuy_seller_0()).

product(car(volvo,s60),11000).
product(car(ford,fiesta),5000).

directbuy_buyer_0() :-
	println(["==========directbuy_buyer_0=========="]),
	iam(Me),
	sendMsg(XID,self,Me,query_ref,car(ford,fiesta),buyer),
	directbuy_buyer_1(XID,self,Me,Product,4500),
	println(["Result:"|Product]," ").
directbuy_buyer_0() :-
	iam(Me),
	sendMsg(XID,self,Me,query_ref,car(volvo,s60),buyer),
	directbuy_buyer_1(XID,self,Me,Product,12000),
	println(["Result:"|Product]," ").
directbuy_buyer_0() :-
	iam(Me),
	sendMsg(XID,self,Me,query_ref,car(ford,focus),buyer),
	directbuy_buyer_1(XID,self,Me,Product,12000),
	println(["Result:",Product]).
directbuy_buyer_0() :-
	iam(Me),
	sendMsg(XID,self,Me,end_of_transmission,[X|Xs],buyer).

directbuy_buyer_1(XID,Protocol,From,Product,Price) :-
	% Wait for a generic reply only knowing the conversation-id XID 
	rcvMsg(XID,Protocol,From,Perf,Product,seller),
	% Proceed based on their first reply Perf [agree OR refuse]
	directbuy_buyer_2(Perf,XID,Protocol,From,Product,Price).

directbuy_buyer_2(agree,XID,Protocol,From,Product,Price) :-
	!,
	rcvMsg(XID,Protocol,From,inform_result,Product,seller),
	println(["Agreed-1:"|Product]," "),
	% Send our offer (Price for Product)
	sendMsg(XID,Protocol,From,request,[Product,Price],buyer),
	directbuy_buyer_3(XID,Protocol,From,Product,Price).
directbuy_buyer_2(refuse,XID,Protocol,From,Product,Price) :-
	println(["Refused-1"|Product]," "),
	fail().

directbuy_buyer_3(XID,Protocol,From,Product,Price) :-
	% Wait for seller's decision on our offer
	rcvMsg(XID,Protocol,From,Perf,[Product,Price],seller),
	% Proceed based on their first reply [agree OR refuse]
	directbuy_buyer_4(Perf,XID,Protocol,From,Product,Price).

directbuy_buyer_4(agree,XID,Protocol,From,Product,Price) :-
	!,
	println(["Agreed-2:",Product,"for",Price]," "),
	rcvMsg(XID,Protocol,From,inform_done,[Product,Price],seller),
	println(["Transaction complete:",Product,"for",Price]," ").
directbuy_buyer_4(refuse,XID,Protocol,From,Product,Price) :-
	println(["Refused-2",Product,"for",Price]," "),
	fail().

directbuy_seller_0() :-
	println(["==========directbuy_seller_0=========="]),
	rcvMult(XID,Protocol,From,query_ref,Product,buyer),
	directbuy_seller_1(XID,Protocol,From,Product).

directbuy_seller_1(XID,Protocol,From,Product) :-
	product(Product|_),
	!,
	sendMsg(XID,Protocol,From,agree,Product,seller),
	sendMsg(XID,Protocol,From,inform_result,Product,seller),
	directbuy_seller_2(yes,XID,Protocol,From,Product).
directbuy_seller_1(XID,Protocol,From,Product) :-
	sendMsg(XID,Protocol,From,refuse,Product,seller),
	directbuy_seller_2(no,XID,Protocol,From,Product).

directbuy_seller_2(yes,XID,Protocol,From,Product) :-
	!,
	rcvMsg(XID,Protocol,From,request,[Product,Price],buyer),
	product(Product,SellerPrice),
	directbuy_seller_3(XID,Protocol,From,Product,Price,SellerPrice).
directbuy_seller_2(no,XID,Protocol,From,Product).

directbuy_seller_3(XID,Protocol,From,Product,Price,SellerPrice) :-
	Price>SellerPrice,
	!,
	sendMsg(XID,Protocol,From,agree,[Product,Price],seller),
	sendMsg(XID,Protocol,From,inform_done,[Product,Price],seller),
	directbuy_seller_4(agree,XID,Protocol,From,Product,Price).
directbuy_seller_3(XID,Protocol,From,Product,Price,SellerPrice) :-
	sendMsg(XID,Protocol,From,refuse,[Product,Price],seller),
	directbuy_seller_4(refuse,XID,Protocol,From,Product,Price).

directbuy_seller_4(agree,XID,Protocol,From,Product,Price).
directbuy_seller_4(refuse,XID,Protocol,From,Product,Price).

% The general pattern for each state is:
% state_j(...) :-
%    event(...),
%    condition_j_j+1(...),
%    [!,]
%    entry_actions_j+1(...),
%    state_j+1(...).
% state_j(...) :-
%    ...
% If there are several possible events in state_j then
%    multiple next states are created parametrized by the parameters
%    that separate these events.

% Current limitations:
%   - rcvMult cannot normally occur at any state deeper than 0
%     in the SAME conversation
%     but rcvMult may be nested for different conversations-id(s).
%   - if it does then end_of_transmission is expected from the caller and
%     it should then contain a unique context.
%   - 


