1
2
3
4
5
6
7
8
9
10
11
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
143 Calendar calendar = Calendar.getInstance();
144 double simTime = this.owner.getSimulator().getSimulatorTime();
145
146
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
161 this.contentStore.addListener(this,
162 GameActorContentStore.EVENT_ORDERCOMMIT_RECEIVED, false);
163
164 try
165 {
166
167
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
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
208 int yearDiffence = calendar.get(Calendar.YEAR)
209 - startCalendar.get(Calendar.YEAR);
210
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
228 this.handlePerDay(data, calendar);
229
230
231 this.handlePerWeek(data, calendar);
232
233
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
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
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
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
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
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
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
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
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
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 }