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