View Javadoc

1   /*
2    * ConfirmedOrderHandler.java Created @ Jul 12, 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.singleuser.handlers;
15  
16  import java.rmi.RemoteException;
17  import java.util.Calendar;
18  import java.util.Collections;
19  import java.util.HashMap;
20  import java.util.Iterator;
21  import java.util.Map;
22  
23  import nl.tudelft.simulation.dsol.experiment.TimeUnit;
24  import nl.tudelft.simulation.dsol.experiment.TimeUnitInterface;
25  import nl.tudelft.simulation.event.Event;
26  import nl.tudelft.simulation.event.EventInterface;
27  import nl.tudelft.simulation.event.EventListenerInterface;
28  import nl.tudelft.simulation.event.EventProducer;
29  import nl.tudelft.simulation.event.EventType;
30  import nl.tudelft.simulation.logger.Logger;
31  
32  import org.gscg.common.gui.exceptions.ReceivedUnknownEventException;
33  import org.gscg.common.interactionlayer.AnnounceInterface;
34  import org.gscg.common.interactionlayer.timecontrol.GlobalRowOrColumnNumber;
35  import org.gscg.game.GameActorContentStore;
36  import org.gscg.gameactors.GameInteractiveActorRoleInterface;
37  import org.gscg.singleuser.interactionlayer.SingleUserInteractionLayerInterface;
38  import org.gscg.singleuser.interactionlayer.dataobjects.CommittedOrderDayData;
39  import org.gscg.singleuser.interactionlayer.dataobjects.CommittedOrderMonthData;
40  import org.gscg.singleuser.interactionlayer.dataobjects.CommittedOrderWeekData;
41  import org.gscg.singleuser.interactionlayer.dataobjects.content.OrderConfirmationData;
42  
43  /***
44   * Updates the number of orders based on the day in the interactive simulation.
45   * Whenever an order is received or is handled, accordingly the number is
46   * updated at the client side gui. This handler is used by the PURCHASE PANEL of
47   * a client-side gui.
48   * <p>
49   * Copyright (c) 2003-2005 Delft University of Technology, Jaffalaan 5, 2628 BX
50   * Delft, the Netherlands. All rights reserved.
51   * 
52   * See for project information <a href="http://www.simulation.tudelft.nl/">
53   * www.simulation.tudelft.nl </a>.
54   * 
55   * The source code and binary code of this software is proprietary information
56   * of Delft University of Technology.
57   * 
58   * @author <a
59   *         href="http://www.tbm.tudelft.nl/webstaf/stijnh/index.htm">Stijn-Pieter
60   *         van Houten </a>
61   * @version $Revision: 1.3 $ $Date: 2005/08/09 15:43:41 $
62   * @since 1.0.0
63   */
64  public class ConfirmedOrderHandler extends EventProducer implements
65  		EventListenerInterface, AnnounceInterface
66  {
67  	/*** the serial version uid */
68  	private static final long serialVersionUID = 11L;
69  
70  	/*** the event type for the amount of orders per product per day */
71  	public static final EventType EVENT_NUMBER_ORDERCONFIRMED_RECEIVED_DAY = new EventType(
72  			"EVENT_NUMBER_ORDERCONFIRMED_RECEIVED_DAY");
73  
74  	/*** the event type for the amount of orders per product per week */
75  	public static final EventType EVENT_NUMBER_ORDERCONFIRMED_RECEIVED_WEEK = new EventType(
76  			"EVENT_NUMBER_ORDERCONFIRMED_RECEIVED_WEEK");
77  
78  	/*** the event type for the amount of orders per product per month */
79  	public static final EventType EVENT_NUMBER_ORDERCONFIRMED_RECEIVED_MONTH = new EventType(
80  			"EVENT_NUMBER_ORDERCONFIRMED_RECEIVED_MONTH");
81  
82  	/*** the event type to update all the order commitments */
83  	public static final EventType EVENT_NUMBER_ORDERCONFIRMED_RECEIVED_UPDATE = new EventType(
84  			"EVENT_NUMBER_ORDERCONFIRMED_RECEIVED_UPDATE");
85  
86  	/*** the owner */
87  	private SingleUserInteractionLayerInterface owner = null;
88  
89  	/*** the content store */
90  	private GameActorContentStore contentStore = null;
91  
92  	/*** the product map per day */
93  	private Map productDayMap = new HashMap();
94  
95  	/*** the product map per week */
96  	private Map productWeekMap = new HashMap();
97  
98  	/*** the product map per month */
99  	private Map productMonthMap = new HashMap();
100 
101 	/*** indicates the current day */
102 	private int currentDay = 0;
103 
104 	/*** indicates the current week */
105 	private int currentWeek = 0;
106 
107 	/*** indicates the current month */
108 	private int currentMonth = 0;
109 
110 	/*** used when the runlength of a simulation run spans two calendar years */
111 	private int additionalDays = 0;
112 
113 	/*** used when the runlength of a simulation run spans two calendar years */
114 	private int additionalWeeks = 0;
115 
116 	/*** used when the runlength of a simulation run spans two calendar years */
117 	private int additionalMonths = 0;
118 
119 	/*** the events to subscribe the owner to */
120 	private EventType[] eventsToSubscribeOwnerTo = {
121 			ConfirmedOrderHandler.EVENT_NUMBER_ORDERCONFIRMED_RECEIVED_DAY,
122 			ConfirmedOrderHandler.EVENT_NUMBER_ORDERCONFIRMED_RECEIVED_WEEK,
123 			ConfirmedOrderHandler.EVENT_NUMBER_ORDERCONFIRMED_RECEIVED_MONTH};
124 
125 	/*** the history of the fired events */
126 	private Map history = Collections.synchronizedMap(new HashMap());
127 
128 	/***
129 	 * constructs a new ConfirmedOrderHandler
130 	 * 
131 	 * @param owner the owner
132 	 */
133 	public ConfirmedOrderHandler(final SingleUserInteractionLayerInterface owner)
134 	{
135 		super();
136 		this.owner = owner;
137 		try
138 		{
139 			this.contentStore = ((GameInteractiveActorRoleInterface) this.owner
140 					.getOwner()).getGameContentStore();
141 
142 			// set the week and year
143 			Calendar calendar = Calendar.getInstance();
144 			double simTime = this.owner.getSimulator().getSimulatorTime();
145 
146 			// convert the simtime
147 			double convertedTime = TimeUnit.convert(simTime, this.owner
148 					.getSimulator().getReplication().getRunControl()
149 					.getTreatment().getTimeUnit(),
150 					TimeUnitInterface.MILLISECOND);
151 
152 			double startTime = this.owner.getSimulator().getReplication()
153 					.getRunControl().getTreatment().getStartTime();
154 			calendar.setTimeInMillis((long) (convertedTime + startTime));
155 		} catch (RemoteException remoteException)
156 		{
157 			Logger.severe(this, "ConfirmedOrderHandler", remoteException);
158 		}
159 
160 		// add requestForQuotes
161 		this.contentStore.addListener(this,
162 				GameActorContentStore.EVENT_ORDERCOMMIT_RECEIVED, false);
163 
164 		try
165 		{
166 			// subscribe the owner to events fired from this object
167 			// also add the necessary announce events
168 			for (int i = 0; i < this.eventsToSubscribeOwnerTo.length; i++)
169 			{
170 				this.addListener(this.owner, this.eventsToSubscribeOwnerTo[i]);
171 				this.owner.addEventType(this.eventsToSubscribeOwnerTo[i]);
172 			}
173 
174 			this.owner
175 					.addEventTypeToAnnounceList(
176 							ConfirmedOrderHandler.EVENT_NUMBER_ORDERCONFIRMED_RECEIVED_UPDATE,
177 							this);
178 		} catch (RemoteException remoteException)
179 		{
180 			Logger.severe(this, "<init>", remoteException);
181 		}
182 
183 		// initialize the history
184 		this.history.put(new String("day"), new HashMap());
185 		this.history.put(new String("week"), new HashMap());
186 		this.history.put(new String("month"), new HashMap());
187 	}
188 
189 	/***
190 	 * @see nl.tudelft.simulation.event.EventListenerInterface#notify(nl.tudelft.simulation.event.EventInterface)
191 	 */
192 	public void notify(final EventInterface event) throws RemoteException
193 	{
194 		if (event.getType().equals(
195 				GameActorContentStore.EVENT_ORDERCOMMIT_RECEIVED))
196 		{
197 			OrderConfirmationData data = (OrderConfirmationData) event
198 					.getContent();
199 			Calendar calendar = Calendar.getInstance();
200 			calendar.set(data.getProposedDelivery().getYear(), data
201 					.getProposedDelivery().getMonth(), data
202 					.getProposedDelivery().getDay());
203 			Calendar startCalendar = Calendar.getInstance();
204 			startCalendar.setTimeInMillis(GlobalRowOrColumnNumber
205 					.getStartTime());
206 
207 			// calculcate difference between startCalendar and order date
208 			int yearDiffence = calendar.get(Calendar.YEAR)
209 					- startCalendar.get(Calendar.YEAR);
210 			// reset old additional values
211 			this.additionalDays = 0;
212 			this.additionalWeeks = 0;
213 			this.additionalMonths = 0;
214 
215 			while (yearDiffence > 0)
216 			{
217 				startCalendar.set(Calendar.YEAR, startCalendar
218 						.get(Calendar.YEAR) + 1);
219 				this.additionalDays = startCalendar
220 						.getActualMaximum(Calendar.DAY_OF_YEAR);
221 				this.additionalWeeks += 52;
222 				this.additionalMonths += 12;
223 
224 				yearDiffence--;
225 			}
226 
227 			// handle per day
228 			this.handlePerDay(data, calendar);
229 
230 			// handle per week
231 			this.handlePerWeek(data, calendar);
232 
233 			// handle per month
234 			this.handlePerMonth(data, calendar);
235 
236 			return;
237 		}
238 		new ReceivedUnknownEventException(this, "notify", event.getType());
239 	}
240 
241 	/***
242 	 * handles an orderconfirmation per day
243 	 * 
244 	 * @param data the data
245 	 * @param calendar the calendar
246 	 */
247 	private void handlePerDay(final OrderConfirmationData data,
248 			final Calendar calendar)
249 	{
250 		int day = calendar.get(Calendar.DAY_OF_YEAR);
251 
252 		// we compensate extra years
253 		day += this.additionalDays;
254 
255 		if (this.currentDay != day)
256 		{
257 			this.currentDay = day;
258 		}
259 
260 		double value = Double.NaN;
261 		if (!this.productDayMap.containsKey(data.getProductName()))
262 		{
263 			Map map = new HashMap();
264 			map.put("" + this.currentDay, new Double(data.getAmount()));
265 			this.productDayMap.put(data.getProductName(), map);
266 			value = data.getAmount();
267 		} else
268 		{
269 			Map map = (Map) this.productDayMap.get(data.getProductName());
270 
271 			if (map.containsKey("" + this.currentDay))
272 			{
273 				value = ((Double) map.get("" + this.currentDay)).doubleValue();
274 				value += data.getAmount();
275 				map.put("" + this.currentDay, new Double(value));
276 			} else
277 			{
278 				value = data.getAmount();
279 				map.put("" + this.currentDay, new Double(value));
280 			}
281 		}
282 
283 		// lookup table row
284 		try
285 		{
286 			int rowNumber = 0;
287 			try
288 			{
289 				rowNumber = ((Integer) GlobalRowOrColumnNumber
290 						.getDayNumberTableRowNumber().get(new Integer(day)))
291 						.intValue();
292 			} catch (NullPointerException nullPointerException)
293 			{
294 				if (this.dateWithinRange(data))
295 				{
296 					Logger.severe(this, "handlePerDay",
297 							"Date should be in range, but no row found.");
298 				} else
299 				{
300 					// set the scope outside the game
301 					rowNumber = GlobalRowOrColumnNumber.getDayHeaderValues()
302 							.size() + 10;
303 				}
304 			}
305 
306 			Event event = new Event(
307 					ConfirmedOrderHandler.EVENT_NUMBER_ORDERCONFIRMED_RECEIVED_DAY,
308 					this, new CommittedOrderDayData(data.getProductName(),
309 							rowNumber, value));
310 			this.fireEvent(event);
311 			this.addToHistory("day", day, data.getProductName(), event);
312 		} catch (Exception exception)
313 		{
314 			Logger.severe(this, "handlePerDay", exception);
315 		}
316 	}
317 
318 	/***
319 	 * handles an orderconfirmation per week
320 	 * 
321 	 * @param data the data
322 	 * @param calendar the calendar
323 	 */
324 	private void handlePerWeek(final OrderConfirmationData data,
325 			final Calendar calendar)
326 	{
327 		int week = (calendar.get(Calendar.WEEK_OF_YEAR));
328 
329 		// we compensate extra years
330 		week += this.additionalWeeks;
331 
332 		if (this.currentWeek != week)
333 		{
334 			this.currentWeek = week;
335 		}
336 
337 		double value = Double.NaN;
338 		if (!this.productWeekMap.containsKey(data.getProductName()))
339 		{
340 			Map map = new HashMap();
341 			map.put("" + this.currentWeek, new Double(data.getAmount()));
342 			this.productWeekMap.put(data.getProductName(), map);
343 			value = data.getAmount();
344 		} else
345 		{
346 			Map map = (Map) this.productWeekMap.get(data.getProductName());
347 
348 			if (map.containsKey("" + this.currentWeek))
349 			{
350 				value = ((Double) map.get("" + this.currentWeek)).doubleValue();
351 				value += data.getAmount();
352 				map.put("" + this.currentWeek, new Double(value));
353 			} else
354 			{
355 				value = data.getAmount();
356 				map.put("" + this.currentWeek, new Double(value));
357 			}
358 		}
359 
360 		// lookup table row
361 		try
362 		{
363 			int rowNumber = 0;
364 			try
365 			{
366 				rowNumber = ((Integer) GlobalRowOrColumnNumber
367 						.getWeekNumberTableRowNumber().get(new Integer(week)))
368 						.intValue();
369 			} catch (NullPointerException nullPointerException)
370 			{
371 				if (this.dateWithinRange(data))
372 				{
373 					Logger.severe(this, "handlePerWeek",
374 							"Date should be in range, but no row found.");
375 				} else
376 				{
377 					// set the scope outside the game
378 					rowNumber = GlobalRowOrColumnNumber.getWeekHeaderValues()
379 							.size() + 10;
380 				}
381 			}
382 			Event event = new Event(
383 					ConfirmedOrderHandler.EVENT_NUMBER_ORDERCONFIRMED_RECEIVED_WEEK,
384 					this, new CommittedOrderWeekData(data.getProductName(),
385 							rowNumber, value));
386 			this.fireEvent(event);
387 			this.addToHistory("week", week, data.getProductName(), event);
388 		} catch (Exception exception)
389 		{
390 			Logger.severe(this, "handlePerWeek", exception);
391 		}
392 	}
393 
394 	/***
395 	 * handles an orderconfirmation per month
396 	 * 
397 	 * @param data the data
398 	 * @param calendar the calendar
399 	 */
400 	private void handlePerMonth(final OrderConfirmationData data,
401 			final Calendar calendar)
402 	{
403 		int month = calendar.get(Calendar.MONTH);
404 
405 		// we compensate extra years
406 		month += this.additionalMonths;
407 
408 		if (this.currentMonth != month)
409 		{
410 			this.currentMonth = month;
411 		}
412 
413 		double value = Double.NaN;
414 		if (!this.productMonthMap.containsKey(data.getProductName()))
415 		{
416 			Map map = new HashMap();
417 			map.put("" + this.currentMonth, new Double(data.getAmount()));
418 			this.productMonthMap.put(data.getProductName(), map);
419 			value = data.getAmount();
420 		} else
421 		{
422 			Map map = (Map) this.productMonthMap.get(data.getProductName());
423 
424 			if (map.containsKey("" + this.currentMonth))
425 			{
426 				value = ((Double) map.get("" + this.currentMonth))
427 						.doubleValue();
428 				value += data.getAmount();
429 				map.put("" + this.currentMonth, new Double(value));
430 			} else
431 			{
432 				value = data.getAmount();
433 				map.put("" + this.currentMonth, new Double(value));
434 			}
435 		}
436 
437 		// lookup table row
438 		try
439 		{
440 			int rowNumber = 0;
441 			try
442 			{
443 				rowNumber = ((Integer) GlobalRowOrColumnNumber
444 						.getMonthNumberTableRowNumber().get(new Integer(month)))
445 						.intValue();
446 			} catch (NullPointerException nullPointerException)
447 			{
448 				if (this.dateWithinRange(data))
449 				{
450 					Logger.severe(this, "handlePerMonth",
451 							"Date should be in range, but no row found.");
452 				} else
453 				{
454 					// set the scope outside the game
455 					rowNumber = GlobalRowOrColumnNumber.getMonthHeaderValues()
456 							.size() + 10;
457 				}
458 			}
459 			Event event = new Event(
460 					ConfirmedOrderHandler.EVENT_NUMBER_ORDERCONFIRMED_RECEIVED_MONTH,
461 					this, new CommittedOrderMonthData(data.getProductName(),
462 							rowNumber, value));
463 			this.fireEvent(event);
464 			this.addToHistory("month", month, data.getProductName(), event);
465 		} catch (Exception exception)
466 		{
467 			Logger.severe(this, "handlePerMonth", exception);
468 		}
469 	}
470 
471 	/***
472 	 * @see org.gscg.common.interactionlayer.AnnounceInterface#announce(nl.tudelft.simulation.event.EventType,
473 	 *      boolean)
474 	 */
475 	public void announce(final EventType eventType, final boolean announce)
476 	{
477 		if (announce)
478 		{
479 			for (Iterator i = this.history.keySet().iterator(); i.hasNext();)
480 			{
481 				HashMap dateMap = (HashMap) this.history.get(i.next());
482 				for (Iterator ii = dateMap.keySet().iterator(); ii.hasNext();)
483 				{
484 					HashMap productMap = (HashMap) dateMap.get(ii.next());
485 					for (Iterator iii = productMap.keySet().iterator(); iii
486 							.hasNext();)
487 					{
488 						try
489 						{
490 							this.owner
491 									.notifyAnnounced((EventInterface) productMap
492 											.get(iii.next()));
493 						} catch (RemoteException remoteException)
494 						{
495 							Logger.severe(this, "announce", remoteException);
496 						}
497 
498 					}
499 				}
500 			}
501 		}
502 	}
503 
504 	/***
505 	 * Method addToHistory.
506 	 * 
507 	 * @param dateType a string reflecting the date type, e.g. day, week or
508 	 *        month
509 	 * @param key the key, i.e. the number of the day, week or month
510 	 * @param productName the name of the product the confirmed order is
511 	 *        received for
512 	 * @param event the event to store in the history
513 	 */
514 	private void addToHistory(final String dateType, final int key,
515 			final String productName, final Event event)
516 	{
517 		HashMap dateMap = (HashMap) this.history.get(dateType);
518 		if (dateMap == null)
519 		{
520 			dateMap = new HashMap();
521 			this.history.put(dateType, dateMap);
522 		}
523 
524 		HashMap productMap = (HashMap) dateMap.get(productName);
525 		if (productMap == null)
526 		{
527 			productMap = new HashMap();
528 			dateMap.put(productName, productMap);
529 		}
530 		productMap.put(new Integer(key), event);
531 	}
532 
533 	/***
534 	 * calculates whether a date is within range
535 	 * 
536 	 * @param data the data
537 	 * @return returns false if the date is not within range, true otherwise
538 	 */
539 	private boolean dateWithinRange(final OrderConfirmationData data)
540 	{
541 		Calendar startCalendar = Calendar.getInstance();
542 		startCalendar.setTimeInMillis(GlobalRowOrColumnNumber.getStartTime());
543 
544 		Calendar endCalendar = Calendar.getInstance();
545 		endCalendar.set(data.getProposedDelivery().getYear(), data
546 				.getProposedDelivery().getMonth(), data.getProposedDelivery()
547 				.getDay());
548 
549 		long runLength = GlobalRowOrColumnNumber.getNumberOfDays()
550 				* TimeUnitInterface.DAY.getValue();
551 		if ((endCalendar.getTimeInMillis() - startCalendar.getTimeInMillis()) > runLength)
552 		{
553 			return false;
554 		}
555 		return true;
556 
557 	}
558 }