View Javadoc

1   /*
2    * @(#)GameManufacturer.java Apr 25, 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.net.URL;
17  import java.rmi.RemoteException;
18  import java.util.Collection;
19  import java.util.HashMap;
20  import java.util.HashSet;
21  import java.util.Iterator;
22  import java.util.List;
23  import java.util.Map;
24  import java.util.Set;
25  
26  import javax.media.j3d.Bounds;
27  import javax.vecmath.Point2d;
28  import javax.vecmath.Point3d;
29  
30  import nl.tudelft.simulation.actor.messagehandlers.HandleAllMessages;
31  import nl.tudelft.simulation.actor.messagehandlers.MessageHandlerInterface;
32  import nl.tudelft.simulation.content.HandlerInterface;
33  import nl.tudelft.simulation.dsol.experiment.TimeUnit;
34  import nl.tudelft.simulation.dsol.experiment.TimeUnitInterface;
35  import nl.tudelft.simulation.dsol.simulators.AnimatorInterface;
36  import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
37  import nl.tudelft.simulation.dsol.statistics.charts.XYChart;
38  import nl.tudelft.simulation.jstats.distributions.DistConstant;
39  import nl.tudelft.simulation.jstats.distributions.DistContinuous;
40  import nl.tudelft.simulation.jstats.streams.StreamInterface;
41  import nl.tudelft.simulation.language.d3.BoundingBox;
42  import nl.tudelft.simulation.language.d3.DirectedPoint;
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.Content;
51  import nl.tudelft.simulation.supplychain.content.InternalDemand;
52  import nl.tudelft.simulation.supplychain.content.Order;
53  import nl.tudelft.simulation.supplychain.handlers.InternalDemandHandlerRFQ;
54  import nl.tudelft.simulation.supplychain.product.Product;
55  import nl.tudelft.simulation.supplychain.reference.Manufacturer;
56  import nl.tudelft.simulation.supplychain.roles.Role;
57  import nl.tudelft.simulation.supplychain.stock.Stock;
58  
59  import org.gscg.common.GameActorInterface;
60  import org.gscg.common.geo.CalculateLatLonDistance;
61  import org.gscg.experiment.HandlerParser;
62  import org.gscg.game.GameActorContentStore;
63  import org.gscg.game.GameGlobalData;
64  import org.gscg.gameleader.animation2D.GisActorAnimation;
65  import org.gscg.singleuser.handlers.InteractiveQuoteHandler;
66  import org.gscg.singleuser.interactionlayer.business.statistics.CustomerStatistics;
67  import org.gscg.singleuser.interactionlayer.dataobjects.DateIntData;
68  import org.gscg.singleuser.interactionlayer.dataobjects.content.RFQDataSuppliers;
69  import org.jdom.Element;
70  import org.jdom.input.SAXBuilder;
71  
72  /***
73   * The GameManufacturer extends a Manufacturer from the supplychain project and
74   * provides additional game-specific functionalities.
75   * <p>
76   * Copyright (c) 2003-2005 Delft University of Technology, Jaffalaan 5, 2628 BX
77   * Delft, the Netherlands. All rights reserved.
78   * 
79   * See for project information <a href="http://www.simulation.tudelft.nl/">
80   * www.simulation.tudelft.nl </a>.
81   * 
82   * The source code and binary code of this software is proprietary information
83   * of Delft University of Technology.
84   * 
85   * @author <a
86   *         href="http://www.tbm.tudelft.nl/webstaf/alexandv/index.htm">Alexander
87   *         Verbraeck </a>
88   * @version $Revision: 1.4 $ $Date: 2005/08/10 11:23:30 $
89   * @since 1.0.0 <br>
90   */
91  
92  public class GameManufacturer extends Manufacturer implements
93  		GameActorInterface, GameInteractiveActorRoleInterface
94  {
95  	/*** builder the xerces parser with validation turned on */
96  	protected static SAXBuilder builder = new SAXBuilder(
97  			"org.apache.xerces.parsers.SAXParser", true);
98  
99  	static
100 	{
101 		// turns on Schema Validation with Xerces
102 		GameManufacturer.builder.setFeature(
103 				"http://xml.org/sax/features/validation", true);
104 		GameManufacturer.builder.setFeature(
105 				"http://apache.org/xml/features/validation/schema", true);
106 
107 		// Let's find the XSD file
108 		String xsd = URLResource.getResource("/handler.xsd").toExternalForm();
109 		GameManufacturer.builder
110 				.setProperty(
111 						"http://apache.org/xml/properties/schema/external-schemaLocation",
112 						"http://www.simulation.tudelft.nl/dsol " + xsd);
113 	}
114 
115 	/*** the serial version uid */
116 	private static final long serialVersionUID = 12L;
117 
118 	/*** debug */
119 	private static final boolean DEBUG = false;
120 
121 	/*** the suppliers where the GameManufacturer buys */
122 	protected Trader[] suppliers;
123 
124 	/*** the global supply chain game data */
125 	protected GameGlobalData globalSupplyChainData = null;
126 
127 	/*** the customer statistisc for this player */
128 	protected CustomerStatistics customerStatistics = null;
129 
130 	/*** the special interactive quotehander */
131 	protected InteractiveQuoteHandler interactiveQuoteHandler = null;
132 
133 	/*** if true than we use any human intervention */
134 	protected boolean humanControlled = false;
135 
136 	/*** true for warming-up */
137 	protected boolean warmingUp = false;
138 
139 	/*** the lat lon distance calculator to use */
140 	protected CalculateLatLonDistance latLonDistanceCalculator = null;
141 
142 	/*** the location on the small map */
143 	private DirectedPoint smallMapLocation = new DirectedPoint();
144 
145 	/*** the animation used for serialization */
146 	private GisActorAnimation animation = null;
147 
148 
149 	/*** the map with product names and their suppliers */
150 	private Map productNameToSuppliers = null;
151 
152 	/***
153 	 * constructs a new GameManufacturer; used when dragging and dropping an
154 	 * actor
155 	 * 
156 	 * @param name the name
157 	 * @param simulator the simulator
158 	 * @param position the position
159 	 * @param bank the bank
160 	 */
161 	public GameManufacturer(final String name,
162 			final DEVSSimulatorInterface simulator, final Point3d position,
163 			final Bank bank)
164 	{
165 		super(name, simulator, position, new Role[]{}, bank);
166 		this.initAnimation();
167 	}
168 
169 	/***
170 	 * constructs a new GameManufacturer
171 	 * 
172 	 * @param name the name
173 	 * @param simulator the simulator
174 	 * @param position the position on the map
175 	 * @param roles the roles to implement
176 	 * @param bank the bank
177 	 * @param product the product
178 	 * @param amount the amount
179 	 * @param globalSupplyChainData the global supply chain data
180 	 * @param suppliers the suppliers
181 	 */
182 	public GameManufacturer(final String name,
183 			final DEVSSimulatorInterface simulator, final Point3d position,
184 			final Role[] roles, final Bank bank, final Product[] product,
185 			final Double[] amount, final GameGlobalData globalSupplyChainData,
186 			final Trader[] suppliers)
187 	{
188 		this(name, simulator, position, roles, bank, 0.0, product, amount,
189 				globalSupplyChainData, suppliers);
190 	}
191 
192 	/***
193 	 * constructs a new GameManufacturer
194 	 * 
195 	 * @param name the name
196 	 * @param simulator the simulator
197 	 * @param position the position on the map
198 	 * @param roles the roles to implement
199 	 * @param bank the bank
200 	 * @param initialBankAccount the initial bank account
201 	 * @param product the product
202 	 * @param amount the amount
203 	 * @param globalSupplyChainData the global supply chain data
204 	 * @param suppliers the suppliers
205 	 */
206 	public GameManufacturer(final String name,
207 			final DEVSSimulatorInterface simulator, final Point3d position,
208 			final Role[] roles, final Bank bank,
209 			final double initialBankAccount, final Product[] product,
210 			final Double[] amount, final GameGlobalData globalSupplyChainData,
211 			final Trader[] suppliers)
212 	{
213 		super(name, simulator, position, roles, bank, initialBankAccount);
214 		super.setContentStore(new GameActorContentStore(this, simulator));
215 		this.suppliers = (Trader[]) suppliers.clone();
216 		this.globalSupplyChainData = globalSupplyChainData;
217 		this.latLonDistanceCalculator = new CalculateLatLonDistance();
218 
219 		// make a map which keeps track which manufacturer supplies what
220 		// products
221 		this.productNameToSuppliers = new HashMap();
222 		for (int i = 0; i < this.suppliers.length; i++)
223 		{
224 			Trader trader = this.suppliers[i];
225 			List productsOnStock = trader.getProductsOnStock();
226 			for (int ii = 0; ii < productsOnStock.size(); ii++)
227 			{
228 				Product productOnStock = (Product) productsOnStock.get(ii);
229 				if (GameManufacturer.DEBUG)
230 				{
231 					System.out
232 							.println("DEBUG -- GameManufacturer: <init> : supplier: "
233 									+ trader.getName()
234 									+ "has product: "
235 									+ productOnStock.getName() + " on stock");
236 				}
237 				if (!this.productNameToSuppliers.containsKey(productOnStock
238 						.getName()))
239 				{
240 					this.productNameToSuppliers.put(productOnStock.getName(),
241 							new HashSet());
242 				}
243 				Set set = (Set) this.productNameToSuppliers.get(productOnStock
244 						.getName());
245 				set.add(trader);
246 				this.productNameToSuppliers.put(productOnStock.getName(), set);
247 			}
248 		}
249 
250 		// give the manufacturer some stock
251 		Stock stock = new Stock(this);
252 		for (int i = 0; i < product.length; i++)
253 		{
254 			stock.addStock(product[i], amount[i].doubleValue(), amount[i]
255 					.doubleValue()
256 					* product[i].getUnitMarketPrice());
257 		}
258 		super.setInitialStock(stock);
259 
260 		// add the devices
261 		this.addDevices();
262 
263 		// We initialize GameManufacturer
264 		this.init();
265 
266 		// may be initialized earlier during modeling of supply chain game
267 		if (this.animation == null)
268 		{
269 			this.initAnimation();
270 		}
271 	}
272 
273 	/***
274 	 * Initializes the animation.
275 	 */
276 	private void initAnimation()
277 	{
278 		// Let's give PCManufacturer its corresponding image
279 		this.animation = new GisActorAnimation(
280 				this,
281 				this.simulator,
282 				GameManufacturer.class
283 						.getResource("/nl/tudelft/simulation/supplychain/images/Manufacturer.gif"));
284 	}
285 
286 	/***
287 	 * Method init
288 	 */
289 	protected void init()
290 	{
291 		this.addComputerControlledContentHandlers();
292 		try
293 		{
294 			//
295 			// CHARTS
296 			//
297 			if (this.simulator instanceof AnimatorInterface)
298 			{
299 				XYChart bankChart = new XYChart(this.simulator, "BankAccount "
300 						+ this.name);
301 				bankChart.add("bank account", this.bankAccount,
302 						BankAccount.BANK_ACCOUNT_CHANGED_EVENT);
303 			}
304 		} catch (RemoteException remoteException)
305 		{
306 			Logger.severe(this, "init", remoteException);
307 		}
308 
309 		if (GameManufacturer.DEBUG)
310 		{
311 			System.out.println("GameManufacturer: player: " + this.name
312 					+ " initialized.");
313 		}
314 	}
315 
316 	/***
317 	 * adds computer-controlled interactive content handlers
318 	 */
319 	protected void addComputerControlledContentHandlers()
320 	{
321 		// remove all previous content handlers
322 		this.removeAllContentHandlers();
323 
324 		// look for our personal xml file with handler description
325 		URL url = URLResource.getResource("/" + this.name
326 				+ "_computer_controlled.xml");
327 		url=null;
328 		if (url == null)
329 		{
330 			url = URLResource.getResource("/manufacturer_default_handler.xml");
331 		}
332 		Logger
333 				.info(
334 						this,
335 						"addComputerControlledContentHandlers",
336 						"Using: "
337 								+ url.toExternalForm()
338 								+ " as the file containing the configuration for the handlers.");
339 		try
340 		{
341 			// let's parse the xml file data to handlers
342 			Element rootElement = GameManufacturer.builder.build(url)
343 					.getRootElement();
344 			HandlerParser.parseAndAddHandler(this, rootElement);
345 		} catch (Exception exception)
346 		{
347 			Logger.severe(this, "addComputerControlledContentHandlers",
348 					exception);
349 		}
350 
351 		// after all handlers have been added we check whether there is an
352 		// internal demand handler for rfq's
353 		if (this.contentHandlers.containsKey(InternalDemand.class))
354 		{
355 			Set resolvedHandlers = (Set) this.contentHandlers
356 					.get(InternalDemand.class);
357 			for (Iterator resolvedHandlersIterator = resolvedHandlers
358 					.iterator(); resolvedHandlersIterator.hasNext();)
359 			{
360 				HandlerInterface handler = (HandlerInterface) resolvedHandlersIterator
361 						.next();
362 
363 				if (handler instanceof InternalDemandHandlerRFQ)
364 				{
365 					Iterator productIterator = this.getStock().iterator();
366 					while (productIterator.hasNext())
367 					{
368 						Product product = (Product) productIterator.next();
369 						Set suppliers = (Set) this.getProductNameToSuppliers()
370 								.get(product.getName());
371 
372 						if (suppliers != null)
373 						{
374 							for (Iterator supplierIterator = suppliers
375 									.iterator(); supplierIterator.hasNext();)
376 							{
377 								((InternalDemandHandlerRFQ) handler)
378 										.addSupplier(product,
379 												(Trader) supplierIterator
380 														.next());
381 								if (GameManufacturer.DEBUG)
382 								{
383 
384 									System.out
385 											.println("DEBUG -- GameManufacturer: addComputerControlledContentHandlers : added supplier to internaldemand handler rfq");
386 								}
387 							}
388 						} else
389 						{
390 							Logger.warning(this,
391 									"addComputerControlledContentHandlers",
392 									"No suppliers found for product: "
393 											+ product);
394 						}
395 					}
396 				}
397 			}
398 		}
399 	}
400 
401 	/***
402 	 * @see nl.tudelft.simulation.supplychain.actor.SupplyChainActor#sendContent(nl.tudelft.simulation.supplychain.content.Content, double)
403 	 */
404 	public void sendContent(final Content content,
405 			final double administrativeDelay)
406 	{
407 		//TODO is this method still needed?
408 		// we snoop the orders for statististical analysis
409 		if (content instanceof Order)
410 		{
411 			// let's send to the statistics
412 		}
413 		super.sendContent(content, administrativeDelay);
414 	}
415 
416 	/***
417 	 * @see nl.tudelft.simulation.dsol.animation.LocatableInterface#getBounds()
418 	 */
419 	public Bounds getBounds()
420 	{
421 		return new BoundingBox(1.0, 1.0, 0.0);
422 	}
423 
424 	/***
425 	 * @see org.gscg.gameactors.GameInteractiveActorRoleInterface#getGameContentStore()
426 	 */
427 	public GameActorContentStore getGameContentStore()
428 	{
429 		return (GameActorContentStore) super.getContentStore();
430 	}
431 
432 	/***
433 	 * Method getContent returns all data objects of type contentClass
434 	 * 
435 	 * @param contentClass the content class to look for
436 	 * @param sent indicates whether the content is sent or received
437 	 * @param productName the name of the product
438 	 */
439 	public void fireAllContentData(final Class contentClass,
440 			final boolean sent, final String productName)
441 	{
442 		getGameContentStore().fireAllProductContentData(contentClass, sent,
443 				productName);
444 	}
445 
446 	/***
447 	 * Method fireAllNumberData.
448 	 */
449 	public void fireAllNumberData()
450 	{
451 		Collection products = this.globalSupplyChainData.getProducts();
452 		Iterator prodIter = products.iterator();
453 		while (prodIter.hasNext())
454 		{
455 			Product product = (Product) prodIter.next();
456 			getGameContentStore().fireAllProductNumberData(product.getName());
457 		}
458 	}
459 
460 	/***
461 	 * @param productName the product we want
462 	 * @return an initialized RFQData object with potential suppliers
463 	 */
464 	public RFQDataSuppliers getInitialRFQData(final String productName)
465 	{
466 		double day = 0;
467 		try
468 		{
469 			day = TimeUnit.convert(1, TimeUnitInterface.DAY, this.simulator);
470 		} catch (Exception exception)
471 		{
472 			Logger.severe(this, "getInitialRFQData", "TimeUnit.convert failed");
473 		}
474 
475 		// TODO the desired earliest and delivery date should not be hard-coded
476 		double earliestDeliveryDate = this.getSimulatorTime() + 14 * day;
477 		double defaultAmount = 100;
478 		double latestDeliveryDate = earliestDeliveryDate + 7.0 * day;
479 
480 		String[] supplierNames = new String[0];
481 		String[] supplierNickNames = new String[0];
482 		Point2d ownLocation = new Point2d(this.getLocation().x, this
483 				.getLocation().y);
484 		Point2d[] suppliersLocations = new Point2d[0];
485 
486 		Set suppliers = (Set) this.productNameToSuppliers.get(productName);
487 		if (suppliers != null)
488 		{
489 			supplierNames = new String[suppliers.size()];
490 			supplierNickNames = new String[suppliers.size()];
491 			suppliersLocations = new Point2d[suppliers.size()];
492 
493 			int counter = 0;
494 			for (Iterator it = suppliers.iterator(); it.hasNext();)
495 			{
496 				Trader trader = (Trader) it.next();
497 				supplierNames[counter] = trader.getName();
498 				supplierNickNames[counter] = trader.getLocationDescription();
499 				suppliersLocations[counter] = new Point2d(
500 						trader.getLocation().x, trader.getLocation().y);
501 				counter++;
502 			}
503 		}
504 		return new RFQDataSuppliers(this.name, supplierNames,
505 				supplierNickNames, DateIntData.makeDateIntData(
506 						earliestDeliveryDate, this.simulator), DateIntData
507 						.makeDateIntData(latestDeliveryDate, this.simulator),
508 				defaultAmount, productName, ownLocation, suppliersLocations);
509 	}
510 
511 	/***
512 	 * @return Returns the smallMapLocation.
513 	 */
514 	public DirectedPoint getSmallMapLocation()
515 	{
516 		return this.smallMapLocation;
517 	}
518 
519 	/***
520 	 * @param smallMapLocation The smallMapLocation to set.
521 	 */
522 	public void setSmallMapLocation(final DirectedPoint smallMapLocation)
523 	{
524 		this.smallMapLocation = smallMapLocation;
525 	}
526 
527 	/***
528 	 * @see nl.tudelft.simulation.actor.ActorInterface#getName()
529 	 */
530 	public String getName()
531 	{
532 		return this.name;
533 	}
534 
535 	/***
536 	 * @return Returns the animation
537 	 */
538 	protected GisActorAnimation getAnimation()
539 	{
540 		return this.animation;
541 	}
542 
543 	/***
544 	 * @see nl.tudelft.simulation.supplychain.actor.SupplyChainActor#calculateDistance(nl.tudelft.simulation.supplychain.actor.SupplyChainActor)
545 	 */
546 	public double calculateDistance(final SupplyChainActor actor)
547 	{
548 		return new CalculateLatLonDistance().getDistance(new Point2d(
549 				this.location.x, this.location.y), new Point2d(actor
550 				.getLocation().x, actor.getLocation().y));
551 	}
552 
553 	/***
554 	 * @return Returns the productNameToSuppliers.
555 	 */
556 	public Map getProductNameToSuppliers()
557 	{
558 		return this.productNameToSuppliers;
559 	}
560 
561 	/***
562 	 * @return true if human controlled, false otherwise
563 	 */
564 	public boolean isHumanControlled()
565 	{
566 		return this.humanControlled;
567 	}
568 
569 	/***
570 	 * sets the interactive quote handler
571 	 * 
572 	 * @param interactiveQuoteHandler the interactive quote handler to set
573 	 */
574 	public void setInteractiveQuoteHandler(
575 			final InteractiveQuoteHandler interactiveQuoteHandler)
576 	{
577 		this.interactiveQuoteHandler = interactiveQuoteHandler;
578 	}
579 
580 	/***
581 	 * removes all the content handlers
582 	 */
583 	protected void removeAllContentHandlers()
584 	{
585 		super.contentHandlers.clear();
586 	}
587 
588 	protected void addDevices()
589 	{
590 		try
591 		{
592 			StreamInterface stream = this.simulator.getReplication().getStream(
593 					"default");
594 			double hour = TimeUnit.convert(1.0, TimeUnitInterface.HOUR,
595 					this.simulator);
596 			DistContinuous hourDist = new DistConstant(stream, hour);
597 			//
598 			// give the actor a fax device which is checked every hour
599 			//
600 			FaxDevice fax = new FaxDevice("GameManufacturerFax", this.simulator);
601 			addSendingDevice(fax);
602 			MessageHandlerInterface secretary = new HandleAllMessages(this);
603 			addReceivingDevice(fax, secretary, hourDist);
604 		} catch (RemoteException remoteException)
605 		{
606 			Logger.severe(this, "addDevices", remoteException);
607 		}
608 	}
609 }