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 committed to a customer the number is updated at the
46 * client side gui. This handler is used by the SALES PANEL of a client-side
47 * 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 CommittedOrderHandler 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_ORDERCOMMIT_SENT_DAY = new EventType(
72 "EVENT_NUMBER_ORDERCOMMIT_SENT_DAY");
73
74 /*** the event type for the amount of orders per product per week */
75 public static final EventType EVENT_NUMBER_ORDERCOMMIT_SENT_WEEK = new EventType(
76 "EVENT_NUMBER_ORDERCOMMIT_SENT_WEEK");
77
78 /*** the event type for the amount of orders per product per month */
79 public static final EventType EVENT_NUMBER_ORDERCOMMIT_SENT_MONTH = new EventType(
80 "EVENT_NUMBER_ORDERCOMMIT_SENT_MONTH");
81
82 /*** the event type to update all the order commitments */
83 public static final EventType EVENT_NUMBER_ORDERCOMMIT_SENT_UPDATE = new EventType(
84 "EVENT_NUMBER_ORDERCOMMIT_SENT_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 CommittedOrderHandler.EVENT_NUMBER_ORDERCOMMIT_SENT_DAY,
122 CommittedOrderHandler.EVENT_NUMBER_ORDERCOMMIT_SENT_WEEK,
123 CommittedOrderHandler.EVENT_NUMBER_ORDERCOMMIT_SENT_MONTH};
124
125 /*** the history of the fired events */
126 private Map history = Collections.synchronizedMap(new HashMap());
127
128 /***
129 * constructs a new CommittedOrderHandler
130 *
131 * @param owner the owner
132 */
133 public CommittedOrderHandler(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, "CommittedOrderHandler", remoteException);
158 }
159
160
161 this.contentStore.addListener(this,
162 GameActorContentStore.EVENT_ORDERCOMMIT_SENT, true);
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 this.owner.addEventTypeToAnnounceList(
174 CommittedOrderHandler.EVENT_NUMBER_ORDERCOMMIT_SENT_UPDATE,
175 this);
176 } catch (RemoteException remoteException)
177 {
178 Logger.severe(this, "<init>", remoteException);
179 }
180
181
182 this.history.put(new String("day"), new HashMap());
183 this.history.put(new String("week"), new HashMap());
184 this.history.put(new String("month"), new HashMap());
185 }
186
187 /***
188 * @see nl.tudelft.simulation.event.EventListenerInterface#notify(nl.tudelft.simulation.event.EventInterface)
189 */
190 public void notify(final EventInterface event) throws RemoteException
191 {
192 if (event.getType()
193 .equals(GameActorContentStore.EVENT_ORDERCOMMIT_SENT))
194 {
195 OrderConfirmationData data = (OrderConfirmationData) event
196 .getContent();
197 Calendar calendar = Calendar.getInstance();
198 calendar.set(data.getProposedShippingDate().getYear(), data
199 .getProposedShippingDate().getMonth(), data
200 .getProposedShippingDate().getDay());
201
202 Calendar startCalendar = Calendar.getInstance();
203 startCalendar.setTimeInMillis(GlobalRowOrColumnNumber
204 .getStartTime());
205
206
207 int yearDiffence = calendar.get(Calendar.YEAR)
208 - startCalendar.get(Calendar.YEAR);
209
210 this.additionalDays = 0;
211 this.additionalWeeks = 0;
212 this.additionalMonths = 0;
213
214 while (yearDiffence > 0)
215 {
216 startCalendar.set(Calendar.YEAR, startCalendar
217 .get(Calendar.YEAR) + 1);
218 this.additionalDays = startCalendar
219 .getActualMaximum(Calendar.DAY_OF_YEAR);
220 this.additionalWeeks += 52;
221 this.additionalMonths += 12;
222
223 yearDiffence--;
224 }
225
226
227 this.handlePerDay(data, calendar);
228
229
230 this.handlePerWeek(data, calendar);
231
232
233 this.handlePerMonth(data, calendar);
234
235 return;
236 }
237 new ReceivedUnknownEventException(this, "notify", event.getType());
238 }
239
240 /***
241 * handles an orderconfirmation per day
242 *
243 * @param data the data
244 * @param calendar the calendar
245 */
246 private void handlePerDay(final OrderConfirmationData data,
247 final Calendar calendar)
248 {
249 int day = calendar.get(Calendar.DAY_OF_YEAR);
250
251
252 day += this.additionalDays;
253
254 if (this.currentDay != day)
255 {
256 this.currentDay = day;
257 }
258
259 double value = Double.NaN;
260 if (!this.productDayMap.containsKey(data.getProductName()))
261 {
262 Map map = new HashMap();
263 map.put("" + this.currentDay, new Double(data.getAmount()));
264 this.productDayMap.put(data.getProductName(), map);
265 value = data.getAmount();
266 } else
267 {
268 Map map = (Map) this.productDayMap.get(data.getProductName());
269
270 if (map.containsKey("" + this.currentDay))
271 {
272 value = ((Double) map.get("" + this.currentDay)).doubleValue();
273 value += data.getAmount();
274 map.put("" + this.currentDay, new Double(value));
275 } else
276 {
277 value = data.getAmount();
278 map.put("" + this.currentDay, new Double(value));
279 }
280 }
281
282
283 try
284 {
285 int rowNumber = 0;
286 try
287 {
288 rowNumber = ((Integer) GlobalRowOrColumnNumber
289 .getDayNumberTableRowNumber().get(new Integer(day)))
290 .intValue();
291 } catch (NullPointerException nullPointerException)
292 {
293 if (this.dateWithinRange(data))
294 {
295 Logger.severe(this, "handlePerDay",
296 "Date should be in range, but no row found.");
297 } else
298 {
299
300 rowNumber = GlobalRowOrColumnNumber.getDayHeaderValues()
301 .size() + 10;
302 }
303 }
304
305 Event event = new Event(
306 CommittedOrderHandler.EVENT_NUMBER_ORDERCOMMIT_SENT_DAY,
307 this, new CommittedOrderDayData(data.getProductName(),
308 rowNumber, value));
309 this.fireEvent(event);
310 this.addToHistory("day", day, data.getProductName(), event);
311 } catch (Exception exception)
312 {
313 Logger.severe(this, "handlePerDay", exception);
314 }
315 }
316
317 /***
318 * handles an orderconfirmation per week
319 *
320 * @param data the data
321 * @param calendar the calendar
322 */
323 private void handlePerWeek(final OrderConfirmationData data,
324 final Calendar calendar)
325 {
326 int week = (calendar.get(Calendar.WEEK_OF_YEAR));
327
328
329 week += this.additionalWeeks;
330
331 if (this.currentWeek != week)
332 {
333 this.currentWeek = week;
334 }
335
336 double value = Double.NaN;
337 if (!this.productWeekMap.containsKey(data.getProductName()))
338 {
339 Map map = new HashMap();
340 map.put("" + this.currentWeek, new Double(data.getAmount()));
341 this.productWeekMap.put(data.getProductName(), map);
342 value = data.getAmount();
343 } else
344 {
345 Map map = (Map) this.productWeekMap.get(data.getProductName());
346
347 if (map.containsKey("" + this.currentWeek))
348 {
349 value = ((Double) map.get("" + this.currentWeek)).doubleValue();
350 value += data.getAmount();
351 map.put("" + this.currentWeek, new Double(value));
352 } else
353 {
354 value = data.getAmount();
355 map.put("" + this.currentWeek, new Double(value));
356 }
357 }
358
359
360 try
361 {
362 int rowNumber = 0;
363 try
364 {
365 rowNumber = ((Integer) GlobalRowOrColumnNumber
366 .getWeekNumberTableRowNumber().get(new Integer(week)))
367 .intValue();
368 } catch (NullPointerException nullPointerException)
369 {
370 if (this.dateWithinRange(data))
371 {
372 Logger.severe(this, "handlePerWeek",
373 "Date should be in range, but no row found.");
374 } else
375 {
376
377 rowNumber = GlobalRowOrColumnNumber.getWeekHeaderValues()
378 .size() + 10;
379 }
380 }
381 if (value >= 0)
382 {
383 Event event = new Event(
384 CommittedOrderHandler.EVENT_NUMBER_ORDERCOMMIT_SENT_WEEK,
385 this, new CommittedOrderWeekData(data.getProductName(),
386 rowNumber, value));
387 this.fireEvent(event);
388 this.addToHistory("week", week, data.getProductName(), event);
389 } else
390 {
391 Logger.warning(this, "handlePerWeek", "Value equals: " + value
392 + ", where it should be >= 0.");
393 }
394 } catch (Exception exception)
395 {
396 Logger.severe(this, "handlePerWeek", exception);
397 }
398 }
399
400 /***
401 * handles an orderconfirmation per month
402 *
403 * @param data the data
404 * @param calendar the calendar
405 */
406 private void handlePerMonth(final OrderConfirmationData data,
407 final Calendar calendar)
408 {
409 int month = calendar.get(Calendar.MONTH);
410
411
412 month += this.additionalMonths;
413
414 if (this.currentMonth != month)
415 {
416 this.currentMonth = month;
417 }
418
419 double value = Double.NaN;
420 if (!this.productMonthMap.containsKey(data.getProductName()))
421 {
422 Map map = new HashMap();
423 map.put("" + this.currentMonth, new Double(data.getAmount()));
424 this.productMonthMap.put(data.getProductName(), map);
425 value = data.getAmount();
426 } else
427 {
428 Map map = (Map) this.productMonthMap.get(data.getProductName());
429
430 if (map.containsKey("" + this.currentMonth))
431 {
432 value = ((Double) map.get("" + this.currentMonth))
433 .doubleValue();
434 value += data.getAmount();
435 map.put("" + this.currentMonth, new Double(value));
436 } else
437 {
438 value = data.getAmount();
439 map.put("" + this.currentMonth, new Double(value));
440 }
441 }
442
443
444 try
445 {
446 int rowNumber = 0;
447 try
448 {
449 rowNumber = ((Integer) GlobalRowOrColumnNumber
450 .getMonthNumberTableRowNumber().get(new Integer(month)))
451 .intValue();
452 } catch (NullPointerException nullPointerException)
453 {
454 if (this.dateWithinRange(data))
455 {
456 Logger.severe(this, "handlePerMonth",
457 "Date should be in range, but no row found.");
458 } else
459 {
460
461 rowNumber = GlobalRowOrColumnNumber.getMonthHeaderValues()
462 .size() + 10;
463 }
464 }
465 Event event = new Event(
466 CommittedOrderHandler.EVENT_NUMBER_ORDERCOMMIT_SENT_MONTH,
467 this, new CommittedOrderMonthData(data.getProductName(),
468 rowNumber, value));
469 this.fireEvent(event);
470 this.addToHistory("month", month, data.getProductName(), event);
471 } catch (Exception exception)
472 {
473 Logger.severe(this, "handlePerMonth", exception);
474 }
475 }
476
477 /***
478 * @see org.gscg.common.interactionlayer.AnnounceInterface#announce(nl.tudelft.simulation.event.EventType,
479 * boolean)
480 */
481 public void announce(final EventType eventType, final boolean announce)
482 {
483 if (announce)
484 {
485 for (Iterator i = this.history.keySet().iterator(); i.hasNext();)
486 {
487 HashMap dateMap = (HashMap) this.history.get(i.next());
488 for (Iterator ii = dateMap.keySet().iterator(); ii.hasNext();)
489 {
490 HashMap productMap = (HashMap) dateMap.get(ii.next());
491 for (Iterator iii = productMap.keySet().iterator(); iii
492 .hasNext();)
493 {
494 try
495 {
496 this.owner
497 .notifyAnnounced((EventInterface) productMap
498 .get(iii.next()));
499 } catch (RemoteException remoteException)
500 {
501 Logger.severe(this, "announce", remoteException);
502 }
503 }
504 }
505 }
506 }
507 }
508
509 /***
510 * Method addToHistory.
511 *
512 * @param dateType a string reflecting the date type, e.g. day, week or
513 * month
514 * @param key the key, i.e. the number of the day, week or month
515 * @param productName the name of the product the confirmed order is
516 * received for
517 * @param event the event to store in the history
518 */
519 private void addToHistory(final String dateType, final int key,
520 final String productName, final Event event)
521 {
522 HashMap dateMap = (HashMap) this.history.get(dateType);
523 if (dateMap == null)
524 {
525 dateMap = new HashMap();
526 this.history.put(dateType, dateMap);
527 }
528
529 HashMap productMap = (HashMap) dateMap.get(productName);
530 if (productMap == null)
531 {
532 productMap = new HashMap();
533 dateMap.put(productName, productMap);
534 }
535 productMap.put(new Integer(key), event);
536 }
537
538 /***
539 * calculates whether a date is within range
540 *
541 * @param data the data
542 * @return returns false if the date is not within range, true otherwise
543 */
544 private boolean dateWithinRange(final OrderConfirmationData data)
545 {
546 Calendar startCalendar = Calendar.getInstance();
547 startCalendar.setTimeInMillis(GlobalRowOrColumnNumber.getStartTime());
548
549 Calendar endCalendar = Calendar.getInstance();
550 endCalendar.set(data.getProposedDelivery().getYear(), data
551 .getProposedDelivery().getMonth(), data.getProposedDelivery()
552 .getDay());
553
554 long runLength = GlobalRowOrColumnNumber.getNumberOfDays()
555 * TimeUnitInterface.DAY.getValue();
556 if ((endCalendar.getTimeInMillis() - startCalendar.getTimeInMillis()) > runLength)
557 {
558 return false;
559 }
560 return true;
561 }
562 }