View Javadoc

1   /*
2    * @(#)GameDistributorInteractive.java Jul 8, 2004
3    * 
4    * Copyright (c) 2003-2005 Delft University of Technology, Jaffalaan 5, 2628 BX
5    * Delft, the Netherlands. All rights reserved.
6    * 
7    * See for project information <a href="http://www.simulation.tudelft.nl/">
8    * www.simulation.tudelft.nl </a>.
9    * 
10   * The source code and binary code of this software is proprietary information
11   * of Delft University of Technology.
12   */
13  
14  package org.gscg.gameactors;
15  
16  import java.io.IOException;
17  import java.io.ObjectOutputStream;
18  import java.io.Serializable;
19  import java.net.URL;
20  import java.rmi.RemoteException;
21  import java.util.HashSet;
22  import java.util.Iterator;
23  import java.util.List;
24  import java.util.Properties;
25  import java.util.Set;
26  
27  import javax.vecmath.Point3d;
28  
29  import nl.tudelft.simulation.actor.messagehandlers.HandleAllMessages;
30  import nl.tudelft.simulation.actor.messagehandlers.MessageHandlerInterface;
31  import nl.tudelft.simulation.dsol.experiment.TimeUnit;
32  import nl.tudelft.simulation.dsol.experiment.TimeUnitInterface;
33  import nl.tudelft.simulation.dsol.simulators.AnimatorInterface;
34  import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
35  import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
36  import nl.tudelft.simulation.dsol.statistics.charts.XYChart;
37  import nl.tudelft.simulation.event.Event;
38  import nl.tudelft.simulation.event.EventInterface;
39  import nl.tudelft.simulation.event.EventType;
40  import nl.tudelft.simulation.jstats.distributions.DistConstant;
41  import nl.tudelft.simulation.jstats.distributions.DistContinuous;
42  import nl.tudelft.simulation.jstats.streams.StreamInterface;
43  import nl.tudelft.simulation.language.io.URLResource;
44  import nl.tudelft.simulation.logger.Logger;
45  import nl.tudelft.simulation.messaging.devices.reference.FaxDevice;
46  import nl.tudelft.simulation.supplychain.actor.SupplyChainActor;
47  import nl.tudelft.simulation.supplychain.actor.Trader;
48  import nl.tudelft.simulation.supplychain.banking.Bank;
49  import nl.tudelft.simulation.supplychain.banking.BankAccount;
50  import nl.tudelft.simulation.supplychain.content.Bill;
51  import nl.tudelft.simulation.supplychain.content.Content;
52  import nl.tudelft.simulation.supplychain.content.InternalDemand;
53  import nl.tudelft.simulation.supplychain.content.Order;
54  import nl.tudelft.simulation.supplychain.content.OrderBasedOnQuote;
55  import nl.tudelft.simulation.supplychain.content.OrderConfirmation;
56  import nl.tudelft.simulation.supplychain.content.Payment;
57  import nl.tudelft.simulation.supplychain.content.Quote;
58  import nl.tudelft.simulation.supplychain.content.RequestForQuote;
59  import nl.tudelft.simulation.supplychain.product.Product;
60  import nl.tudelft.simulation.supplychain.roles.Role;
61  import nl.tudelft.simulation.supplychain.stock.StockInterface;
62  import nl.tudelft.simulation.supplychain.stock.StockUpdateData;
63  import nl.tudelft.simulation.supplychain.transport.TransportMode;
64  
65  import org.gscg.common.GameActorInterface;
66  import org.gscg.common.gui.exceptions.ReceivedUnknownEventException;
67  import org.gscg.common.interactionlayer.AnnounceInterface;
68  import org.gscg.common.interactionlayer.timecontrol.GlobalRowOrColumnNumber;
69  import org.gscg.experiment.HandlerParser;
70  import org.gscg.game.GameGlobalData;
71  import org.gscg.singleuser.handlers.InteractiveOrderHandlerStock;
72  import org.gscg.singleuser.interactionlayer.SingleUserInteractionLayerInterface;
73  import org.gscg.singleuser.interactionlayer.business.statistics.CustomerStatistics;
74  import org.gscg.singleuser.interactionlayer.dataobjects.DateIntData;
75  import org.gscg.singleuser.interactionlayer.dataobjects.content.BillData;
76  import org.gscg.singleuser.interactionlayer.dataobjects.content.QuoteData;
77  import org.gscg.singleuser.interactionlayer.dataobjects.content.RFQData;
78  import org.gscg.singleuser.interactionlayer.dataobjects.content.RFQDataSuppliers;
79  import org.gscg.singleuser.interactionlayer.dataobjects.content.SentOrderConfirmationData;
80  import org.gscg.singleuser.interactionlayer.dataobjects.content.SentQuoteData;
81  import org.jdom.Element;
82  
83  /***
84   * The GameDistributorInteractive extends a GameDistributor from the
85   * supplychain-game project and provides additional interactive functionalities.
86   * <br>
87   * Copyright (c) 2003-2005 Delft University of Technology, Jaffalaan 5, 2628 BX
88   * Delft, the Netherlands. All rights reserved.
89   * 
90   * See for project information <a href="http://www.simulation.tudelft.nl/">
91   * www.simulation.tudelft.nl </a>.
92   * 
93   * The source code and binary code of this software is proprietary information
94   * of Delft University of Technology.
95   * 
96   * @author <a
97   *         href="http://www.tbm.tudelft.nl/webstaf/alexandv/index.htm">Alexander
98   *         Verbraeck </a>
99   * @version $Revision: 1.3 $ $Date: 2005/08/10 11:23:30 $
100  * @since 1.0.0 <br>
101  */
102 
103 public class GameManufacturerInteractive extends GameManufacturer implements
104 		GameActorInteractiveInterface, GameActorInterface, AnnounceInterface
105 {
106 	/*** the map with manufacturers after deserialization */
107 	private static Set manufacturers = new HashSet();
108 
109 	/***
110 	 * @return returns the set with manufacturers of which the interactivity
111 	 *         mode has changed after deseriliazation due to changes in the
112 	 *         manufacturer.properties file
113 	 */
114 	public static Set getChangedManufacturers()
115 	{
116 		return GameManufacturerInteractive.manufacturers;
117 	}
118 
119 	/*** the serial version uid */
120 	private static final long serialVersionUID = 13L;
121 
122 	/*** a client has sent an RFQ which forms the basis for a quote */
123 	public static final EventType RFQ_SENT_BY_CLIENT_EVENT = new EventType(
124 			"RFQ_SENT_BY_CLIENT_EVENT");
125 
126 	/*** a client has selected a quote which forms the basis for an order */
127 	public static final EventType SELECTED_QUOTE_EVENT = new EventType(
128 			"SELECTED_QUOTE_EVENT");
129 
130 	/*** a client has selected a bill to pay */
131 	public static final EventType PAY_BILL_EVENT = new EventType(
132 			"PAY_BILL_EVENT");
133 
134 	/*** a client has selected an rfq and sent a quote */
135 	public static final EventType QUOTE_SENT_BY_CLIENT_EVENT = new EventType(
136 			"QUOTE_SENT_BY_CLIENT_EVENT");
137 
138 	/*** a client has deleted an rfq */
139 	public static final EventType RFQ_DELETED_BY_CLIENT_EVENT = new EventType(
140 			"RFQ_DELETED_BY_CLIENT_EVENT");
141 
142 	/*** a client has confirmed an order */
143 	public static final EventType ORDER_CONFIRMATION_SENT_BY_CLIENT_EVENT = new EventType(
144 			"ORDER_CONFIRMATION_SENT_BY_CLIENT_EVENT");
145 
146 	/*** events fired by client */
147 	private EventType[] eventsSentByClientArray = {
148 			GameManufacturerInteractive.ORDER_CONFIRMATION_SENT_BY_CLIENT_EVENT,
149 			GameManufacturerInteractive.RFQ_SENT_BY_CLIENT_EVENT,
150 			GameManufacturerInteractive.SELECTED_QUOTE_EVENT,
151 			GameManufacturerInteractive.PAY_BILL_EVENT,
152 			GameManufacturerInteractive.QUOTE_SENT_BY_CLIENT_EVENT,
153 			GameManufacturerInteractive.RFQ_DELETED_BY_CLIENT_EVENT};
154 
155 	/*** the SingleUserInteractionLayerInterface */
156 	private SingleUserInteractionLayerInterface singleUserInteractionLayer;
157 
158 	/***
159 	 * constructs a new GameDistributorInteractive; used when dragging and
160 	 * dropping an actor
161 	 * 
162 	 * @param name the name
163 	 * @param simulator the simulator
164 	 * @param position the position
165 	 * @param bank the bank
166 	 */
167 	public GameManufacturerInteractive(final String name,
168 			final DEVSSimulatorInterface simulator, final Point3d position,
169 			final Bank bank)
170 	{
171 		super(name, simulator, position, bank);
172 	}
173 
174 	/***
175 	 * constructs a new GameDistributorInteractive
176 	 * 
177 	 * @param globalSupplyChainData the global supply chain data
178 	 * @param name the name
179 	 * @param simulator the simulator
180 	 * @param position the position
181 	 * @param roles the roles to implement
182 	 * @param bank the bank
183 	 * @param initialBankAccount the initial bank account
184 	 * @param product the product
185 	 * @param amount the amount
186 	 * @param suppliers the suppliers
187 	 */
188 	public GameManufacturerInteractive(
189 			final GameGlobalData globalSupplyChainData, final String name,
190 			final DEVSSimulatorInterface simulator, final Point3d position,
191 			final Role[] roles, final Bank bank,
192 			final double initialBankAccount, final Product[] product,
193 			final Double[] amount, final Trader[] suppliers)
194 	{
195 		super(name, simulator, position, roles, bank, initialBankAccount,
196 				product, amount, globalSupplyChainData, suppliers);
197 	}
198 
199 	/***
200 	 * constructs a new GameDistributorInteractive
201 	 * 
202 	 * @param globalSupplyChainData the global supply chain data
203 	 * @param name the name
204 	 * @param simulator the simulator
205 	 * @param position the position
206 	 * @param roles the roles to implement
207 	 * @param bank the bank
208 	 * @param product the product
209 	 * @param amount the amount
210 	 * @param suppliers the suppliers
211 	 */
212 	public GameManufacturerInteractive(
213 			final GameGlobalData globalSupplyChainData, final String name,
214 			final DEVSSimulatorInterface simulator, final Point3d position,
215 			final Role[] roles, final Bank bank, final Product[] product,
216 			final Double[] amount, final Trader[] suppliers)
217 	{
218 		super(name, simulator, position, roles, bank, product, amount,
219 				globalSupplyChainData, suppliers);
220 	}
221 
222 	/***
223 	 * @see org.gscg.gameactors.GameManufacturer#init()
224 	 */
225 	protected void init()
226 	{
227 		// check whether we are in an interactive mode or
228 		// computer-controlled mode
229 
230 		// read properties
231 		Properties properties = new Properties();
232 		try
233 		{
234 			properties.load(URLResource
235 					.getResourceAsStream("/manufacturer.properties"));
236 		} catch (Exception exception)
237 		{
238 			exception.printStackTrace();
239 		}
240 		if (properties.getProperty(this.name) != null)
241 		{
242 			String result = properties.getProperty(this.name);
243 			if (result.equalsIgnoreCase("false"))
244 			{
245 				super.humanControlled = false;
246 				Logger.info(this, "init", "GameManufacturerInteractive: "
247 						+ this.name + " set to computer-controlled mode");
248 				this.addComputerControlledContentHandlers();
249 			} else if (result.equalsIgnoreCase("true"))
250 			{
251 				try
252 				{
253 					if (this.simulator.getReplication().getRunControl()
254 							.getWarmupPeriod() > 0.0)
255 					{
256 						// subscribe to warm-up events; these events are used
257 						// for building up a history in a game, after the
258 						// warmu-up period is finished, and if necessary,
259 						// handlers are swapped from a computer-controlled mode
260 						// to an interactive mode
261 						this.simulator.addListener(this,
262 								SimulatorInterface.WARMUP_EVENT);
263 						super.humanControlled = false;
264 						super.warmingUp = true;
265 						Logger
266 								.info(
267 										this,
268 										"init",
269 										"GameManufacturerInteractive: "
270 												+ this.name
271 												+ " set to computer-controlled mode due to the presence of a warm-up period.");
272 						this.addComputerControlledContentHandlers();
273 					} else
274 					{
275 						super.humanControlled = true;
276 						Logger.info(this, "init",
277 								"GameManufacturerInteractive: " + this.name
278 										+ " set to interactive mode");
279 						this.addInteractiveContentHandlers();
280 					}
281 				} catch (RemoteException remoteException)
282 				{
283 					Logger.severe(this, "init", remoteException);
284 				}
285 			}
286 		} else
287 		{
288 			// no key found
289 			Logger.severe(this, "init",
290 					"GameManufacturerInteractive: no key found for "
291 							+ this.name + " in properties: ." + properties);
292 		}
293 
294 		//
295 		// CHARTS
296 		//
297 		try
298 		{
299 			if (this.simulator instanceof AnimatorInterface)
300 			{
301 				XYChart bankChart = new XYChart(this.simulator, "BankAccount "
302 						+ this.name);
303 				bankChart.add("bank account", this.bankAccount,
304 						BankAccount.BANK_ACCOUNT_CHANGED_EVENT);
305 			}
306 		} catch (RemoteException remoteException)
307 		{
308 			Logger.severe(this, "init", remoteException);
309 		}
310 	}
311 
312 	/***
313 	 * @see org.gscg.gameactors.GameManufacturer#addDevices()
314 	 */
315 	protected void addDevices()
316 	{
317 		try
318 		{
319 			StreamInterface stream = this.simulator.getReplication().getStream(
320 					"default");
321 			double hour = TimeUnit.convert(1.0, TimeUnitInterface.HOUR,
322 					this.simulator);
323 			DistContinuous hourDist = new DistConstant(stream, hour);
324 			// give the actor a fax device which is checked every hour
325 			FaxDevice fax = new FaxDevice("GameManufacturerFax", this.simulator);
326 			addSendingDevice(fax);
327 			MessageHandlerInterface secretary = new HandleAllMessages(this);
328 			addReceivingDevice(fax, secretary, hourDist);
329 		} catch (RemoteException remoteException)
330 		{
331 			Logger.severe(this, "addDevices", remoteException);
332 		}
333 	}
334 
335 	/***
336 	 * @see org.gscg.common.interactionlayer.AnnounceInterface#announce(nl.tudelft.simulation.event.EventType,
337 	 *      boolean)
338 	 */
339 	public void announce(final EventType eventType, final boolean announce)
340 	{
341 		if (eventType.equals(StockInterface.STOCK_CHANGE_EVENT))
342 		{
343 			List products = super.getProductsOnStock();
344 			for (int i = 0; i < products.size(); i++)
345 			{
346 				Product product = (Product) products.get(i);
347 				this.stock.getActualAmount(product);
348 				StockUpdateData data = new StockUpdateData(product.getName(),
349 						this.stock.getActualAmount(product), this.stock
350 								.getClaimedAmount(product), this.stock
351 								.getOrderedAmount(product));
352 				try
353 				{
354 					this.singleUserInteractionLayer.notifyAnnounced(new Event(
355 							StockInterface.STOCK_CHANGE_EVENT, this, data));
356 				} catch (RemoteException remoteException)
357 				{
358 					Logger.severe(this, "announce", remoteException);
359 				}
360 			}
361 			return;
362 		}
363 		new ReceivedUnknownEventException(this, "announce", eventType);
364 	}
365 
366 	/***
367 	 * @see nl.tudelft.simulation.event.EventListenerInterface#notify(nl.tudelft.simulation.event.EventInterface)
368 	 */
369 	public void notify(final EventInterface event)
370 	{
371 		if (event.getType().equals(GlobalRowOrColumnNumber.UPDATE_CURRENT_DAY))
372 		{
373 			// we use these events to update the statistics on a daily basis
374 			this.sendStockUpdateEvent();
375 			this.bankAccount.sendBalanceUpdateEvent();
376 			return;
377 		}
378 		if (event.getType().equals(
379 				GameManufacturerInteractive.RFQ_SENT_BY_CLIENT_EVENT))
380 		{
381 			// make the internal demand
382 			RFQDataSuppliers submitRFQData = (RFQDataSuppliers) event
383 					.getContent();
384 			Product product = this.globalSupplyChainData
385 					.getProduct(submitRFQData.getProductName());
386 			double earliestDeliveryDate = DateIntData.makeSimulationDate(
387 					submitRFQData.getEarliestDelivery(), this.simulator);
388 
389 			double latestDeliveryDate = DateIntData.makeSimulationDate(
390 					submitRFQData.getLatestDelivery(), this.simulator);
391 			// we check whether the simulation date is not already further
392 			// than the delivery dates, if so we ignore the rfq
393 			try
394 			{
395 				if (earliestDeliveryDate > this.simulator.getSimulatorTime())
396 				{
397 					InternalDemand internalDemand = new InternalDemand(this,
398 							product, submitRFQData.getAmount(),
399 							earliestDeliveryDate, latestDeliveryDate);
400 					String[] suppliers = submitRFQData.getSuppliers();
401 					handleContent(internalDemand);
402 					// make the RFQ and send it out to the selected actors
403 					for (int i = 0; i < suppliers.length; i++)
404 					{
405 						SupplyChainActor supplier = this.globalSupplyChainData
406 								.getSupplyChainActor(suppliers[i]);
407 						RequestForQuote rfq = new RequestForQuote(this,
408 								supplier, internalDemand, product,
409 								submitRFQData.getAmount());
410 						this.sendContent(rfq, 0.0);
411 					}
412 				} else
413 				{
414 					Logger
415 							.info(
416 									this,
417 									"notify",
418 									"GameManufacturerInteractive did not send RFQ since the earliest delivery date has already been passed in the game.");
419 				}
420 			} catch (RemoteException remoteException)
421 			{
422 				Logger.severe(this, "notify", remoteException);
423 			}
424 			return;
425 		}
426 		if (event.getType().equals(
427 				GameManufacturerInteractive.SELECTED_QUOTE_EVENT))
428 		{
429 			QuoteData data = (QuoteData) event.getContent();
430 
431 			// first create the quote
432 			SupplyChainActor sender = this.globalSupplyChainData
433 					.getSupplyChainActor(data.getSenderName());
434 			try
435 			{
436 				double proposedDeliveryDate = DateIntData.makeSimulationDate(
437 						data.getProposedDelivery(), this.simulator);
438 
439 				List quotes = super.getGameContentStore().getContentList(
440 						data.getRfqData().getInternalDemandIdentifier(),
441 						Quote.class, false);
442 				OrderBasedOnQuote order = null;
443 				for (int i = 0; i < quotes.size(); i++)
444 				{
445 					Quote quote = (Quote) quotes.get(i);
446 					if (quote.getSender().getName().equalsIgnoreCase(
447 							sender.getName()))
448 					{
449 						order = new OrderBasedOnQuote(quote.getReceiver(),
450 								quote.getSender(), data.getRfqData()
451 										.getInternalDemandIdentifier(),
452 								proposedDeliveryDate, quote);
453 						break;
454 					}
455 				}
456 
457 				// let the interactive quote handler know that
458 				// we have handled a quote for a rfq
459 				// we block further quotes for this rfq
460 				if (order != null)
461 				{
462 					super.interactiveQuoteHandler.addAnsweredQuote(order
463 							.getQuote());
464 				}
465 
466 				this.sendContent(order, 0.0);
467 
468 				// remove the quotes from the content store
469 				for (int i = 0; i < quotes.size(); i++)
470 				{
471 					super.getGameContentStore().removeContent(
472 							(Content) quotes.get(i), false);
473 				}
474 			} catch (Exception exception)
475 			{
476 				Logger.severe(this, "notify", exception);
477 			}
478 			return;
479 		}
480 		if (event.getType().equals(GameManufacturerInteractive.PAY_BILL_EVENT))
481 		{
482 			BillData data = (BillData) event.getContent();
483 			Bill bill = (Bill) super.getGameContentStore().getContentList(
484 					data.getInternalDemandID(), Bill.class, false).get(0);
485 			if (bill == null)
486 			{
487 				Logger.severe(this, "notify PAY_BILL_EVENT",
488 						"bill not found in ContentStore");
489 			} else
490 			{
491 				// we pay the bill
492 				this.pay(bill);
493 
494 				// create the payment and send it out
495 				Payment payment = new Payment(bill.getReceiver(), bill
496 						.getSender(), bill.getInternalDemandID(), bill, bill
497 						.getPrice());
498 				this.sendContent(payment, 0.0);
499 			}
500 			return;
501 		}
502 		if (event.getType().equals(
503 				GameManufacturerInteractive.QUOTE_SENT_BY_CLIENT_EVENT))
504 		{
505 			SentQuoteData data = (SentQuoteData) event.getContent();
506 			try
507 			{
508 				SupplyChainActor sender = this.globalSupplyChainData
509 						.getSupplyChainActor(data.getSenderName());
510 				SupplyChainActor receiver = this.globalSupplyChainData
511 						.getSupplyChainActor(data.getReceiverName());
512 
513 				// find the rfq
514 				List rfqs = super.getGameContentStore().getContentList(
515 						data.getRfqData().getInternalDemandIdentifier(),
516 						RequestForQuote.class, false);
517 				RequestForQuote rfq = null;
518 				for (int i = 0; i < rfqs.size(); i++)
519 				{
520 					RequestForQuote result = (RequestForQuote) rfqs.get(i);
521 					if (result.getReceiver().getName().equalsIgnoreCase(
522 							sender.getName()))
523 					{
524 						rfq = result;
525 						break;
526 					}
527 				}
528 
529 				double proposedDeliveryDate = DateIntData.makeSimulationDate(
530 						data.getProposedDelivery(), this.simulator);
531 
532 				if (proposedDeliveryDate > this.simulator.getSimulatorTime())
533 				{
534 					double price = data.getPrice();
535 					// we add the transportation costs
536 					double weight = rfq.getAmount()
537 							* rfq.getProduct().getAverageUnitWeight();
538 
539 					// calculate the costs based on the the lat lon distance!
540 					double transportCosts = TransportMode.PLANE.transportCosts(
541 							super.latLonDistanceCalculator.getDistance(rfq
542 									.getSender(), rfq.getReceiver()), weight);
543 
544 					// add the transport costs to the price
545 					price += transportCosts;
546 
547 					Quote quote = new Quote(sender, receiver, data.getRfqData()
548 							.getInternalDemandIdentifier(), rfq, rfq
549 							.getProduct(), data.getAmount(), price,
550 							proposedDeliveryDate, TransportMode.PLANE);
551 					this.sendContent(quote, 0.0);
552 				} else
553 				{
554 					Logger
555 							.info(
556 									this,
557 									"notify",
558 									"GameManufacturerInteractive did not send Quote since the proposed delivery date has already been passed in the game. The accompanying rfq has been deleted.");
559 
560 					// delete the rfq from the erp sysem
561 					super.getGameContentStore().removeContent(rfq, false);
562 				}
563 			} catch (Exception exception)
564 			{
565 				Logger.severe(this, "notify", exception);
566 			}
567 			return;
568 		}
569 		if (event.getType().equals(
570 				GameManufacturerInteractive.RFQ_DELETED_BY_CLIENT_EVENT))
571 		{
572 			RFQData data = (RFQData) event.getContent();
573 			try
574 			{
575 				SupplyChainActor receiver = this.globalSupplyChainData
576 						.getSupplyChainActor(data.getReceiverName());
577 
578 				// find the rfq
579 				List rfqs = super.getGameContentStore().getContentList(
580 						data.getInternalDemandIdentifier(),
581 						RequestForQuote.class, false);
582 				RequestForQuote rfq = null;
583 				for (int i = 0; i < rfqs.size(); i++)
584 				{
585 					RequestForQuote result = (RequestForQuote) rfqs.get(i);
586 					if (result.getReceiver().getName().equalsIgnoreCase(
587 							receiver.getName()))
588 					{
589 						rfq = result;
590 						break;
591 					}
592 				}
593 
594 				// delete the rfq from the erp sysem
595 				super.getGameContentStore().removeContent(rfq, false);
596 			} catch (Exception exception)
597 			{
598 				Logger.severe(this, "notify", exception);
599 			}
600 			return;
601 
602 		}
603 		if (event
604 				.getType()
605 				.equals(
606 						GameManufacturerInteractive.ORDER_CONFIRMATION_SENT_BY_CLIENT_EVENT))
607 		{
608 			SentOrderConfirmationData data = (SentOrderConfirmationData) event
609 					.getContent();
610 			try
611 			{
612 				SupplyChainActor sender = this.globalSupplyChainData
613 						.getSupplyChainActor(data.getSenderName());
614 				SupplyChainActor receiver = this.globalSupplyChainData
615 						.getSupplyChainActor(data.getReceiverName());
616 				Order order = (Order) super.getGameContentStore()
617 						.getContentList(
618 								data.getOrderData().getInternalDemandID(),
619 								Order.class, false).get(0);
620 				if (order == null)
621 				{
622 					Logger.severe(this,
623 							"notify ORDER_CONFIRMATION_SENT_BY_CLIENT_EVENT",
624 							"order not found in ContentStore");
625 				} else
626 				{
627 					OrderConfirmation confirmation = new OrderConfirmation(
628 							sender, receiver, data.getOrderData()
629 									.getInternalDemandID(), order, data
630 									.getConfirmationStatus());
631 
632 					this.sendContent(confirmation, 0.0);
633 					InteractiveOrderHandlerStock handler = new InteractiveOrderHandlerStock(
634 							this, super.stock);
635 					handler.handleOrder(order);
636 
637 					// generate the customer statistics
638 					super.customerStatistics.handleContent(confirmation);
639 				}
640 				return;
641 			} catch (Exception exception)
642 			{
643 				Logger.severe(this, "notify", exception);
644 			}
645 			return;
646 		}
647 		if (event.getType().equals(SimulatorInterface.WARMUP_EVENT))
648 		{
649 			super.humanControlled = true;
650 			super.warmingUp = false;
651 			Logger
652 					.info(
653 							this,
654 							"init",
655 							"GameManufacturerInteractive: "
656 									+ this.name
657 									+ " set to interactive mode since the warm-up period has been finished");
658 			this.addInteractiveContentHandlers();
659 			return;
660 		}
661 		new ReceivedUnknownEventException(this, "notify", event.getType());
662 	}
663 
664 	/***
665 	 * pays the bill
666 	 * 
667 	 * @param bill the bill to pay
668 	 */
669 	public void pay(final Bill bill)
670 	{
671 		this.bankAccount.withdrawFromBalance(bill.getPrice());
672 	}
673 
674 	/***
675 	 * @see nl.tudelft.simulation.content.HandlerInterface#handleContent(java.io.Serializable)
676 	 */
677 	public boolean handleContent(final Serializable content)
678 	{
679 		try
680 		{
681 			if (super.humanControlled)
682 			{
683 				if (content instanceof Quote)
684 				{
685 					// handle with the special interactive quote handler
686 					if (super.interactiveQuoteHandler.handleContent(content))
687 					{
688 						// save content in the content store
689 						super.getContentStore().addContent((Content) content,
690 								false);
691 					}
692 					return true;
693 				}
694 			}
695 			return super.handleContent(content);
696 		} catch (Exception exception)
697 		{
698 			Logger.severe(this, "handleContent", exception);
699 			return false;
700 		}
701 	}
702 
703 	/***
704 	 * @see nl.tudelft.simulation.supplychain.actor.SupplyChainActor#sendContent(nl.tudelft.simulation.supplychain.content.Content,
705 	 *      double)
706 	 */
707 	public void sendContent(final Content content,
708 			final double administrativeDelay)
709 	{
710 		super.sendContent(content, administrativeDelay);
711 	}
712 
713 	/***
714 	 * @see org.gscg.gameactors.GameActorInteractiveInterface#getSingleUserInteractionLayer()
715 	 */
716 	public SingleUserInteractionLayerInterface getSingleUserInteractionLayer()
717 	{
718 		return this.singleUserInteractionLayer;
719 	}
720 
721 	/***
722 	 * @see org.gscg.gameactors.GameActorInteractiveInterface#setSingleUserInteractionLayer(org.gscg.singleuser.interactionlayer.SingleUserInteractionLayerInterface)
723 	 */
724 	public void setSingleUserInteractionLayer(
725 			final SingleUserInteractionLayerInterface singleUserInteractionLayer)
726 	{
727 		this.singleUserInteractionLayer = singleUserInteractionLayer;
728 		getGameContentStore().setSingleUserInteractionlayer(
729 				this.singleUserInteractionLayer);
730 
731 		try
732 		{
733 			for (int i = 0; i < this.eventsSentByClientArray.length; i++)
734 			{
735 				this.singleUserInteractionLayer.addListener(this,
736 						this.eventsSentByClientArray[i], false);
737 
738 				this.singleUserInteractionLayer
739 						.addEventTypeSentByClient(this.eventsSentByClientArray[i]);
740 
741 			}
742 
743 			// announce to update the stock
744 			// add the announce events
745 			singleUserInteractionLayer.addEventTypeToAnnounceList(
746 					StockInterface.STOCK_CHANGE_EVENT, this);
747 
748 			//
749 			// listeners
750 			//
751 			// subscribe for time change events on a daily basis these
752 			// events are used to update client side statistics on a daily basis
753 			this.singleUserInteractionLayer.addListener(this,
754 					GlobalRowOrColumnNumber.UPDATE_CURRENT_DAY);
755 		} catch (RemoteException remoteException)
756 		{
757 			Logger.severe(this, "<init>", remoteException);
758 		}
759 
760 		//
761 		// CUSTOMER STATISTICS
762 		//
763 		this.customerStatistics = new CustomerStatistics(this.simulator,
764 				this.singleUserInteractionLayer);
765 	}
766 
767 	/***
768 	 * adds computer-controlled interactive content handlers
769 	 */
770 	public void addComputerControlledContentHandlers()
771 	{
772 		super.addComputerControlledContentHandlers();
773 	}
774 
775 	/***
776 	 * adds interactive content handlers
777 	 */
778 	public void addInteractiveContentHandlers()
779 	{
780 		// remove all previus content handlers
781 		this.removeAllContentHandlers();
782 
783 		// look for our personal xml file with handler description
784 		URL url = URLResource.getResource("/" + this.name + "_interactive.xml");
785 		if (url == null)
786 		{
787 			url = URLResource
788 					.getResource("/manufacturer_interactive_default_handler.xml");
789 		}
790 		Logger
791 				.info(
792 						this,
793 						"addInteractiveContentHandlers",
794 						"Using: "
795 								+ url.toExternalForm()
796 								+ " as the file containing the configuration for the handlers.");
797 		try
798 		{
799 			// let's parse the xml file data to handlers
800 			Element rootElement = GameManufacturer.builder.build(url)
801 					.getRootElement();
802 			HandlerParser.parseAndAddHandler(this, rootElement);
803 		} catch (Exception exception)
804 		{
805 			Logger.severe(this, "addInteractiveContentHandlers", exception);
806 		}
807 	}
808 
809 	// private methods
810 	/***
811 	 * Method sendStockUpdateEvent fires an update for all the products
812 	 * available in the stock
813 	 */
814 	private void sendStockUpdateEvent()
815 	{
816 		for (Iterator i = this.stock.iterator(); i.hasNext();)
817 		{
818 			this.stock.sendStockUpdateEvent((Product) i.next());
819 		}
820 	}
821 
822 	/***
823 	 * writes a serializable method to stream
824 	 * 
825 	 * @param out the outputstream
826 	 * @throws IOException on IOException
827 	 */
828 	private synchronized void writeObject(final ObjectOutputStream out)
829 			throws IOException
830 	{
831 		out.defaultWriteObject();
832 	}
833 
834 	/***
835 	 * reads a serializable method from stream
836 	 * 
837 	 * @param in the inputstream
838 	 */
839 	private synchronized void readObject(final java.io.ObjectInputStream in)
840 	{
841 		try
842 		{
843 			in.defaultReadObject();
844 
845 			// check whether we are in an interactive mode or
846 			// computer-controlled mode
847 			// read properties
848 			Properties properties = new Properties();
849 			try
850 			{
851 				properties.load(URLResource
852 						.getResourceAsStream("/manufacturer.properties"));
853 			} catch (Exception exception)
854 			{
855 				exception.printStackTrace();
856 			}
857 			if (properties.getProperty(this.name) != null)
858 			{
859 				String result = properties.getProperty(this.name);
860 				if (result.equalsIgnoreCase("false"))
861 				{
862 					// only if there has been a change in the properties file
863 					// we put 'this' in the set, this set is evaluated by the
864 					// game management project (LoadGame.deserializeGame) after
865 					// all the actors have been deserialized, otherwise the
866 					// references between objects are not set yet
867 					if (super.humanControlled)
868 					{
869 						GameManufacturerInteractive.manufacturers.add(this);
870 						super.humanControlled = false;
871 						System.out
872 								.println("GameManufacturerInteractive: "
873 										+ this.name
874 										+ ": mode has been changed to computer-controlled mode");
875 					}
876 				} else if (result.equalsIgnoreCase("true"))
877 				{
878 					// only if there has been a change in the properties file
879 					// we put 'this' in the set, this set is evaluated by the
880 					// game management project (LoadGame.deserializeGame) after
881 					// all the actors have been deserialized, otherwise the
882 					// references between objects are not set yet
883 					// furthermore, the warm-up period must be finished
884 					if (!super.humanControlled && !super.warmingUp)
885 					{
886 						System.out
887 								.println("GameManufacturerInteractive: Deserializing: "
888 										+ this + " warm-up finished");
889 						GameManufacturerInteractive.manufacturers.add(this);
890 						super.humanControlled = true;
891 						System.out
892 								.println("GameManufacturerInteractive: "
893 										+ this.name
894 										+ ": mode has been changed to interactive mode");
895 					} else if (!super.humanControlled)
896 					{
897 						System.out.println("Deserializing: " + this
898 								+ " however warm-up not finished yet");
899 					}
900 				}
901 			} else
902 			{
903 				// no key found
904 				System.out
905 						.println("GameManufacturerInteractive: no key found for "
906 								+ this.name + " in properties.");
907 			}
908 		} catch (IOException exception)
909 		{
910 			Logger.severe(this, "readObject", exception);
911 		} catch (ClassNotFoundException exception)
912 		{
913 			Logger.severe(this, "readObject", exception);
914 		}
915 	}
916 }