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.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 cars of a given type
095        int numberOfCars = InstanceManager.getDefault(CarManager.class).getByTypeList(getTypeName()).size();
096        int adjustment = 100 + numberOfCars;
097        _calculatedRandom = adjustment * Math.random();
098        try {
099            int value = Integer.parseInt(getRandom());
100            log.debug("Selected random {}, created random {}", getRandom(), _calculatedRandom);
101            if (_calculatedRandom <= value) {
102                return true;
103            }
104        } catch (NumberFormatException e) {
105            log.error("Schedule item ({}) random value ({}) isn't a number", getId(), getRandom());
106        }
107        return false;
108    }
109
110    double _calculatedRandom;
111
112    public double getCalculatedRandom() {
113        return _calculatedRandom;
114    }
115
116    public String getSetoutTrainScheduleId() {
117        return _setoutTrainScheduleId;
118    }
119
120    public String getSetoutTrainScheduleName() {
121        String name = "";
122        TrainSchedule sch = InstanceManager.getDefault(TrainScheduleManager.class)
123                .getScheduleById(getSetoutTrainScheduleId());
124        if (sch != null) {
125            name = sch.getName();
126        }
127        return name;
128    }
129
130    public void setSetoutTrainScheduleId(String id) {
131        String old = _setoutTrainScheduleId;
132        _setoutTrainScheduleId = id;
133        firePropertyChange(TRAIN_SCHEDULE_CHANGED_PROPERTY, old, id);
134    }
135
136    public String getPickupTrainScheduleId() {
137        return _pickupTrainScheduleId;
138    }
139
140    public String getPickupTrainScheduleName() {
141        String name = "";
142        TrainSchedule sch = InstanceManager.getDefault(TrainScheduleManager.class)
143                .getScheduleById(getPickupTrainScheduleId());
144        if (sch != null) {
145            name = sch.getName();
146        }
147        return name;
148    }
149
150    public void setPickupTrainScheduleId(String id) {
151        String old = _pickupTrainScheduleId;
152        _pickupTrainScheduleId = id;
153        firePropertyChange(TRAIN_SCHEDULE_CHANGED_PROPERTY, old, id);
154    }
155
156    public String getRoadName() {
157        return _road;
158    }
159
160    /**
161     * Sets the requested car road name.
162     *
163     * @param road The car road requested.
164     */
165    public void setRoadName(String road) {
166        String old = _road;
167        _road = road;
168        firePropertyChange(ROAD_CHANGED_PROPERTY, old, road);
169    }
170
171    /**
172     * Sets the car load requested.
173     *
174     * @param load The load name requested.
175     */
176    public void setReceiveLoadName(String load) {
177        String old = _load;
178        _load = load;
179        firePropertyChange(LOAD_CHANGED_PROPERTY, old, load);
180    }
181
182    public String getReceiveLoadName() {
183        return _load;
184    }
185
186    /**
187     * Sets the car load that will ship.
188     *
189     * @param load The car load shipped.
190     */
191    public void setShipLoadName(String load) {
192        String old = _ship;
193        _ship = load;
194        firePropertyChange(LOAD_CHANGED_PROPERTY, old, load);
195    }
196
197    public String getShipLoadName() {
198        return _ship;
199    }
200
201    public int getSequenceId() {
202        return _sequenceId;
203    }
204
205    public void setSequenceId(int sequence) {
206        // property change not needed
207        _sequenceId = sequence;
208    }
209
210    /**
211     * How many times a car type needs to use the schedule item before going to
212     * the next item in the schedule. Used in sequential mode. Default is one.
213     * 
214     * @return the number of times a car type needs to use the schedule item
215     */
216    public int getCount() {
217        return _count;
218    }
219
220    public void setCount(int count) {
221        int old = _count;
222        _count = count;
223        firePropertyChange(COUNT_CHANGED_PROPERTY, old, count);
224    }
225
226    public int getWait() {
227        return _wait;
228    }
229
230    public void setWait(int wait) {
231        int old = _wait;
232        _wait = wait;
233        firePropertyChange(WAIT_CHANGED_PROPERTY, old, wait);
234    }
235
236    public int getHits() {
237        return _hits;
238    }
239
240    public void setHits(int hit) {
241        int old = _hits;
242        _hits = hit;
243        firePropertyChange(HITS_CHANGED_PROPERTY, old, hit);
244    }
245
246    public Location getDestination() {
247        return _destination;
248    }
249
250    public void setDestination(Location destination) {
251        Location old = _destination;
252        _destination = destination;
253        firePropertyChange(DESTINATION_CHANGED_PROPERTY, old, destination);
254    }
255
256    public String getDestinationName() {
257        if (_destination != null) {
258            return _destination.getName();
259        }
260        return NONE;
261    }
262
263    public String getDestinationId() {
264        if (_destination != null) {
265            return _destination.getId();
266        }
267        return NONE;
268    }
269
270    public Track getDestinationTrack() {
271        return _trackDestination;
272    }
273
274    public void setDestinationTrack(Track track) {
275        Track old = _trackDestination;
276        _trackDestination = track;
277        firePropertyChange(DESTINATION_TRACK_CHANGED_PROPERTY, old, track);
278    }
279
280    public String getDestinationTrackName() {
281        if (_trackDestination != null) {
282            return _trackDestination.getName();
283        }
284        return NONE;
285    }
286
287    public String getDestinationTrackId() {
288        if (_trackDestination != null) {
289            return _trackDestination.getId();
290        }
291        return NONE;
292    }
293
294    public void setComment(String comment) {
295        _comment = comment;
296    }
297
298    public String getComment() {
299        return _comment;
300    }
301
302    public void copyScheduleItem(ScheduleItem si) {
303        setComment(si.getComment());
304        setCount(si.getCount());
305        setDestination(si.getDestination());
306        setDestinationTrack(si.getDestinationTrack());
307        setPickupTrainScheduleId(si.getPickupTrainScheduleId());
308        setRandom(si.getRandom());
309        setReceiveLoadName(si.getReceiveLoadName());
310        setRoadName(si.getRoadName());
311        setSetoutTrainScheduleId(si.getSetoutTrainScheduleId());
312        setShipLoadName(si.getShipLoadName());
313        setWait(si.getWait());
314    }
315
316    public void dispose() {
317        firePropertyChange(DISPOSE, null, DISPOSE);
318    }
319
320    /**
321     * Construct this Entry from XML. This member has to remain synchronized
322     * with the detailed DTD in operations-config.xml
323     *
324     * @param e Consist XML element
325     */
326    public ScheduleItem(org.jdom2.Element e) {
327        org.jdom2.Attribute a;
328        if ((a = e.getAttribute(Xml.ID)) != null) {
329            _id = a.getValue();
330        } else {
331            log.warn("no id attribute in Schedule Item element when reading operations");
332        }
333        if ((a = e.getAttribute(Xml.SEQUENCE_ID)) != null) {
334            _sequenceId = Integer.parseInt(a.getValue());
335        }
336        if ((a = e.getAttribute(Xml.RANDOM)) != null) {
337            _random = a.getValue();
338        }
339        if ((a = e.getAttribute(Xml.TRAIN_SCHEDULE_ID)) != null) {
340            _setoutTrainScheduleId = a.getValue();
341        }
342        if ((a = e.getAttribute(Xml.PICKUP_TRAIN_SCHEDULE_ID)) != null) {
343            _pickupTrainScheduleId = a.getValue();
344        }
345        if ((a = e.getAttribute(Xml.COUNT)) != null) {
346            _count = Integer.parseInt(a.getValue());
347        }
348        if ((a = e.getAttribute(Xml.WAIT)) != null) {
349            _wait = Integer.parseInt(a.getValue());
350        }
351        if ((a = e.getAttribute(Xml.TYPE)) != null) {
352            _type = a.getValue();
353        }
354        if ((a = e.getAttribute(Xml.ROAD)) != null) {
355            _road = a.getValue();
356        }
357        if ((a = e.getAttribute(Xml.LOAD)) != null) {
358            _load = a.getValue();
359        }
360        if ((a = e.getAttribute(Xml.SHIP)) != null) {
361            _ship = a.getValue();
362        }
363        if ((a = e.getAttribute(Xml.DESTINATION_ID)) != null) {
364            _destination = InstanceManager.getDefault(LocationManager.class).getLocationById(a.getValue());
365        }
366        if ((a = e.getAttribute(Xml.DEST_TRACK_ID)) != null && _destination != null) {
367            _trackDestination = _destination.getTrackById(a.getValue());
368        }
369        if ((a = e.getAttribute(Xml.COMMENT)) != null) {
370            _comment = a.getValue();
371        }
372        if ((a = e.getAttribute(Xml.HITS)) != null) {
373            _hits = Integer.parseInt(a.getValue());
374        }
375    }
376
377    /**
378     * Create an XML element to represent this Entry. This member has to remain
379     * synchronized with the detailed DTD in operations-config.xml.
380     *
381     * @return Contents in a JDOM Element
382     */
383    public org.jdom2.Element store() {
384        org.jdom2.Element e = new org.jdom2.Element(Xml.ITEM);
385        e.setAttribute(Xml.ID, getId());
386        e.setAttribute(Xml.SEQUENCE_ID, Integer.toString(getSequenceId()));
387        e.setAttribute(Xml.RANDOM, getRandom());
388        e.setAttribute(Xml.TRAIN_SCHEDULE_ID, getSetoutTrainScheduleId());
389        e.setAttribute(Xml.PICKUP_TRAIN_SCHEDULE_ID, getPickupTrainScheduleId());
390        e.setAttribute(Xml.COUNT, Integer.toString(getCount()));
391        e.setAttribute(Xml.WAIT, Integer.toString(getWait()));
392        e.setAttribute(Xml.TYPE, getTypeName());
393        e.setAttribute(Xml.ROAD, getRoadName());
394        e.setAttribute(Xml.LOAD, getReceiveLoadName());
395        e.setAttribute(Xml.SHIP, getShipLoadName());
396        if (!getDestinationId().equals(NONE)) {
397            e.setAttribute(Xml.DESTINATION_ID, getDestinationId());
398        }
399        if (!getDestinationTrackId().equals(NONE)) {
400            e.setAttribute(Xml.DEST_TRACK_ID, getDestinationTrackId());
401        }
402        e.setAttribute(Xml.COMMENT, getComment());
403        e.setAttribute(Xml.HITS, Integer.toString(getHits()));
404        return e;
405    }
406
407    private static final Logger log = LoggerFactory.getLogger(ScheduleItem.class);
408
409}