/*********************************************************************/
/* */
/* AgentService Framework */
/* www.agentservice.it */
/* */
/* Copyright (C) 2007 l.i.d.o. - DIST, University of Genoa, Italy */
/* GNU Lesser General Public License */
/* */
/* This library is free software; you can redistribute it and/or */
/* modify it under the terms of the GNU Lesser General Public */
/* License as published by the Free Software Foundation, */
/* version 2.1 of the License. */
/* */
/* This library is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
/* Lesser General Public License for more details. */
/* */
/* You should have received a copy of the GNU Lesser General Public */
/* License along with this library; if not, write to the */
/* Free Software Foundation, Inc., 59 Temple Place - Suite 330, */
/* Boston, MA 02111-1307, USA. */
/* */
/*********************************************************************/
using System;
// namespace che definisce i componenti
// di base per l'implementazione di nuovi
// tipi di agenti
using AgentService.Agent;
// namespace che definisce tutti gli
// elementi per la creazione di nuovi
// tipi di behaviour
using AgentService.Agent.Behaviour;
// namespace che definisce tutti gli
// elementi per la creazione di nuovi
// tipi knowledge
using AgentService.Agent.Knowledge;
// namespace che definisce le interfacce
// per i servizi di runtime
using AgentService.Agent.Runtime;
//
using AgentService.Platform.AMS;
// namespace che definisce i componenti
// per la messaggistica
using AgentService.Platform.MTS;
// namespace che definisce i componenti
// che implementano il servizio di pagine
// gialle
using AgentService.Platform.DF;
namespace AuctionDemo
{
///
/// this is the behaviour of the auctionner. It waits for the maximum number of bidders
/// and then starts the auction.
///
[Knowledge(typeof(AuctionData))]
public class ManageAuction:Behaviour
{
///
/// Knowledge that maintains information about the auction session
///
private AuctionData auction;
///
/// Constructor for the behaviour instance
///
/// the name of the instance
/// the reference to the knwoledge that holds information about the auction session
public ManageAuction(string name, AuctionData auction) : base(name)
{
this.auction = auction;
}
///
/// The entry point of the behaviour.
///
public override void Body()
{
this.Runtime.Console.AppendMessage("Behaviour [ManageAuction] started by: " + this.Owner.Name);
// it registers the service of the auctioneer at the directory facilitator
this.SetupAuctioneerService();
// it creates the message for the auction opening
MessageBody msgBody = new MessageBody();
float price = 0.0f;
string item = String.Empty;
int maxParticipants = 0;
try
{
this.LockKnowledge(this.auction);
price = this.auction.GetPrice(this);
item = this.auction.GetItem(this);
maxParticipants = this.auction.GetMaxParticipants(this);
// it creates the starting message
msgBody.Add("StartPrice",((object)price));
msgBody.Add("Item",item);
}
finally
{
this.ReleaseKnowledge(true);
}
this.Runtime.Console.AppendMessage("Auction: {0},{1}",item,price);
// it waits for the maximum number of bidders.
int wait = 10;
int timeout = 5000;
do
{
timeout -= wait;
System.Threading.Thread.Sleep(wait);
} while ((this.IncomingConvs.Count != maxParticipants) && (timeout > 0)) ;
if (this.IncomingConvs.Count > 0)
{
// it sends the opening message
foreach (IConversation conv in this.IncomingConvs)
{
conv.SendMessage(msgBody);
}
this.Runtime.Console.AppendMessage("Sent Auction Data");
bool bClosed = false;
AgentMessage[] recMsg = new AgentMessage[maxParticipants];
AID actualWinner = null;
float actualPrice = price;
do
{
// it waits for the messages from each bidders
for (int i = 0; i < maxParticipants; i++)
{
IConversation conv = this.IncomingConvs[i];
if (conv.State == ConversationState.Active)
{
recMsg[i] = this.IncomingConvs[i].WaitForMessage();
}
else
{
recMsg[i] = null;
}
}
this.Runtime.Console.AppendMessage("Got Proposals");
int buddies = this.EvaluateProposals(recMsg, ref actualWinner, ref actualPrice);
this.LockKnowledge(this.auction);
this.auction.SetMaxParticipants(this, buddies);
this.auction.SetPrice(this, actualPrice);
this.auction.Update(this);
this.ReleaseKnowledge(true);
if (buddies > 0)
{
if (buddies == 1)
{
// if it remains only one bidder, then it is the winner
MessageBody closeBody = new MessageBody();
closeBody.Add("Verb", "Close");
closeBody.Add("Winner", actualWinner);
closeBody.Add("Price", price);
for (int ndx = 0; ndx < recMsg.Length; ndx++)
{
AgentMessage msg = recMsg[ndx];
if (msg != null)
{
this.IncomingConvs[ndx].SendMessage(closeBody);
}
}
bClosed = true;
this.Runtime.Console.AppendMessage("Win: [Winner: {0}, Price: {1}]", actualWinner.Name, actualPrice);
}
else
{
// there is no winner: the bidders must to send another raising price
MessageBody body = new MessageBody();
body.Add("Verb", "Run");
body.Add("Winner", actualWinner);
body.Add("Price", (object)actualPrice);
for (int ndx = 0; ndx < recMsg.Length; ndx++)
{
AgentMessage msg = recMsg[ndx];
if (msg != null)
{
this.IncomingConvs[ndx].SendMessage(body);
}
}
this.Runtime.Console.AppendMessage("Run: [Winner: {0}, Price: {1}]", actualWinner.Name, actualPrice);
}
}
else
{
bClosed = true;
this.Runtime.Console.AppendMessage("Abort: All Retired");
}
} while (bClosed == false);
this.Runtime.Console.AppendMessage("Auction Finished");
}
else
this.Runtime.Console.AppendMessage("Abort: No Bidders");
}
///
/// Evaluates the bidders raising price and calculates the current winner and price.
///
/// the incoming message array
/// the current winner
/// the current price
/// the number of active bidders
private int EvaluateProposals(AgentMessage[] messages, ref AID actualWinner, ref float actualPrice)
{
int participants = messages.Length;
for(int ndx = 0; ndx < messages.Length; ndx++)
{
// if the message is null then it decrements the number of active bidders.
if (messages[ndx] == null)
{
participants--;
}
else
{
// if the message is not null, it gets the information about the raising
// price or "escape"
AgentMessage msg = messages[ndx];
string verb = msg.Body["Verb"] as string;
if (verb == "Offer")
{
//the current bidder makes a bid
//and the auctionner have to decide the winner
if (actualWinner == null)
{
actualPrice = (float) msg.Body["Price"];
actualWinner = msg.Envelope.From;
}
else
{
float tmpPrice = (float) msg.Body["Price"];
if (tmpPrice > actualPrice)
{
actualPrice = tmpPrice;
actualWinner = msg.Envelope.From;
}
}
}
else
{
//the current bidder is drop-out
messages[ndx] = null;
this.IncomingConvs[ndx].Close();
participants--;
}
}
}
return participants;
}
///
/// Constructs the auctioneer service description and sends it to the DF
///
/// descrittore del servizio di banditore
private void SetupAuctioneerService()
{
DFAgentDescription dfDescription = new DFAgentDescription(this.Owner);
dfDescription.Services.Add(new ServiceDescription("Auctioneer","Auction"));
this.Runtime.YPageSvc.Register(dfDescription);
}
}
}