001package jmri.jmrit.etcs;
002
003import java.awt.image.BufferedImage;
004import java.util.Objects;
005
006import javax.annotation.CheckForNull;
007import javax.swing.ImageIcon;
008
009import jmri.jmrit.etcs.dmi.swing.DmiPanel;
010
011import org.apiguardian.api.API;
012
013/**
014 * Class to represent DMI Track Points of Interest,
015 * i.e. Announcements and Orders.
016 * @author Steve Young Copyright (C) 2024
017 */
018@API(status=API.Status.EXPERIMENTAL)
019public class TrackCondition {
020
021    private final boolean isOrder;
022    private int distanceFromStart;
023    private final BufferedImage smallImage;
024    private final String largeImageOrder;
025    private final String largeImageNotOrder;
026    protected final String descript;
027    private int slotNum =0;
028    private final String actionCommand;
029
030    protected TrackCondition( int distance, boolean order,
031            String ordSmlPath, String notOrdSmlPath,
032            String ordLrgPath, String notOrdLrgPath,
033            String description, String command ) {
034        distanceFromStart = distance;
035        isOrder = order;
036        descript = description;
037        largeImageOrder = ordLrgPath;
038        largeImageNotOrder = notOrdLrgPath;
039        String smlIconPath = ( order ? ordSmlPath : notOrdSmlPath );
040        if ( ! smlIconPath.isBlank() ) {
041            smlIconPath += ".bmp";
042        }
043        actionCommand = command;
044        smallImage = ResourceUtil.getTransparentImage(smlIconPath);
045    }
046
047    /**
048     * Get if the Track Condition is an order,
049     * i.e. the Condition requires an acknowledgement from driver.
050     * @return true if order, else false if informational.
051     */
052    public boolean getIsOrder(){
053        return isOrder;
054    }
055
056    /**
057     * Get the Distance to the start of the Track Condition.
058     * @return the distance.
059     */
060    public int getDistanceFromStart() {
061        return distanceFromStart;
062    }
063
064    protected void setDistanceFromStart(int distance) {
065        distanceFromStart = distance;
066    }
067
068    /**
069     * Get a small icon to display in the Planning area?
070     * @return small icon.
071     */
072    public BufferedImage getSmlImage(){
073        return smallImage;
074    }
075
076    /**
077     * Get a larger image to display in a button.
078     * @param isOrder true if requires acknowledgement, false if informational.
079     * @return Large image.
080     */
081    @CheckForNull
082    public ImageIcon getLargeIcon(boolean isOrder){
083        var tst = getLargeImage(isOrder);
084        if ( tst == null ) {
085            return null;
086        }
087        return new ImageIcon(tst);
088    }
089
090    @CheckForNull
091    private BufferedImage getLargeImage(boolean isOrder){
092        String lrgIconPath = ( isOrder ? largeImageOrder : largeImageNotOrder );
093        if (!lrgIconPath.isEmpty()) {
094            lrgIconPath += ".bmp";
095        }
096        log.debug("getting image for {}", lrgIconPath);
097        return ResourceUtil.getTransparentImage(lrgIconPath);
098    }
099
100    /**
101     * Get Description of Track Condition.
102     * @return if is driver action or informational, along with description.
103     */
104    public String getDescription(){
105        return Bundle.getMessage(getIsOrder() ? "DriverAction" : "DriverInfo",descript);
106    }
107
108    /**
109     * If this is an order, get the acknowledgement String for when
110     * the driver clicks the button.
111     * These can be listened for via adding a changeListener to DmiPanel.
112     * @return the Acknowledgement String for the Condition.
113     */
114    public String getAckString(){
115        return actionCommand;
116    }
117
118    /**
119     * Get the Column Number for a Condition in the PASP Planning area.
120     * @return column number, 0 if unset.
121     */
122    public int getColumnNum(){
123        return slotNum;
124    }
125
126    /**
127     * Set the Column Number for the PASP column.
128     * @param newCol column number.
129     */
130    public void setColumnNum(int newCol) {
131        slotNum = newCol;
132    }
133
134    @Override
135    public boolean equals(Object o){
136        return o instanceof TrackCondition &&
137            ((TrackCondition)o).descript.equals(this.descript);
138    }
139
140    @Override
141    public int hashCode() {
142        return 29 + Objects.hashCode(descript);
143    }
144
145    @Override
146    public String toString(){
147        return this.getDescription();
148    }
149
150    /**
151     * Get a new Level Crossing Track Condition.
152     * No acknowledgement element.
153     * @param distance distance until the Track Condition.
154     * @return a Level Crossing Track Condition. 
155     */
156    public static TrackCondition levelCrossing(int distance ) {
157        return new TrackCondition(distance, false,
158            "", "","","LX_01",
159            "Level Crossing, not protected", "");
160    }
161
162    /**
163     * Get a new Radio Hole Track Condition.
164     * No acknowledgement element.
165     * @param distance distance until the Track Condition.
166     * @return a Radio Hole Track Condition. 
167     */
168    public static TrackCondition radioHole(int distance ) {
169        return new TrackCondition(distance, false,
170            "", "PL_10","","TC_12",
171            "Radio hole", "");
172    }
173
174    /**
175     * Get a new Radio Hole Track Condition.
176     * Always contains acknowledgement element.
177     * @param distance distance until the Track Condition.
178     * @return a Radio Hole Track Condition. 
179     */
180    public static TrackCondition soundHorn(int distance) {
181        return new TrackCondition(distance, true,
182            "PL_24", "","TC_35","",
183            "Sound Horn", DmiPanel.PROP_CHANGE_SOUND_HORN_ACK);
184    }
185
186    /**
187     * Get a new Radio Hole Track Condition.
188     * No acknowledgement element.
189     * No distance element as used for displaying symbol.
190     * @return a Radio Hole Track Condition. 
191     */
192    public static TrackCondition pantographIsLowered() {
193        return new TrackCondition(0, false,
194            "", "","","TC_01",
195            "Pantograph Lowered","");
196    }
197
198    /**
199     * Get a new Lower Pantograph Track Condition.
200     * @param distance distance until the Track Condition.
201     * @param order true if acknowledgement required, else false.
202     * @return a Lower Pantograph Track Condition. 
203     */
204    public static TrackCondition pantographLower(int distance, boolean order) {
205        return new TrackCondition(distance, order,
206            "PL_02", "PL_01","TC_03","TC_02",
207            "Lower Pantograph", DmiPanel.PROP_CHANGE_LOWER_PANT_ACK);
208    }
209
210    /**
211     * Get a new Raise Pantograph Track Condition.
212     * @param distance distance until the Track Condition.
213     * @param order true if acknowledgement required, else false.
214     * @return a Raise Pantograph Track Condition. 
215     */
216    public static TrackCondition pantographRaise(int distance, boolean order) {
217        return new TrackCondition(distance, order,
218            "PL_04", "PL_03","TC_05","TC_04",
219            "Raise Pantograph", DmiPanel.PROP_CHANGE_RAISE_PANT_ACK);
220    }
221
222    /**
223     * Get a new Close Air Conditioning Track Condition.
224     * @param distance distance until the Track Condition.
225     * @param order true if acknowledgement required, else false.
226     * @return a Close Air Conditioning Track Condition. 
227     */
228    public static TrackCondition airConClose(int distance, boolean order) {
229        return new TrackCondition(distance, order,
230            "PL_19", "PL_17","TC_21","TC_19",
231            "Close air conditioning intake", DmiPanel.PROP_CHANGE_AIRCON_CLOSE_ACK);
232    }
233
234    /**
235     * Get a new Open Air Conditioning Track Condition.
236     * @param distance distance until the Track Condition.
237     * @param order true if acknowledgement required, else false.
238     * @return an Open Air Conditioning Track Condition. 
239     */
240    public static TrackCondition airConOpen(int distance, boolean order) {
241        return new TrackCondition(distance, order,
242            "PL_20", "PL_18","TC_22","TC_20",
243            "Open air conditioning intake", DmiPanel.PROP_CHANGE_AIRCON_OPEN_ACK);
244    }
245
246    /**
247     * Get a Start of Neutral Section Track Condition.
248     * @param distance distance until the Track Condition.
249     * @param order true if acknowledgement required, else false.
250     * @return a start of Neutral Section Track Condition. 
251     */
252    public static TrackCondition neutralSection(int distance, boolean order) {
253        return new TrackCondition(distance, order,
254            "PL_06", "PL_05","TC_07","TC_06",
255            "Neutral Section", DmiPanel.PROP_CHANGE_NEUTRAL_START_ACK);
256    }
257
258    /**
259     * Get an End of Neutral Section Track Condition.
260     * @param distance distance until the Track Condition.
261     * @param order true if acknowledgement required, else false.
262     * @return an end of Neutral Section Track Condition. 
263     */
264    public static TrackCondition neutralSectionEnd(int distance, boolean order) {
265        return new TrackCondition(distance, order,
266            "PL_08", "PL_07","TC_09","TC_08",
267            "End of Neutral Section", DmiPanel.PROP_CHANGE_NEUTRAL_END_ACK);
268    }
269
270    /**
271     * Get a Non Stopping Area Track Condition.
272     * @param distance distance until the Track Condition.
273     * @param order true if acknowledgement required, else false.
274     *              Always true when used in a TrackSection
275     * @return a Non Stopping Area Track Condition. 
276     */
277    public static TrackCondition nonStoppingArea(int distance, boolean order ) {
278        return new TrackCondition(distance, order,
279            "PL_09", "PL_09","TC_11","TC_10",
280            "Non stopping area", DmiPanel.PROP_CHANGE_NONSTOP_ACK);
281    }
282
283    /**
284     * Get an Inhibit Magnetic Shoe Brake Track Condition.
285     * @param distance distance until the Track Condition.
286     * @param order true if acknowledgement required, else false.
287     * @return an Inhibit Magnetic Shoe Brake Track Condition. 
288     */
289    public static TrackCondition inhibitMagShoeBrake(int distance, boolean order) {
290        return new TrackCondition(distance, order,
291            "PL_12", "PL_11","TC_14","TC_13",
292            "Inhibition of Magnetic Shoe Brake", DmiPanel.PROP_CHANGE_INHIBIT_MAG_BRAKE_ACK);
293    }
294
295    /**
296     * Get an Inhibit Eddy Current Brake Track Condition.
297     * @param distance distance until the Track Condition.
298     * @param order true if acknowledgement required, else false.
299     * @return an Inhibit Eddy Current Brake Track Condition. 
300     */
301    public static TrackCondition inhibitEddyCurrentBrake(int distance, boolean order) {
302        return new TrackCondition(distance, order,
303            "PL_14", "PL_13","TC_16","TC_15",
304            "Inhibition of eddy current Brake", DmiPanel.PROP_CHANGE_INHIBIT_EDDY_BRAKE_ACK);
305    }
306
307    /**
308     * Get an Inhibit Regenerative Brake Track Condition.
309     * @param distance distance until the Track Condition.
310     * @param order true if acknowledgement required, else false.
311     * @return an Inhibit Regenerative Brake Track Condition. 
312     */
313    public static TrackCondition inhibitRegenerativeBrake(int distance, boolean order) {
314        return new TrackCondition(distance, order,
315            "PL_16", "PL_15","TC_18", "TC_17",
316            "Inhibition of regenerative Brake", DmiPanel.PROP_CHANGE_INHIBIT_REGEN_BRAKE_ACK);
317    }
318
319    /**
320     * Get a No Traction Track Condition.
321     * @param distance distance until the Track Condition.
322     * @param order true if acknowledgement required, else false.
323     * @return a No Traction Track Condition. 
324     */
325    public static TrackCondition tractionChange0(int distance, boolean order) {
326        return new TrackCondition(distance, order,
327            "PL_26", "PL_25","TC_24","TC_23",
328            "No traction system", DmiPanel.PROP_CHANGE_TRACTION_0_ACK);
329    }
330
331    /**
332     * Get a Traction Change to 25kV Track Condition.
333     * @param distance distance until the Track Condition.
334     * @param order true if acknowledgement required, else false.
335     * @return a Traction Change to 25kV Track Condition. 
336     */
337    public static TrackCondition tractionChange25000(int distance, boolean order) {
338        return new TrackCondition(distance, order,
339            "PL_28", "PL_27","TC_26","TC_25",
340            "Traction System : AC 25 kV 50 Hz", DmiPanel.PROP_CHANGE_TRACTION_25KV_ACK);
341    }
342
343    /**
344     * Get a Traction Change to 25kV Track Condition.
345     * @param distance distance until the Track Condition.
346     * @param order true if acknowledgement required, else false.
347     * @return a Traction Change to 25kV Track Condition. 
348     */
349    public static TrackCondition tractionChange15000(int distance, boolean order) {
350        return new TrackCondition(distance, order,
351            "PL_30", "PL_29","TC_28","TC_27",
352            "Traction System : AC 15 kV 16.7 Hz", DmiPanel.PROP_CHANGE_TRACTION_15KV_ACK);
353    }
354
355    /**
356     * Get a Traction Change to 3kV DC Track Condition.
357     * @param distance distance until the Track Condition.
358     * @param order true if acknowledgement required, else false.
359     * @return a Traction Change to 3kV DC Track Condition. 
360     */
361    public static TrackCondition tractionChange3000(int distance, boolean order) {
362        return new TrackCondition(distance, order,
363            "PL_32", "PL_31","TC_30","TC_29",
364            "Traction System : DC 3 kV", DmiPanel.PROP_CHANGE_TRACTION_3KV_ACK);
365    }
366
367    /**
368     * Get a Traction Change to 1.5kV Track Condition.
369     * @param distance distance until the Track Condition.
370     * @param order true if acknowledgement required, else false.
371     * @return a Traction Change to 1.5kV Track Condition. 
372     */
373    public static TrackCondition tractionChange1500(int distance, boolean order) {
374        return new TrackCondition(distance, order,
375            "PL_34", "PL_33","TC_32","TC_31",
376            "Traction System : DC 1.5 kV", DmiPanel.PROP_CHANGE_TRACTION_1_5KV_ACK);
377    }
378
379    /**
380     * Get a Traction Change to 600V or 750V Track Condition.
381     * @param distance distance until the Track Condition.
382     * @param order true if acknowledgement required, else false.
383     * @return a Traction Change to 750V Track Condition. 
384     */
385    public static TrackCondition tractionChange750(int distance, boolean order) {
386        return new TrackCondition(distance, order,
387            "PL_36", "PL_35","TC_34","TC_33",
388            "Traction System : DC 600/750 V", DmiPanel.PROP_CHANGE_TRACTION_750V_ACK);
389    }
390
391    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TrackCondition.class);
392
393}