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.setup.Setup;
010import jmri.jmrit.operations.trains.schedules.TrainSchedule;
011import jmri.jmrit.operations.trains.schedules.TrainScheduleManager;
012
013/**
014 * Represents one schedule item of a schedule
015 *
016 * @author Daniel Boudreau Copyright (C) 2009, 2010, 2013, 2014
017 */
018public class ScheduleItem extends PropertyChangeSupport {
019
020    public static final String NONE = ""; // NOI18N
021
022    protected String _id = NONE;
023    protected int _sequenceId = 0; // used to determine order in schedule
024    protected String _random = NONE; // used to determine if random set out is needed
025    protected String _setoutTrainScheduleId = NONE; // which day of the week to deliver car
026    protected String _type = NONE; // the type of car
027    protected String _road = NONE; // the car road
028    protected String _load = NONE; // the car load requested
029    protected String _ship = NONE; // the car load shipped
030    protected Location _destination = null; // car destination after load
031    protected Track _trackDestination = null;// car destination track after load
032    protected String _pickupTrainScheduleId = NONE; // which day of the week to pickup car
033    protected int _count = 1; // the number of times this type of car must be dropped
034    protected int _wait = 0; // how many trains this car must wait before being picked up
035    protected int _hits = 0; // how many times this schedule item has been used
036    protected String _comment = NONE;
037
038    public static final String TRAIN_SCHEDULE_CHANGED_PROPERTY = "trainScheduleId"; // NOI18N
039    public static final String COUNT_CHANGED_PROPERTY = "scheduleItemCount"; // NOI18N
040    public static final String TYPE_CHANGED_PROPERTY = "scheduleItemType"; // NOI18N
041    public static final String ROAD_CHANGED_PROPERTY = "scheduleItemRoad"; // NOI18N
042    public static final String LOAD_CHANGED_PROPERTY = "scheduleItemLoad"; // NOI18N
043    public static final String DESTINATION_CHANGED_PROPERTY = "scheduleItemDestination"; // NOI18N
044    public static final String DESTINATION_TRACK_CHANGED_PROPERTY = "scheduleItemDestinationTrack"; // NOI18N
045    public static final String WAIT_CHANGED_PROPERTY = "scheduleItemWait"; // NOI18N
046    public static final String HITS_CHANGED_PROPERTY = "scheduleItemHits"; // NOI18N
047    public static final String DISPOSE = "scheduleItemDispose"; // NOI18N
048
049    /**
050     * @param id   ScheduleItem string id
051     * @param type car type for schedule
052     */
053    public ScheduleItem(String id, String type) {
054        log.debug("New schedule item, car type ({}) id: {}", type, id);
055        _type = type;
056        _id = id;
057    }
058
059    public String getId() {
060        return _id;
061    }
062
063    public String getTypeName() {
064        return _type;
065    }
066
067    /**
068     * Sets the type of car requested.
069     *
070     * @param type The car type requested.
071     */
072    public void setTypeName(String type) {
073        String old = _type;
074        _type = type;
075        firePropertyChange(TYPE_CHANGED_PROPERTY, old, type);
076    }
077
078    public String getRandom() {
079        return _random;
080    }
081
082    public void setRandom(String value) {
083        String old = _random;
084        _random = value;
085        firePropertyChange("scheduleItemRandomValueChanged", old, value); // NOI18N
086    }
087
088    /**
089     * Method determines by random if a car is accepted by a scheduleItem
090     * 
091     * @return true if car is accepted by the scheduleItem
092     */
093    public boolean doRandom() {
094        // make an adjustment based on the number of passes
095        int passes = 1;
096        if (Setup.isBuildAggressive()) {
097            passes = Setup.getNumberPasses();
098        }
099        _calculatedRandom = 100 * passes * 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        firePropertyChange(DESTINATION_CHANGED_PROPERTY, old, destination);
256    }
257
258    public String getDestinationName() {
259        if (_destination != null) {
260            return _destination.getName();
261        }
262        return NONE;
263    }
264
265    public String getDestinationId() {
266        if (_destination != null) {
267            return _destination.getId();
268        }
269        return NONE;
270    }
271
272    public Track getDestinationTrack() {
273        return _trackDestination;
274    }
275
276    public void setDestinationTrack(Track track) {
277        Track old = _trackDestination;
278        _trackDestination = track;
279        firePropertyChange(DESTINATION_TRACK_CHANGED_PROPERTY, old, track);
280    }
281
282    public String getDestinationTrackName() {
283        if (_trackDestination != null) {
284            return _trackDestination.getName();
285        }
286        return NONE;
287    }
288
289    public String getDestinationTrackId() {
290        if (_trackDestination != null) {
291            return _trackDestination.getId();
292        }
293        return NONE;
294    }
295
296    public void setComment(String comment) {
297        _comment = comment;
298    }
299
300    public String getComment() {
301        return _comment;
302    }
303
304    public void copyScheduleItem(ScheduleItem si) {
305        setComment(si.getComment());
306        setCount(si.getCount());
307        setDestination(si.getDestination());
308        setDestinationTrack(si.getDestinationTrack());
309        setPickupTrainScheduleId(si.getPickupTrainScheduleId());
310        setRandom(si.getRandom());
311        setReceiveLoadName(si.getReceiveLoadName());
312        setRoadName(si.getRoadName());
313        setSetoutTrainScheduleId(si.getSetoutTrainScheduleId());
314        setShipLoadName(si.getShipLoadName());
315        setWait(si.getWait());
316    }
317
318    public void dispose() {
319        firePropertyChange(DISPOSE, null, DISPOSE);
320    }
321
322    /**
323     * Construct this Entry from XML. This member has to remain synchronized
324     * with the detailed DTD in operations-config.xml
325     *
326     * @param e Consist XML element
327     */
328    public ScheduleItem(org.jdom2.Element e) {
329        org.jdom2.Attribute a;
330        if ((a = e.getAttribute(Xml.ID)) != null) {
331            _id = a.getValue();
332        } else {
333            log.warn("no id attribute in Schedule Item element when reading operations");
334        }
335        if ((a = e.getAttribute(Xml.SEQUENCE_ID)) != null) {
336            _sequenceId = Integer.parseInt(a.getValue());
337        }
338        if ((a = e.getAttribute(Xml.RANDOM)) != null) {
339            _random = a.getValue();
340        }
341        if ((a = e.getAttribute(Xml.TRAIN_SCHEDULE_ID)) != null) {
342            _setoutTrainScheduleId = a.getValue();
343        }
344        if ((a = e.getAttribute(Xml.PICKUP_TRAIN_SCHEDULE_ID)) != null) {
345            _pickupTrainScheduleId = a.getValue();
346        }
347        if ((a = e.getAttribute(Xml.COUNT)) != null) {
348            _count = Integer.parseInt(a.getValue());
349        }
350        if ((a = e.getAttribute(Xml.WAIT)) != null) {
351            _wait = Integer.parseInt(a.getValue());
352        }
353        if ((a = e.getAttribute(Xml.TYPE)) != null) {
354            _type = a.getValue();
355        }
356        if ((a = e.getAttribute(Xml.ROAD)) != null) {
357            _road = a.getValue();
358        }
359        if ((a = e.getAttribute(Xml.LOAD)) != null) {
360            _load = a.getValue();
361        }
362        if ((a = e.getAttribute(Xml.SHIP)) != null) {
363            _ship = a.getValue();
364        }
365        if ((a = e.getAttribute(Xml.DESTINATION_ID)) != null) {
366            _destination = InstanceManager.getDefault(LocationManager.class).getLocationById(a.getValue());
367        }
368        if ((a = e.getAttribute(Xml.DEST_TRACK_ID)) != null && _destination != null) {
369            _trackDestination = _destination.getTrackById(a.getValue());
370        }
371        if ((a = e.getAttribute(Xml.COMMENT)) != null) {
372            _comment = a.getValue();
373        }
374        if ((a = e.getAttribute(Xml.HITS)) != null) {
375            _hits = Integer.parseInt(a.getValue());
376        }
377    }
378
379    /**
380     * Create an XML element to represent this Entry. This member has to remain
381     * synchronized with the detailed DTD in operations-config.xml.
382     *
383     * @return Contents in a JDOM Element
384     */
385    public org.jdom2.Element store() {
386        org.jdom2.Element e = new org.jdom2.Element(Xml.ITEM);
387        e.setAttribute(Xml.ID, getId());
388        e.setAttribute(Xml.SEQUENCE_ID, Integer.toString(getSequenceId()));
389        e.setAttribute(Xml.RANDOM, getRandom());
390        e.setAttribute(Xml.TRAIN_SCHEDULE_ID, getSetoutTrainScheduleId());
391        e.setAttribute(Xml.PICKUP_TRAIN_SCHEDULE_ID, getPickupTrainScheduleId());
392        e.setAttribute(Xml.COUNT, Integer.toString(getCount()));
393        e.setAttribute(Xml.WAIT, Integer.toString(getWait()));
394        e.setAttribute(Xml.TYPE, getTypeName());
395        e.setAttribute(Xml.ROAD, getRoadName());
396        e.setAttribute(Xml.LOAD, getReceiveLoadName());
397        e.setAttribute(Xml.SHIP, getShipLoadName());
398        if (!getDestinationId().equals(NONE)) {
399            e.setAttribute(Xml.DESTINATION_ID, getDestinationId());
400        }
401        if (!getDestinationTrackId().equals(NONE)) {
402            e.setAttribute(Xml.DEST_TRACK_ID, getDestinationTrackId());
403        }
404        e.setAttribute(Xml.COMMENT, getComment());
405        e.setAttribute(Xml.HITS, Integer.toString(getHits()));
406        return e;
407    }
408
409    private static final Logger log = LoggerFactory.getLogger(ScheduleItem.class);
410
411}