001package jmri.jmrit.operations.locations.schedules; 002 003import org.slf4j.Logger; 004import org.slf4j.LoggerFactory; 005 006import jmri.InstanceManager; 007import jmri.beans.PropertyChangeSupport; 008import jmri.jmrit.operations.locations.*; 009import jmri.jmrit.operations.rollingstock.cars.CarManager; 010import jmri.jmrit.operations.setup.Control; 011import jmri.jmrit.operations.trains.schedules.TrainSchedule; 012import jmri.jmrit.operations.trains.schedules.TrainScheduleManager; 013 014/** 015 * Represents one schedule item of a schedule 016 * 017 * @author Daniel Boudreau Copyright (C) 2009, 2010, 2013, 2014 018 */ 019public class ScheduleItem extends PropertyChangeSupport implements java.beans.PropertyChangeListener { 020 021 public static final String NONE = ""; // NOI18N 022 023 protected String _id = NONE; 024 protected int _sequenceId = 0; // used to determine order in schedule 025 protected String _random = NONE; // used to determine if random set out is needed 026 protected String _setoutTrainScheduleId = NONE; // which day of the week to deliver car 027 protected String _type = NONE; // the type of car 028 protected String _road = NONE; // the car road 029 protected String _load = NONE; // the car load requested 030 protected String _ship = NONE; // the car load shipped 031 protected Location _destination = null; // car destination after load 032 protected Track _trackDestination = null;// car destination track after load 033 protected String _pickupTrainScheduleId = NONE; // which day of the week to pickup car 034 protected int _count = 1; // the number of times this type of car must be dropped 035 protected int _wait = 0; // how many trains this car must wait before being picked up 036 protected int _hits = 0; // how many times this schedule item has been used 037 protected String _comment = NONE; 038 039 public static final String TRAIN_SCHEDULE_CHANGED_PROPERTY = "trainScheduleId"; // NOI18N 040 public static final String COUNT_CHANGED_PROPERTY = "scheduleItemCount"; // NOI18N 041 public static final String TYPE_CHANGED_PROPERTY = "scheduleItemType"; // NOI18N 042 public static final String ROAD_CHANGED_PROPERTY = "scheduleItemRoad"; // NOI18N 043 public static final String LOAD_CHANGED_PROPERTY = "scheduleItemLoad"; // NOI18N 044 public static final String DESTINATION_CHANGED_PROPERTY = "scheduleItemDestination"; // NOI18N 045 public static final String DESTINATION_TRACK_CHANGED_PROPERTY = "scheduleItemDestinationTrack"; // NOI18N 046 public static final String WAIT_CHANGED_PROPERTY = "scheduleItemWait"; // NOI18N 047 public static final String HITS_CHANGED_PROPERTY = "scheduleItemHits"; // NOI18N 048 public static final String DISPOSE = "scheduleItemDispose"; // NOI18N 049 050 /** 051 * 052 * @param id ScheduleItem string id 053 * @param type car type for schedule 054 */ 055 public ScheduleItem(String id, String type) { 056 log.debug("New schedule item, car type ({}) id: {}", type, id); 057 _type = type; 058 _id = id; 059 } 060 061 public String getId() { 062 return _id; 063 } 064 065 public String getTypeName() { 066 return _type; 067 } 068 069 /** 070 * Sets the type of car requested. 071 * 072 * @param type The car type requested. 073 */ 074 public void setTypeName(String type) { 075 String old = _type; 076 _type = type; 077 firePropertyChange(TYPE_CHANGED_PROPERTY, old, type); 078 } 079 080 public String getRandom() { 081 return _random; 082 } 083 084 public void setRandom(String value) { 085 String old = _random; 086 _random = value; 087 firePropertyChange("scheduleItemRandomValueChanged", old, value); // NOI18N 088 } 089 090 /** 091 * Method determines by random if a car is accepted by a scheduleItem 092 * 093 * @return true if car is accepted by the scheduleItem 094 */ 095 public boolean doRandom() { 096 // make an adjustment based on the number of cars of a given type 097 int numberOfCars = InstanceManager.getDefault(CarManager.class).getByTypeList(getTypeName()).size(); 098 int adjustment = 100 + numberOfCars; 099 _calculatedRandom = adjustment * Math.random(); 100 try { 101 int value = Integer.parseInt(getRandom()); 102 log.debug("Selected random {}, created random {}", getRandom(), _calculatedRandom); 103 if (_calculatedRandom <= value) { 104 return true; 105 } 106 } catch (NumberFormatException e) { 107 log.error("Schedule item ({}) random value ({}) isn't a number", getId(), getRandom()); 108 } 109 return false; 110 } 111 112 double _calculatedRandom; 113 114 public double getCalculatedRandom() { 115 return _calculatedRandom; 116 } 117 118 public String getSetoutTrainScheduleId() { 119 return _setoutTrainScheduleId; 120 } 121 122 public String getSetoutTrainScheduleName() { 123 String name = ""; 124 TrainSchedule sch = InstanceManager.getDefault(TrainScheduleManager.class) 125 .getScheduleById(getSetoutTrainScheduleId()); 126 if (sch != null) { 127 name = sch.getName(); 128 } 129 return name; 130 } 131 132 public void setSetoutTrainScheduleId(String id) { 133 String old = _setoutTrainScheduleId; 134 _setoutTrainScheduleId = id; 135 firePropertyChange(TRAIN_SCHEDULE_CHANGED_PROPERTY, old, id); 136 } 137 138 public String getPickupTrainScheduleId() { 139 return _pickupTrainScheduleId; 140 } 141 142 public String getPickupTrainScheduleName() { 143 String name = ""; 144 TrainSchedule sch = InstanceManager.getDefault(TrainScheduleManager.class) 145 .getScheduleById(getPickupTrainScheduleId()); 146 if (sch != null) { 147 name = sch.getName(); 148 } 149 return name; 150 } 151 152 public void setPickupTrainScheduleId(String id) { 153 String old = _pickupTrainScheduleId; 154 _pickupTrainScheduleId = id; 155 firePropertyChange(TRAIN_SCHEDULE_CHANGED_PROPERTY, old, id); 156 } 157 158 public String getRoadName() { 159 return _road; 160 } 161 162 /** 163 * Sets the requested car road name. 164 * 165 * @param road The car road requested. 166 */ 167 public void setRoadName(String road) { 168 String old = _road; 169 _road = road; 170 firePropertyChange(ROAD_CHANGED_PROPERTY, old, road); 171 } 172 173 /** 174 * Sets the car load requested. 175 * 176 * @param load The load name requested. 177 */ 178 public void setReceiveLoadName(String load) { 179 String old = _load; 180 _load = load; 181 firePropertyChange(LOAD_CHANGED_PROPERTY, old, load); 182 } 183 184 public String getReceiveLoadName() { 185 return _load; 186 } 187 188 /** 189 * Sets the car load that will ship. 190 * 191 * @param load The car load shipped. 192 */ 193 public void setShipLoadName(String load) { 194 String old = _ship; 195 _ship = load; 196 firePropertyChange(LOAD_CHANGED_PROPERTY, old, load); 197 } 198 199 public String getShipLoadName() { 200 return _ship; 201 } 202 203 public int getSequenceId() { 204 return _sequenceId; 205 } 206 207 public void setSequenceId(int sequence) { 208 // property change not needed 209 _sequenceId = sequence; 210 } 211 212 /** 213 * How many times a car type needs to use the schedule item before going to 214 * the next item in the schedule. Used in sequential mode. Default is one. 215 * 216 * @return the number of times a car type needs to use the schedule item 217 */ 218 public int getCount() { 219 return _count; 220 } 221 222 public void setCount(int count) { 223 int old = _count; 224 _count = count; 225 firePropertyChange(COUNT_CHANGED_PROPERTY, old, count); 226 } 227 228 public int getWait() { 229 return _wait; 230 } 231 232 public void setWait(int wait) { 233 int old = _wait; 234 _wait = wait; 235 firePropertyChange(WAIT_CHANGED_PROPERTY, old, wait); 236 } 237 238 public int getHits() { 239 return _hits; 240 } 241 242 public void setHits(int hit) { 243 int old = _hits; 244 _hits = hit; 245 firePropertyChange(HITS_CHANGED_PROPERTY, old, hit); 246 } 247 248 public Location getDestination() { 249 return _destination; 250 } 251 252 public void setDestination(Location destination) { 253 Location old = _destination; 254 _destination = destination; 255 String oldName = "null"; // NOI18N 256 if (old != null) { 257 oldName = old.getName(); 258 } 259 String newName = "null"; // NOI18N 260 if (_destination != null) { 261 newName = _destination.getName(); 262 } 263 firePropertyChange(DESTINATION_CHANGED_PROPERTY, oldName, newName); 264 } 265 266 public String getDestinationName() { 267 if (_destination != null) { 268 return _destination.getName(); 269 } 270 return NONE; 271 } 272 273 public String getDestinationId() { 274 if (_destination != null) { 275 return _destination.getId(); 276 } 277 return NONE; 278 } 279 280 public Track getDestinationTrack() { 281 return _trackDestination; 282 } 283 284 public void setDestinationTrack(Track track) { 285 Track old = _trackDestination; 286 _trackDestination = track; 287 String oldName = "null"; // NOI18N 288 if (old != null) { 289 oldName = old.getName(); 290 } 291 String newName = "null"; // NOI18N 292 if (_trackDestination != null) { 293 newName = _trackDestination.getName(); 294 } 295 firePropertyChange(DESTINATION_TRACK_CHANGED_PROPERTY, oldName, newName); 296 } 297 298 public String getDestinationTrackName() { 299 if (_trackDestination != null) { 300 return _trackDestination.getName(); 301 } 302 return NONE; 303 } 304 305 public String getDestinationTrackId() { 306 if (_trackDestination != null) { 307 return _trackDestination.getId(); 308 } 309 return NONE; 310 } 311 312 public void setComment(String comment) { 313 _comment = comment; 314 } 315 316 public String getComment() { 317 return _comment; 318 } 319 320 public void copyScheduleItem (ScheduleItem si) { 321 setComment(si.getComment()); 322 setCount(si.getCount()); 323 setDestination(si.getDestination()); 324 setDestinationTrack(si.getDestinationTrack()); 325 setPickupTrainScheduleId(si.getPickupTrainScheduleId()); 326 setRandom(si.getRandom()); 327 setReceiveLoadName(si.getReceiveLoadName()); 328 setRoadName(si.getRoadName()); 329 setSetoutTrainScheduleId(si.getSetoutTrainScheduleId()); 330 setShipLoadName(si.getShipLoadName()); 331 setWait(si.getWait()); 332 } 333 334 public void dispose() { 335 firePropertyChange(DISPOSE, null, DISPOSE); 336 } 337 338 /** 339 * Construct this Entry from XML. This member has to remain synchronized 340 * with the detailed DTD in operations-config.xml 341 * 342 * @param e Consist XML element 343 */ 344 public ScheduleItem(org.jdom2.Element e) { 345 org.jdom2.Attribute a; 346 if ((a = e.getAttribute(Xml.ID)) != null) { 347 _id = a.getValue(); 348 } else { 349 log.warn("no id attribute in Schedule Item element when reading operations"); 350 } 351 if ((a = e.getAttribute(Xml.SEQUENCE_ID)) != null) { 352 _sequenceId = Integer.parseInt(a.getValue()); 353 } 354 if ((a = e.getAttribute(Xml.RANDOM)) != null) { 355 _random = a.getValue(); 356 } 357 if ((a = e.getAttribute(Xml.TRAIN_SCHEDULE_ID)) != null) { 358 _setoutTrainScheduleId = a.getValue(); 359 } 360 if ((a = e.getAttribute(Xml.PICKUP_TRAIN_SCHEDULE_ID)) != null) { 361 _pickupTrainScheduleId = a.getValue(); 362 } 363 if ((a = e.getAttribute(Xml.COUNT)) != null) { 364 _count = Integer.parseInt(a.getValue()); 365 } 366 if ((a = e.getAttribute(Xml.WAIT)) != null) { 367 _wait = Integer.parseInt(a.getValue()); 368 } 369 if ((a = e.getAttribute(Xml.TYPE)) != null) { 370 _type = a.getValue(); 371 } 372 if ((a = e.getAttribute(Xml.ROAD)) != null) { 373 _road = a.getValue(); 374 } 375 if ((a = e.getAttribute(Xml.LOAD)) != null) { 376 _load = a.getValue(); 377 } 378 if ((a = e.getAttribute(Xml.SHIP)) != null) { 379 _ship = a.getValue(); 380 } 381 if ((a = e.getAttribute(Xml.DESTINATION_ID)) != null) { 382 _destination = InstanceManager.getDefault(LocationManager.class).getLocationById(a.getValue()); 383 } 384 if ((a = e.getAttribute(Xml.DEST_TRACK_ID)) != null && _destination != null) { 385 _trackDestination = _destination.getTrackById(a.getValue()); 386 } 387 if ((a = e.getAttribute(Xml.COMMENT)) != null) { 388 _comment = a.getValue(); 389 } 390 if ((a = e.getAttribute(Xml.HITS)) != null) { 391 _hits = Integer.parseInt(a.getValue()); 392 } 393 } 394 395 /** 396 * Create an XML element to represent this Entry. This member has to remain 397 * synchronized with the detailed DTD in operations-config.xml. 398 * 399 * @return Contents in a JDOM Element 400 */ 401 public org.jdom2.Element store() { 402 org.jdom2.Element e = new org.jdom2.Element(Xml.ITEM); 403 e.setAttribute(Xml.ID, getId()); 404 e.setAttribute(Xml.SEQUENCE_ID, Integer.toString(getSequenceId())); 405 e.setAttribute(Xml.RANDOM, getRandom()); 406 e.setAttribute(Xml.TRAIN_SCHEDULE_ID, getSetoutTrainScheduleId()); 407 e.setAttribute(Xml.PICKUP_TRAIN_SCHEDULE_ID, getPickupTrainScheduleId()); 408 e.setAttribute(Xml.COUNT, Integer.toString(getCount())); 409 e.setAttribute(Xml.WAIT, Integer.toString(getWait())); 410 e.setAttribute(Xml.TYPE, getTypeName()); 411 e.setAttribute(Xml.ROAD, getRoadName()); 412 e.setAttribute(Xml.LOAD, getReceiveLoadName()); 413 e.setAttribute(Xml.SHIP, getShipLoadName()); 414 if (!getDestinationId().equals(NONE)) { 415 e.setAttribute(Xml.DESTINATION_ID, getDestinationId()); 416 } 417 if (!getDestinationTrackId().equals(NONE)) { 418 e.setAttribute(Xml.DEST_TRACK_ID, getDestinationTrackId()); 419 } 420 e.setAttribute(Xml.COMMENT, getComment()); 421 e.setAttribute(Xml.HITS, Integer.toString(getHits())); 422 return e; 423 } 424 425 @Override 426 public void propertyChange(java.beans.PropertyChangeEvent e) { 427 if (Control.SHOW_PROPERTY) { 428 log.debug("ScheduleItem ({}) id ({}) sees property change: ({}) old: ({}) new: ({})", getTypeName(), 429 getId(), e.getPropertyName(), e.getOldValue(), e.getNewValue()); // NOI18N 430 } 431 } 432 433 private final static Logger log = LoggerFactory.getLogger(ScheduleItem.class); 434 435}