| 1 | package tmcsim.cadsimulator.managers; |
|---|
| 2 | |
|---|
| 3 | import java.util.TreeMap; |
|---|
| 4 | import java.util.Vector; |
|---|
| 5 | |
|---|
| 6 | import tmcsim.cadmodels.IncidentBoardModel_obj; |
|---|
| 7 | import tmcsim.cadmodels.IncidentInquiryModel_obj; |
|---|
| 8 | import tmcsim.cadmodels.IncidentSummaryModel_obj; |
|---|
| 9 | import tmcsim.cadsimulator.CADServer; |
|---|
| 10 | import tmcsim.cadsimulator.Coordinator; |
|---|
| 11 | import tmcsim.cadsimulator.SoundPlayer; |
|---|
| 12 | import tmcsim.client.cadclientgui.data.Incident; |
|---|
| 13 | import tmcsim.client.cadclientgui.data.IncidentEvent; |
|---|
| 14 | import tmcsim.common.ScriptException; |
|---|
| 15 | |
|---|
| 16 | /** |
|---|
| 17 | * IncidentManager is a CAD Simulator Manager containing the Incident data |
|---|
| 18 | * that has been loaded and occured during the simulation. The IncidentManager |
|---|
| 19 | * is used to load, remove, trigger, and reschedule Incidents in the simulation. |
|---|
| 20 | * Methods are provided to clear all Incident data from the simulation and to reset |
|---|
| 21 | * the Incidents to begin a new simulation. The IncidentBoard, IncidentInquiry, |
|---|
| 22 | * IncidentSummary, and IncidentEvent object lists are viewable through accessor methods. |
|---|
| 23 | * The tick() method is called when the simulation time changes. This method will then |
|---|
| 24 | * update all loaded Incidents. Any events that occur will be enqueued on the SoundPlayer. |
|---|
| 25 | * Any events that have completed are updated into the simulation data. The Coordinator |
|---|
| 26 | * is notified when an Incident starts or is updated. |
|---|
| 27 | * |
|---|
| 28 | * @author Matthew Cechini |
|---|
| 29 | * @version |
|---|
| 30 | */ |
|---|
| 31 | public class IncidentManager { |
|---|
| 32 | |
|---|
| 33 | /** Reference to the Coordinator Object. */ |
|---|
| 34 | private Coordinator theCoordinator; |
|---|
| 35 | |
|---|
| 36 | /** Reference to the SoundPlayer Object. */ |
|---|
| 37 | private SoundPlayer theSoundPlayer; |
|---|
| 38 | |
|---|
| 39 | /** |
|---|
| 40 | * Synchronization lock object used to avoid race conditions in accessing the |
|---|
| 41 | * incidentList Vector. |
|---|
| 42 | */ |
|---|
| 43 | private Object lock = new Object(); |
|---|
| 44 | |
|---|
| 45 | /** |
|---|
| 46 | * Map containing a vector of IncidentEvent objects(values) that have |
|---|
| 47 | * completed for each Incident log number(key). |
|---|
| 48 | */ |
|---|
| 49 | private TreeMap<Integer, Vector<IncidentEvent>> completedEvents; |
|---|
| 50 | |
|---|
| 51 | /** |
|---|
| 52 | * Vector of Incident objects that exist in the simulation. |
|---|
| 53 | */ |
|---|
| 54 | private Vector<Incident> incidentList; |
|---|
| 55 | |
|---|
| 56 | /** |
|---|
| 57 | * Vector of IncidentBoardModel_obj objects containing the data for |
|---|
| 58 | * incident board messages. |
|---|
| 59 | */ |
|---|
| 60 | private Vector<IncidentBoardModel_obj> IncidentBoardModelObjects; |
|---|
| 61 | |
|---|
| 62 | /** |
|---|
| 63 | * Vector of IncidentInquiryModel_obj objects containing the data |
|---|
| 64 | * for incident inquiry requests. |
|---|
| 65 | */ |
|---|
| 66 | private Vector<IncidentInquiryModel_obj> IncidentInquiryModelObjects; |
|---|
| 67 | |
|---|
| 68 | /** |
|---|
| 69 | * Vector of IncidentSummaryModel_obj objects containing the data |
|---|
| 70 | * for incident summary requests. |
|---|
| 71 | */ |
|---|
| 72 | private Vector<IncidentSummaryModel_obj> IncidentSummaryModelObjects; |
|---|
| 73 | |
|---|
| 74 | /** Boolean flag to designate whether incidents are loaded. */ |
|---|
| 75 | private boolean incidentsLoaded; |
|---|
| 76 | |
|---|
| 77 | |
|---|
| 78 | /** |
|---|
| 79 | * Constructor. Initialize data members. |
|---|
| 80 | * |
|---|
| 81 | * @param coor Coordinator Object. |
|---|
| 82 | * @param soundPlayer SoundPlayer Object. |
|---|
| 83 | */ |
|---|
| 84 | public IncidentManager(Coordinator coor, SoundPlayer soundPlayer) { |
|---|
| 85 | theCoordinator = coor; |
|---|
| 86 | theSoundPlayer = soundPlayer; |
|---|
| 87 | |
|---|
| 88 | incidentList = new Vector<Incident>(); |
|---|
| 89 | completedEvents = new TreeMap<Integer, Vector<IncidentEvent>>(); |
|---|
| 90 | IncidentBoardModelObjects = new Vector<IncidentBoardModel_obj>(); |
|---|
| 91 | IncidentInquiryModelObjects = new Vector<IncidentInquiryModel_obj>(); |
|---|
| 92 | IncidentSummaryModelObjects = new Vector<IncidentSummaryModel_obj>(); |
|---|
| 93 | |
|---|
| 94 | incidentsLoaded = false; |
|---|
| 95 | } |
|---|
| 96 | |
|---|
| 97 | /** |
|---|
| 98 | * Returns whether Incidents have been loaded into the simulation. |
|---|
| 99 | * @return true if incidents are loaded, false if not. |
|---|
| 100 | */ |
|---|
| 101 | public boolean areIncidentsLoaded() { |
|---|
| 102 | return incidentsLoaded; |
|---|
| 103 | } |
|---|
| 104 | |
|---|
| 105 | /** |
|---|
| 106 | * Clears IncidentBoard, IncidentInquiry, and IncidentSummary |
|---|
| 107 | * lists. The IncidentEvent list is also cleared. All |
|---|
| 108 | * Incidents are removed from the simulation and the |
|---|
| 109 | * incidentsLoaded flag is reset to false. |
|---|
| 110 | */ |
|---|
| 111 | public void clearIncidents() { |
|---|
| 112 | IncidentBoardModelObjects.clear(); |
|---|
| 113 | IncidentInquiryModelObjects.clear(); |
|---|
| 114 | IncidentSummaryModelObjects.clear(); |
|---|
| 115 | |
|---|
| 116 | incidentList.clear(); |
|---|
| 117 | |
|---|
| 118 | completedEvents.clear(); |
|---|
| 119 | |
|---|
| 120 | incidentsLoaded = false; |
|---|
| 121 | } |
|---|
| 122 | |
|---|
| 123 | /** |
|---|
| 124 | * Clears IncidentBoard, IncidentInquiry, and IncidentSummary |
|---|
| 125 | * lists. The IncidentEvent list is also cleared. All |
|---|
| 126 | * Incidents are reset, but not removed from the simulation. The |
|---|
| 127 | * incidentsLoaded flag is not changed. |
|---|
| 128 | */ |
|---|
| 129 | public void resetIncidents() { |
|---|
| 130 | IncidentBoardModelObjects.clear(); |
|---|
| 131 | IncidentInquiryModelObjects.clear(); |
|---|
| 132 | IncidentSummaryModelObjects.clear(); |
|---|
| 133 | |
|---|
| 134 | for(Incident inc : incidentList) { |
|---|
| 135 | inc.resetSimulation(); |
|---|
| 136 | } |
|---|
| 137 | |
|---|
| 138 | completedEvents.clear(); |
|---|
| 139 | } |
|---|
| 140 | |
|---|
| 141 | /** |
|---|
| 142 | * This method removes an Incident from the list of Incidents that |
|---|
| 143 | * have been loaded into the simulation. The incidentsLoaded flag |
|---|
| 144 | * is updated accordingly to whether there are Incidents remaining. |
|---|
| 145 | * |
|---|
| 146 | * @param incidentNumber Log number of Incident to remove. |
|---|
| 147 | * @throws ScriptException if the Incident has already occured. |
|---|
| 148 | */ |
|---|
| 149 | public void deleteIncident(Integer incidentNumber) throws ScriptException { |
|---|
| 150 | |
|---|
| 151 | synchronized (lock) { |
|---|
| 152 | Vector<Incident> incToRemove = new Vector<Incident>(); |
|---|
| 153 | |
|---|
| 154 | for (Incident inc : incidentList) { |
|---|
| 155 | |
|---|
| 156 | if (inc.getLogNumber().compareTo(incidentNumber) == 0) { |
|---|
| 157 | if (inc.hasOccured()) |
|---|
| 158 | throw new ScriptException( |
|---|
| 159 | ScriptException.INCIDENT_ALREADY_STARTED); |
|---|
| 160 | |
|---|
| 161 | incToRemove.add(inc); |
|---|
| 162 | } |
|---|
| 163 | } |
|---|
| 164 | |
|---|
| 165 | for (Incident inc : incToRemove) |
|---|
| 166 | incidentList.remove(inc); |
|---|
| 167 | } |
|---|
| 168 | |
|---|
| 169 | incidentsLoaded = incidentList.size() > 0; |
|---|
| 170 | } |
|---|
| 171 | |
|---|
| 172 | /** |
|---|
| 173 | * This method reschedules a loaded Incident to occur at a new simulation |
|---|
| 174 | * time. |
|---|
| 175 | * |
|---|
| 176 | * @param incidentNumber Log number of Incident to remove. |
|---|
| 177 | * @param newTime New simulation time for Incident to occur. |
|---|
| 178 | * @throws ScriptException if the Incident has already occured. |
|---|
| 179 | */ |
|---|
| 180 | public void rescheduleIncident(Integer incidentNumber, long newTime) |
|---|
| 181 | throws ScriptException { |
|---|
| 182 | |
|---|
| 183 | synchronized (lock) { |
|---|
| 184 | |
|---|
| 185 | for (Incident inc : incidentList) { |
|---|
| 186 | |
|---|
| 187 | if (inc.getLogNumber().equals(incidentNumber)) { |
|---|
| 188 | if (inc.hasOccured()) { |
|---|
| 189 | throw new ScriptException( |
|---|
| 190 | ScriptException.INCIDENT_ALREADY_STARTED); |
|---|
| 191 | } |
|---|
| 192 | inc.setSecondsToStart(newTime); |
|---|
| 193 | } |
|---|
| 194 | } |
|---|
| 195 | } |
|---|
| 196 | } |
|---|
| 197 | |
|---|
| 198 | /** |
|---|
| 199 | * This method adds a new Incident to the simulation. The incidentsLoaded |
|---|
| 200 | * flag is set to true. |
|---|
| 201 | * |
|---|
| 202 | * @param newIncident New Incident. |
|---|
| 203 | */ |
|---|
| 204 | public void addIncident(Incident newIncident) { |
|---|
| 205 | |
|---|
| 206 | synchronized (lock) { |
|---|
| 207 | incidentList.add(newIncident); |
|---|
| 208 | incidentsLoaded = true; |
|---|
| 209 | } |
|---|
| 210 | } |
|---|
| 211 | |
|---|
| 212 | /** |
|---|
| 213 | * This method adds a list of new Incidents to the simulation. The |
|---|
| 214 | * incidentsLoaded flag is set to true. |
|---|
| 215 | * |
|---|
| 216 | * @param newIncident New Incident. |
|---|
| 217 | */ |
|---|
| 218 | public void addIncidents(Vector<Incident> vector) { |
|---|
| 219 | |
|---|
| 220 | synchronized (lock) { |
|---|
| 221 | incidentList.addAll(vector); |
|---|
| 222 | incidentsLoaded = true; |
|---|
| 223 | } |
|---|
| 224 | } |
|---|
| 225 | |
|---|
| 226 | /** |
|---|
| 227 | * This method calls the tick() method on all loaded Incidents. If the |
|---|
| 228 | * clock tick causes IncidentEvents to be triggered, the events are |
|---|
| 229 | * enqueued in the SoundPlayer. If any IncidentEvents have completed, |
|---|
| 230 | * they are finalized with the current simulation and CAD time. The local |
|---|
| 231 | * IncidentInquiry and IncidentSummary lists are updated with the completed |
|---|
| 232 | * IncidentEvent Objects and then the Coordinator is notified with the |
|---|
| 233 | * IncidentEvent. |
|---|
| 234 | * |
|---|
| 235 | * @param currentSimTime Current simulation time (in seconds). |
|---|
| 236 | */ |
|---|
| 237 | public void tick(long currentSimTime) { |
|---|
| 238 | |
|---|
| 239 | for(Incident inc : incidentList) { |
|---|
| 240 | |
|---|
| 241 | inc.tick(currentSimTime); |
|---|
| 242 | |
|---|
| 243 | //For all events that occur with this tick, enqueue them in the sound player. |
|---|
| 244 | for(IncidentEvent event : inc.getTriggeredEvents(currentSimTime)) { |
|---|
| 245 | theSoundPlayer.enqueueClip(event); |
|---|
| 246 | } |
|---|
| 247 | |
|---|
| 248 | for(IncidentEvent event : inc.getCompletedEvents()) { |
|---|
| 249 | event.finalizeEvent(currentSimTime, CADServer.getCADTime()); |
|---|
| 250 | updateIncident(inc.getLogNumber(), event); |
|---|
| 251 | theCoordinator.updateIncidentInGUI(inc.getLogNumber(), event); |
|---|
| 252 | } |
|---|
| 253 | } |
|---|
| 254 | } |
|---|
| 255 | |
|---|
| 256 | /** |
|---|
| 257 | * This method forces an Incident to trigger. If the Incident corresponding |
|---|
| 258 | * to the parameter log number has not occured it is manually triggered. |
|---|
| 259 | * |
|---|
| 260 | * @param incidentNumber Log number of Incident to trigger. |
|---|
| 261 | * @param currentSimTime Current simulation time (in seconds). |
|---|
| 262 | */ |
|---|
| 263 | public void triggerIncident(Integer incidentNumber, Long currentSimTime) { |
|---|
| 264 | |
|---|
| 265 | for(Incident inc : incidentList) { |
|---|
| 266 | |
|---|
| 267 | if(inc.getLogNumber().equals(incidentNumber) |
|---|
| 268 | && !inc.hasOccured()) { |
|---|
| 269 | |
|---|
| 270 | inc.manualTrigger(currentSimTime); |
|---|
| 271 | } |
|---|
| 272 | } |
|---|
| 273 | |
|---|
| 274 | } |
|---|
| 275 | |
|---|
| 276 | /** |
|---|
| 277 | * This method updates the completed events, IncidentInquiry, and |
|---|
| 278 | * IncidentSummary lists with the completed IncidentEvent Object. |
|---|
| 279 | * If the IncidentEvent is the first event in an Incident, |
|---|
| 280 | * notify the Coordinator that the Incident has started. |
|---|
| 281 | * Regardles of whether the IncidentEvent is first or not, |
|---|
| 282 | * notify the Coordinator that the Incident has been updated. |
|---|
| 283 | * |
|---|
| 284 | * @param incidentNumber Log number of Incident to trigger. |
|---|
| 285 | * @param triggeredEvent Completed IncidentEvent. |
|---|
| 286 | */ |
|---|
| 287 | public void updateIncident(Integer incidentNumber, IncidentEvent completedEvent) { |
|---|
| 288 | |
|---|
| 289 | IncidentInquiryModel_obj targetIncident = null; |
|---|
| 290 | |
|---|
| 291 | if(completedEvents.containsKey(incidentNumber)) { |
|---|
| 292 | completedEvents.get(incidentNumber).add(completedEvent); |
|---|
| 293 | } |
|---|
| 294 | else { |
|---|
| 295 | Vector<IncidentEvent> temp = new Vector<IncidentEvent>(); |
|---|
| 296 | temp.add(completedEvent); |
|---|
| 297 | |
|---|
| 298 | completedEvents.put(incidentNumber, temp); |
|---|
| 299 | } |
|---|
| 300 | |
|---|
| 301 | for(IncidentInquiryModel_obj iimo : IncidentInquiryModelObjects) { |
|---|
| 302 | |
|---|
| 303 | if(iimo.getLogNumber().compareTo(incidentNumber) == 0) { |
|---|
| 304 | targetIncident = iimo; |
|---|
| 305 | |
|---|
| 306 | targetIncident.update(completedEvent.eventInfo); |
|---|
| 307 | break; |
|---|
| 308 | } |
|---|
| 309 | } |
|---|
| 310 | |
|---|
| 311 | if(targetIncident == null) { |
|---|
| 312 | completedEvent.eventInfo.getHeader().logStatus = "A"; |
|---|
| 313 | completedEvent.eventInfo.getHeader().incidentDate = CADServer.getCADDate().substring(0,4); |
|---|
| 314 | completedEvent.eventInfo.getHeader().incidentTime = CADServer.getCADTime(); |
|---|
| 315 | |
|---|
| 316 | targetIncident = new IncidentInquiryModel_obj(completedEvent.eventInfo); |
|---|
| 317 | IncidentInquiryModelObjects.add(targetIncident); |
|---|
| 318 | IncidentSummaryModelObjects.add(new IncidentSummaryModel_obj(completedEvent.eventInfo.getHeader())); |
|---|
| 319 | |
|---|
| 320 | theCoordinator.incidentStarted(completedEvent); |
|---|
| 321 | } |
|---|
| 322 | |
|---|
| 323 | theCoordinator.incidentUpdated(completedEvent); |
|---|
| 324 | } |
|---|
| 325 | |
|---|
| 326 | /** |
|---|
| 327 | * Returns whether an Incident exists in the simulation with a log number |
|---|
| 328 | * that matches the parameter value. |
|---|
| 329 | * |
|---|
| 330 | * @param incidentNumber Log number of Incident to trigger. |
|---|
| 331 | * @return true if Incident exists, false if not. |
|---|
| 332 | */ |
|---|
| 333 | public boolean incidentExists(Integer incidentNumber) { |
|---|
| 334 | boolean found = false; |
|---|
| 335 | |
|---|
| 336 | for(IncidentInquiryModel_obj iimo : IncidentInquiryModelObjects) { |
|---|
| 337 | if(iimo.getLogNumber().compareTo(incidentNumber) == 0) { |
|---|
| 338 | found = true; |
|---|
| 339 | break; |
|---|
| 340 | } |
|---|
| 341 | } |
|---|
| 342 | |
|---|
| 343 | return found; |
|---|
| 344 | } |
|---|
| 345 | |
|---|
| 346 | /** |
|---|
| 347 | * Returns the Vector of Incidents loaded into the simulation. |
|---|
| 348 | * @return Vector of loaded Incidents. |
|---|
| 349 | */ |
|---|
| 350 | public Vector<Incident> getIncidentList() { |
|---|
| 351 | return incidentList; |
|---|
| 352 | } |
|---|
| 353 | |
|---|
| 354 | /** |
|---|
| 355 | * Returns the map of triggered IncidentEvents referenced by eac |
|---|
| 356 | * Incident log number. |
|---|
| 357 | * |
|---|
| 358 | * @return Map of triggered IncidentEvents for all Incidents. |
|---|
| 359 | */ |
|---|
| 360 | public TreeMap<Integer, Vector<IncidentEvent>> getTriggeredEvents() { |
|---|
| 361 | return completedEvents; |
|---|
| 362 | } |
|---|
| 363 | |
|---|
| 364 | /** |
|---|
| 365 | * Returns the list of all IncidentBoardModel_obj objects. |
|---|
| 366 | * |
|---|
| 367 | * @returns A Vector of all IncidentBoardModel_obj objects. |
|---|
| 368 | */ |
|---|
| 369 | public Vector<IncidentBoardModel_obj> getIncidentBoardModelObjects() { |
|---|
| 370 | return IncidentBoardModelObjects; |
|---|
| 371 | } |
|---|
| 372 | |
|---|
| 373 | /** |
|---|
| 374 | * Returns a list of all IncidentInquiryModel_obj objects that match the parameter |
|---|
| 375 | * Incident log number. |
|---|
| 376 | * |
|---|
| 377 | * @param logNumber The log number to get all incident inquiry data for. |
|---|
| 378 | * @returns A Vector of IncidentInquiryModel_obj objects. |
|---|
| 379 | */ |
|---|
| 380 | public Vector<IncidentInquiryModel_obj> getIncidentInquiryModelObjects(Integer logNumber) { |
|---|
| 381 | Vector<IncidentInquiryModel_obj> modelObjs = new Vector<IncidentInquiryModel_obj>(); |
|---|
| 382 | |
|---|
| 383 | synchronized(lock) { |
|---|
| 384 | |
|---|
| 385 | for(IncidentInquiryModel_obj iimo : IncidentInquiryModelObjects) { |
|---|
| 386 | |
|---|
| 387 | //Find the model object in the private vector of incidents that matches |
|---|
| 388 | //the incident in the parameter's model. |
|---|
| 389 | |
|---|
| 390 | if(iimo.getLogNumber().compareTo(logNumber) == 0) { |
|---|
| 391 | modelObjs.add(iimo); |
|---|
| 392 | } |
|---|
| 393 | } |
|---|
| 394 | } |
|---|
| 395 | |
|---|
| 396 | |
|---|
| 397 | return modelObjs; |
|---|
| 398 | } |
|---|
| 399 | |
|---|
| 400 | /** |
|---|
| 401 | * Returns the list of all IncidentSummaryModel_obj objects. |
|---|
| 402 | * |
|---|
| 403 | * @returns A Vector of all IncidentSummaryModel_obj objects. |
|---|
| 404 | */ |
|---|
| 405 | public Vector<IncidentSummaryModel_obj> getIncidentSummaryModelObjects() { |
|---|
| 406 | return IncidentSummaryModelObjects; |
|---|
| 407 | } |
|---|
| 408 | |
|---|
| 409 | } |
|---|