001package jmri.implementation;
002
003import java.awt.event.ActionListener;
004import javax.swing.Timer;
005
006import javax.annotation.CheckForNull;
007
008import jmri.Audio;
009import jmri.Conditional;
010import jmri.ConditionalAction;
011import jmri.InstanceManager;
012import jmri.Light;
013import jmri.Memory;
014import jmri.NamedBean;
015import jmri.NamedBeanHandle;
016import jmri.Route;
017import jmri.RouteManager;
018import jmri.Sensor;
019import jmri.SignalHead;
020import jmri.Turnout;
021import jmri.jmrit.Sound;
022import jmri.jmrit.beantable.LogixTableAction;
023import jmri.jmrit.logix.OBlockManager;
024import jmri.jmrit.logix.Warrant;
025import jmri.jmrit.logix.WarrantManager;
026
027/**
028 * The consequent of the antecedent of the conditional proposition. The data for
029 * the action to be taken when a Conditional calculates to True
030 * <p>
031 * This is in the implementations package because of a Swing dependence via the
032 * times. Java 1.5 or Java 1.6 might make it possible to break that, which will
033 * simplify things.
034 *
035 * @author Pete Cressman Copyright (C) 2009, 2010, 2011
036 * @author Matthew Harris copyright (c) 2009
037 */
038public class DefaultConditionalAction implements ConditionalAction {
039
040    private int _option = Conditional.ACTION_OPTION_ON_CHANGE_TO_TRUE;
041    private Conditional.Action _type = Conditional.Action.NONE;
042    private String _deviceName = " ";
043    private int _actionData = 0;
044    private String _actionString = "";
045    private NamedBeanHandle<?> _namedBean = null;
046
047    private Timer _timer = null;
048    private ActionListener _listener = null;
049    private boolean _timerActive = false;
050    private boolean _indirectAction = false;
051    private Sound _sound = null;
052
053    static final java.util.ResourceBundle rbx = java.util.ResourceBundle.getBundle("jmri.jmrit.conditional.ConditionalBundle");
054    protected jmri.NamedBeanHandleManager nbhm = InstanceManager.getDefault(jmri.NamedBeanHandleManager.class);
055
056    public DefaultConditionalAction() {
057    }
058
059    public DefaultConditionalAction(int option, Conditional.Action type, String name, int actionData, String actionStr) {
060        _option = option;
061        _type = type;
062        _deviceName = name;
063        _actionData = actionData;
064        _actionString = actionStr;
065
066        NamedBean bean = getIndirectBean(_deviceName);
067        if (bean == null) {
068            bean = getActionBean(_deviceName);
069        }
070        if (bean != null) {
071            _namedBean = nbhm.getNamedBeanHandle(_deviceName, bean);
072        } else {
073            _namedBean = null;
074        }
075    }
076
077    @Override
078    public boolean equals(Object obj) {
079        if (obj == this) {
080            return true;
081        }
082        if (obj == null) {
083            return false;
084        }
085
086        if (!(getClass() == obj.getClass())) {
087            return false;
088        } else {
089            DefaultConditionalAction p = (DefaultConditionalAction) obj;
090            if ((p._option != this._option)
091                    || (p._type != this._type)
092                    || (p._actionData != this._actionData)) {
093                return false;
094            }
095
096            if ((p._namedBean == null && this._namedBean != null)
097                    || (p._namedBean != null && this._namedBean == null)
098                    || (p._namedBean != null && this._namedBean != null && !p._namedBean.equals(this._namedBean))) {
099                return false;
100            }
101
102            if ((p._deviceName == null && this._deviceName != null)
103                    || (p._deviceName != null && this._deviceName == null)
104                    || (p._deviceName != null && this._deviceName != null && !p._deviceName.equals(this._deviceName))) {
105                return false;
106            }
107
108            if ((p._actionString == null && this._actionString != null)
109                    || (p._actionString != null && this._actionString == null)
110                    || (p._actionString != null && this._actionString != null && !p._actionString.equals(this._actionString))) {
111                return false;
112            }
113
114        }
115        return true;
116    }
117
118    @Override
119    public int hashCode() {
120        int hash = _option * 1000 + _type.getIntValue() * 1000 * 1000 + _actionData;
121        if (_deviceName != null) {
122            hash += _deviceName.hashCode();
123        }
124        return hash;
125    }
126
127    /**
128     * If this is an indirect reference, return the Memory bean.
129     *
130     */
131    @CheckForNull
132    private Memory getIndirectBean(@CheckForNull String devName) {
133        if (devName != null && devName.length() > 0 && devName.charAt(0) == '@') {
134            String memName = devName.substring(1);
135            Memory m = InstanceManager.memoryManagerInstance().getMemory(memName);
136            if (m != null) {
137                _indirectAction = true;
138                return m;
139            }
140            log.error("\"{}\" invalid indirect memory name in action {} of type {}", devName, _actionString, _type);
141        } else {
142            _indirectAction = false;
143        }
144        return null;
145    }
146
147    /**
148     * Return the device bean that will do the action.
149     *
150     */
151    @CheckForNull
152    private NamedBean getActionBean(@CheckForNull String devName) {
153        if (devName == null) {
154            return null;
155        }
156        NamedBean bean = null;
157        try {
158            switch (_type.getItemType()) {
159                case SENSOR:
160                    try {
161                        bean = InstanceManager.sensorManagerInstance().provideSensor(devName);
162                    } catch (IllegalArgumentException e) {
163                        bean = null;
164                        log.error("invalid sensor name= \"{}\" in conditional action", devName);
165                    }
166                    break;
167                case TURNOUT:
168                    try {
169                        bean = InstanceManager.turnoutManagerInstance().provideTurnout(devName);
170                    } catch (IllegalArgumentException e) {
171                        bean = null;
172                        log.error("invalid turnout name= \"{}\" in conditional action", devName);
173                    }
174                    break;
175                case MEMORY:
176                    try {
177                        bean = InstanceManager.memoryManagerInstance().provideMemory(devName);
178                    } catch (IllegalArgumentException e) {
179                        bean = null;
180                        log.error("invalid memory name= \"{}\" in conditional action", devName);
181                    }
182                    break;
183                case LIGHT:
184                    try {
185                        bean = InstanceManager.lightManagerInstance().getLight(devName);
186                    } catch (IllegalArgumentException e) {
187                        bean = null;
188                        log.error("invalid light name= \"{}\" in conditional action", devName);
189                    }
190                    break;
191                case SIGNALMAST:
192                    try {
193                        bean = InstanceManager.getDefault(jmri.SignalMastManager.class).provideSignalMast(devName);
194                    } catch (IllegalArgumentException e) {
195                        bean = null;
196                        log.error("invalid signal mast name= \"{}\" in conditional action", devName);
197                    }
198                    break;
199                case SIGNALHEAD:
200                    try {
201                        bean = InstanceManager.getDefault(jmri.SignalHeadManager.class).getSignalHead(devName);
202                    } catch (IllegalArgumentException e) {
203                        bean = null;
204                        log.error("invalid signal head name= \"{}\" in conditional action", devName);
205                    }
206                    break;
207                case WARRANT:
208                    try {
209                        bean = InstanceManager.getDefault(WarrantManager.class).getWarrant(devName);
210                    } catch (IllegalArgumentException e) {
211                        bean = null;
212                        log.error("invalid Warrant name= \"{}\" in conditional action", devName);
213                    }
214                    break;
215                case OBLOCK:
216                    try {
217                        bean = InstanceManager.getDefault(OBlockManager.class).getOBlock(devName);
218                    } catch (IllegalArgumentException e) {
219                        bean = null;
220                        log.error("invalid OBlock name= \"{}\" in conditional action", devName);
221                    }
222                    break;
223                case ENTRYEXIT:
224                    try {
225                        bean = InstanceManager.getDefault(jmri.jmrit.entryexit.EntryExitPairs.class).getNamedBean(devName);
226                    } catch (IllegalArgumentException e) {
227                        bean = null;
228                        log.error("invalid NX name= \"{}\" in conditional action", devName);
229                    }
230                    break;
231                case LOGIX:
232                    try {
233                        bean = InstanceManager.getDefault(jmri.LogixManager.class).getLogix(devName);
234                    } catch (IllegalArgumentException e) {
235                        bean = null;
236                        log.error("invalid Logix name= \"{}\" in conditional action", devName);
237                    }
238                    break;
239                default:
240                    if (getType() == Conditional.Action.TRIGGER_ROUTE) {
241                        try {
242                            bean = InstanceManager.getDefault(RouteManager.class).getRoute(devName);
243                        } catch (IllegalArgumentException e) {
244                            bean = null;
245                            log.error("invalid Route name= \"{}\" in conditional action", devName);
246                        }
247                    }
248            }
249        } catch (java.lang.NumberFormatException ex) {
250            // ingonred, can be considered normal if the logixs are loaded prior to any other beans
251        }
252        return bean;
253    }
254
255    /**
256     * The consequent device or element type.
257     */
258    @Override
259    public Conditional.Action getType() {
260        return _type;
261    }
262
263    @Override
264    public void setType(Conditional.Action type) {
265        _type = type;
266    }
267
268    /**
269     * Set type from user name for it.
270     */
271    @Override
272    public void setType(String type) {
273        _type = stringToActionType(type);
274    }
275
276    /**
277     * Name of the device or element that is affected.
278     */
279    @Override
280    public String getDeviceName() {
281        if (_namedBean != null) {
282            return _namedBean.getName();
283        }
284        /* As we have a trigger for something using the action, then hopefully
285         all the managers have been loaded and we can get the bean, which prevented
286         the bean from being loaded in the first place */
287        setDeviceName(_deviceName);
288        return _deviceName;
289    }
290
291    @Override
292    public void setDeviceName(String deviceName) {
293        _deviceName = deviceName;
294        NamedBean bean = getIndirectBean(_deviceName);
295        if (bean == null) {
296            bean = getActionBean(_deviceName);
297        }
298        if (bean != null) {
299            _namedBean = nbhm.getNamedBeanHandle(_deviceName, bean);
300        } else {
301            _namedBean = null;
302        }
303    }
304
305    @Override
306    public NamedBeanHandle<?> getNamedBean() {
307        if (_indirectAction) {
308            Memory m = (Memory) (_namedBean.getBean());
309            String actionName = (String) m.getValue();
310            NamedBean bean = getActionBean(actionName);
311            if (bean != null) {
312                return nbhm.getNamedBeanHandle(actionName, bean);
313            } else {
314                return null;
315            }
316        }
317        return _namedBean;
318    }
319
320    @Override
321    public NamedBean getBean() {
322        if (_namedBean != null) {
323            NamedBeanHandle<?> handle = getNamedBean();
324            if (handle == null) return null;
325            return handle.getBean();
326        }
327        setDeviceName(_deviceName); //ReApply name as that will create namedBean, save replicating it here
328        if (_namedBean != null) {
329            return getNamedBean().getBean();
330        }
331        return null;
332    }
333
334    /**
335     * Options on when action is taken.
336     */
337    @Override
338    public int getOption() {
339        return _option;
340    }
341
342    @Override
343    public void setOption(int option) {
344        _option = option;
345    }
346
347    /**
348     * Integer data for action.
349     */
350    @Override
351    public int getActionData() {
352        return _actionData;
353    }
354
355    @Override
356    public void setActionData(int actionData) {
357        _actionData = actionData;
358    }
359
360    /**
361     * Set action data from user name for it.
362     */
363    @Override
364    public void setActionData(String actionData) {
365        _actionData = stringToActionData(actionData);
366    }
367
368    /**
369     * String data for action.
370     */
371    @Override
372    public String getActionString() {
373        if (_actionString == null) {
374            _actionString = getTypeString();
375        }
376        return _actionString;
377    }
378
379    @Override
380    public void setActionString(String actionString) {
381        _actionString = actionString;
382    }
383
384    /*
385     * Get timer for delays and other timed events.
386     */
387    @Override
388    public Timer getTimer() {
389        return _timer;
390    }
391
392    /*
393     * Set timer for delays and other timed events.
394     */
395    @Override
396    public void setTimer(Timer timer) {
397        _timer = timer;
398    }
399
400    @Override
401    public boolean isTimerActive() {
402        return _timerActive;
403    }
404
405    @Override
406    public void startTimer() {
407        if (_timer != null) {
408            _timer.start();
409            _timerActive = true;
410        } else {
411            log.error("timer is null for {} of type {}", _deviceName, getTypeString());
412        }
413    }
414
415    @Override
416    public void stopTimer() {
417        if (_timer != null) {
418            _timer.stop();
419            _timerActive = false;
420        }
421    }
422
423    /*
424     * Set listener for delays and other timed events.
425     */
426    @Override
427    public ActionListener getListener() {
428        return _listener;
429    }
430
431    /*
432     * set listener for delays and other timed events
433     */
434    @Override
435    public void setListener(ActionListener listener) {
436        _listener = listener;
437    }
438
439    /**
440     * Get Sound file.
441     */
442    @Override
443    public Sound getSound() {
444        return _sound;
445    }
446
447    /**
448     * Set the sound file.
449     *
450     * @param sound the new sound file
451     */
452    protected void setSound(Sound sound) {
453        _sound = sound;
454    }
455
456    /*
457     * Methods that return user interface strings ****
458     */
459
460    /**
461     * @return name of this consequent type
462     */
463    @Override
464    public String getTypeString() {
465        return _type.toString();
466    }
467
468    /**
469     * @return name of the option for this consequent type
470     */
471    @Override
472    public String getOptionString(boolean type) {
473        return getOptionString(_option, type);
474    }
475
476    @Override
477    public String getActionDataString() {
478        return getActionDataString(_type, _actionData);
479    }
480
481    /**
482     * Convert Variable Type to Text String.
483     *
484     * @.param t the Action type
485     * @.return a human readable description of the type or an empty String
486     *./
487    public static String getItemTypeString(int t) {
488        switch (t) {
489            case Conditional.ITEM_TYPE_SENSOR:
490                return (Bundle.getMessage("BeanNameSensor"));
491            case Conditional.ITEM_TYPE_TURNOUT:
492                return (Bundle.getMessage("BeanNameTurnout"));
493            case Conditional.ITEM_TYPE_LIGHT:
494                return (Bundle.getMessage("BeanNameLight"));
495            case Conditional.ITEM_TYPE_SIGNALHEAD:
496                return (Bundle.getMessage("BeanNameSignalHead"));
497            case Conditional.ITEM_TYPE_SIGNALMAST:
498                return (Bundle.getMessage("BeanNameSignalMast"));
499            case Conditional.ITEM_TYPE_MEMORY:
500                return (Bundle.getMessage("BeanNameMemory"));
501            case Conditional.ITEM_TYPE_LOGIX:
502                return (Bundle.getMessage("BeanNameLogix"));
503            case Conditional.ITEM_TYPE_WARRANT:
504                return (Bundle.getMessage("BeanNameWarrant"));
505            case Conditional.ITEM_TYPE_OBLOCK:
506                return (Bundle.getMessage("BeanNameOBlock"));
507            case Conditional.ITEM_TYPE_ENTRYEXIT:
508                return (Bundle.getMessage("BeanNameEntryExit"));
509            case Conditional.ITEM_TYPE_CLOCK:
510                return (Bundle.getMessage("FastClock"));
511            case Conditional.ITEM_TYPE_AUDIO:
512                return (Bundle.getMessage("BeanNameAudio"));
513            case Conditional.ITEM_TYPE_SCRIPT:
514                return (Bundle.getMessage("Script"));
515            case Conditional.ITEM_TYPE_OTHER:
516                return (rbx.getString("Other"));
517            default:
518                // fall through
519                break;
520        }
521        return "";
522    }
523*/
524    /**
525     * Convert Consequent Type to text String.
526     *
527     * @.param t the Action type
528     * @.return a human readable description of the type or an empty String
529     *./
530    public static String getActionTypeString(int t) {
531        switch (t) {
532            case Conditional.ACTION_NONE:
533                return (rbx.getString("ActionNone"));
534            case Conditional.ACTION_SET_TURNOUT:
535                return (rbx.getString("ActionSetTurnout"));
536            case Conditional.ACTION_SET_SIGNAL_APPEARANCE:
537                return (rbx.getString("ActionSetSignal"));
538            case Conditional.ACTION_SET_SIGNAL_HELD:
539                return (rbx.getString("ActionSetSignalHeld"));
540            case Conditional.ACTION_CLEAR_SIGNAL_HELD:
541                return (rbx.getString("ActionClearSignalHeld"));
542            case Conditional.ACTION_SET_SIGNAL_DARK:
543                return (rbx.getString("ActionSetSignalDark"));
544            case Conditional.ACTION_SET_SIGNAL_LIT:
545                return (rbx.getString("ActionSetSignalLit"));
546            case Conditional.ACTION_TRIGGER_ROUTE:
547                return (rbx.getString("ActionTriggerRoute"));
548            case Conditional.ACTION_SET_SENSOR:
549                return (rbx.getString("ActionSetSensor"));
550            case Conditional.ACTION_DELAYED_SENSOR:
551                return (rbx.getString("ActionDelayedSensor"));
552            case Conditional.ACTION_SET_LIGHT:
553                return (rbx.getString("ActionSetLight"));
554            case Conditional.ACTION_SET_MEMORY:
555                return (rbx.getString("ActionSetMemory"));
556            case Conditional.ACTION_ENABLE_LOGIX:
557                return (rbx.getString("ActionEnableLogix"));
558            case Conditional.ACTION_DISABLE_LOGIX:
559                return (rbx.getString("ActionDisableLogix"));
560            case Conditional.ACTION_PLAY_SOUND:
561                return (rbx.getString("ActionPlaySound"));
562            case Conditional.ACTION_RUN_SCRIPT:
563                return (rbx.getString("ActionRunScript"));
564            case Conditional.ACTION_DELAYED_TURNOUT:
565                return (rbx.getString("ActionDelayedTurnout"));
566            case Conditional.ACTION_LOCK_TURNOUT:
567                return (rbx.getString("ActionTurnoutLock"));
568            case Conditional.ACTION_RESET_DELAYED_SENSOR:
569                return (rbx.getString("ActionResetDelayedSensor"));
570            case Conditional.ACTION_CANCEL_SENSOR_TIMERS:
571                return (rbx.getString("ActionCancelSensorTimers"));
572            case Conditional.ACTION_RESET_DELAYED_TURNOUT:
573                return (rbx.getString("ActionResetDelayedTurnout"));
574            case Conditional.ACTION_CANCEL_TURNOUT_TIMERS:
575                return (rbx.getString("ActionCancelTurnoutTimers"));
576            case Conditional.ACTION_SET_FAST_CLOCK_TIME:
577                return (rbx.getString("ActionSetFastClockTime"));
578            case Conditional.ACTION_START_FAST_CLOCK:
579                return (rbx.getString("ActionStartFastClock"));
580            case Conditional.ACTION_STOP_FAST_CLOCK:
581                return (rbx.getString("ActionStopFastClock"));
582            case Conditional.ACTION_COPY_MEMORY:
583                return (rbx.getString("ActionCopyMemory"));
584            case Conditional.ACTION_SET_LIGHT_INTENSITY:
585                return (rbx.getString("ActionSetLightIntensity"));
586            case Conditional.ACTION_SET_LIGHT_TRANSITION_TIME:
587                return (rbx.getString("ActionSetLightTransitionTime"));
588            case Conditional.ACTION_CONTROL_AUDIO:
589                return (rbx.getString("ActionControlAudio"));
590            case Conditional.ACTION_JYTHON_COMMAND:
591                return (rbx.getString("ActionJythonCommand"));
592            case Conditional.ACTION_ALLOCATE_WARRANT_ROUTE:
593                return (rbx.getString("ActionAllocateWarrant"));
594            case Conditional.ACTION_DEALLOCATE_WARRANT_ROUTE:
595                return (rbx.getString("ActionDeallocateWarrant"));
596            case Conditional.ACTION_SET_ROUTE_TURNOUTS:
597                return (rbx.getString("ActionSetWarrantTurnouts"));
598            case Conditional.ACTION_AUTO_RUN_WARRANT:
599                return (rbx.getString("ActionAutoRunWarrant"));
600            case Conditional.ACTION_MANUAL_RUN_WARRANT:
601                return (rbx.getString("ActionManualRunWarrant"));
602            case Conditional.ACTION_CONTROL_TRAIN:
603                return (rbx.getString("ActionControlTrain"));
604            case Conditional.ACTION_SET_TRAIN_ID:
605                return (rbx.getString("ActionSetTrainId"));
606            case Conditional.ACTION_SET_TRAIN_NAME:
607                return (rbx.getString("ActionSetTrainName"));
608            case Conditional.ACTION_SET_SIGNALMAST_ASPECT:
609                return (rbx.getString("ActionSetSignalMastAspect"));
610            case Conditional.ACTION_THROTTLE_FACTOR:
611                return (rbx.getString("ActionSetThrottleFactor"));
612            case Conditional.ACTION_SET_SIGNALMAST_HELD:
613                return (rbx.getString("ActionSetSignalMastHeld"));
614            case Conditional.ACTION_CLEAR_SIGNALMAST_HELD:
615                return (rbx.getString("ActionClearSignalMastHeld"));
616            case Conditional.ACTION_SET_SIGNALMAST_DARK:
617                return (rbx.getString("ActionSetSignalMastDark"));
618            case Conditional.ACTION_SET_SIGNALMAST_LIT:
619                return (rbx.getString("ActionClearSignalMastDark"));
620            case Conditional.ACTION_SET_BLOCK_VALUE:
621                return (rbx.getString("ActionSetBlockValue"));
622            case Conditional.ACTION_SET_BLOCK_ERROR:
623                return (rbx.getString("ActionSetBlockError"));
624            case Conditional.ACTION_CLEAR_BLOCK_ERROR:
625                return (rbx.getString("ActionClearBlockError"));
626            case Conditional.ACTION_DEALLOCATE_BLOCK:
627                return (rbx.getString("ActionDeallocateBlock"));
628            case Conditional.ACTION_SET_BLOCK_OUT_OF_SERVICE:
629                return (rbx.getString("ActionSetBlockOutOfService"));
630            case Conditional.ACTION_SET_BLOCK_IN_SERVICE:
631                return (rbx.getString("ActionBlockInService"));
632            case Conditional.ACTION_SET_NXPAIR_ENABLED:
633                return (rbx.getString("ActionNXPairEnabled"));
634            case Conditional.ACTION_SET_NXPAIR_DISABLED:
635                return (rbx.getString("ActionNXPairDisabled"));
636            case Conditional.ACTION_SET_NXPAIR_SEGMENT:
637                return (rbx.getString("ActionNXPairSegment"));
638            default:
639                // fall through
640                break;
641        }
642        log.warn("Unexpected parameter to getActionTypeString({})", t);
643        return ("");
644    }
645*/
646    /**
647     * Convert consequent option to String.
648     *
649     * @param opt  the option
650     * @param type true if option is a change; false if option is a trigger
651     * @return a human readable description of the option or an empty String
652     */
653    public static String getOptionString(int opt, boolean type) {
654        switch (opt) {
655            case Conditional.ACTION_OPTION_ON_CHANGE_TO_TRUE:
656                if (type) {
657                    return (rbx.getString("OnChangeToTrue"));
658                } else {
659                    return (rbx.getString("OnTriggerToTrue"));
660                }
661            case Conditional.ACTION_OPTION_ON_CHANGE_TO_FALSE:
662                if (type) {
663                    return (rbx.getString("OnChangeToFalse"));
664                } else {
665                    return (rbx.getString("OnTriggerToFalse"));
666                }
667            case Conditional.ACTION_OPTION_ON_CHANGE:
668                if (type) {
669                    return (rbx.getString("OnChange"));
670                } else {
671                    return (rbx.getString("OnTrigger"));
672                }
673            default:
674                // fall through
675                break;
676        }
677        log.warn("Unexpected parameter to getOptionString({})", opt);
678        return "";
679    }
680
681    /**
682     * Get action type from a String.
683     *
684     * @param str the string to get the type for
685     * @return the type or 0 if str is not a recognized action
686     */
687    public static Conditional.Action stringToActionType(String str) {
688        if (str != null) {
689            for (Conditional.Action action : Conditional.Action.values()) {
690                if (str.equals(action.toString())) {
691                    return action;
692                }
693            }
694        }
695        log.warn("Unexpected parameter to stringToActionType({})", str);
696        return Conditional.Action.NONE;
697    }
698
699    /**
700     * Get action Data from a String.
701     *
702     * @param str the string to get the action data for
703     * @return the action data of -1 is str is not recognized
704     */
705    public static int stringToActionData(String str) {
706        if (str.equals(Bundle.getMessage("TurnoutStateClosed"))) {
707            return Turnout.CLOSED;
708        } else if (str.equals(Bundle.getMessage("TurnoutStateThrown"))) {
709            return Turnout.THROWN;
710        } else if (str.equals(Bundle.getMessage("SensorStateActive"))) {
711            return Sensor.ACTIVE;
712        } else if (str.equals(Bundle.getMessage("SensorStateInactive"))) {
713            return Sensor.INACTIVE;
714        } else if (str.equals(rbx.getString("LightOn"))) {
715            return Light.ON;
716        } else if (str.equals(rbx.getString("LightOff"))) {
717            return Light.OFF;
718        } else if (str.equals(rbx.getString("TurnoutUnlock"))) {
719            return Turnout.UNLOCKED;
720        } else if (str.equals(rbx.getString("TurnoutLock"))) {
721            return Turnout.LOCKED;
722        } else if (str.equals(Bundle.getMessage("SignalHeadStateRed"))) {
723            return SignalHead.RED;
724        } else if (str.equals(Bundle.getMessage("SignalHeadStateYellow"))) {
725            return SignalHead.YELLOW;
726        } else if (str.equals(Bundle.getMessage("SignalHeadStateGreen"))) {
727            return SignalHead.GREEN;
728        } else if (str.equals(Bundle.getMessage("SignalHeadStateDark"))) {
729            return SignalHead.DARK;
730        } else if (str.equals(Bundle.getMessage("SignalHeadStateFlashingRed"))) {
731            return SignalHead.FLASHRED;
732        } else if (str.equals(Bundle.getMessage("SignalHeadStateFlashingYellow"))) {
733            return SignalHead.FLASHYELLOW;
734        } else if (str.equals(Bundle.getMessage("SignalHeadStateFlashingGreen"))) {
735            return SignalHead.FLASHGREEN;
736        } else if (str.equals(Bundle.getMessage("SignalHeadStateLunar"))) {
737            return SignalHead.LUNAR;
738        } else if (str.equals(Bundle.getMessage("SignalHeadStateFlashingLunar"))) {
739            return SignalHead.FLASHLUNAR;
740        } else if (str.equals(rbx.getString("AudioSourcePlay"))) {
741            return Audio.CMD_PLAY;
742        } else if (str.equals(rbx.getString("AudioSourceStop"))) {
743            return Audio.CMD_STOP;
744        } else if (str.equals(rbx.getString("AudioSourcePlayToggle"))) {
745            return Audio.CMD_PLAY_TOGGLE;
746        } else if (str.equals(rbx.getString("AudioSourcePause"))) {
747            return Audio.CMD_PAUSE;
748        } else if (str.equals(rbx.getString("AudioSourceResume"))) {
749            return Audio.CMD_RESUME;
750        } else if (str.equals(rbx.getString("AudioSourcePauseToggle"))) {
751            return Audio.CMD_PAUSE_TOGGLE;
752        } else if (str.equals(rbx.getString("AudioSourceRewind"))) {
753            return Audio.CMD_REWIND;
754        } else if (str.equals(rbx.getString("AudioSourceFadeIn"))) {
755            return Audio.CMD_FADE_IN;
756        } else if (str.equals(rbx.getString("AudioSourceFadeOut"))) {
757            return Audio.CMD_FADE_OUT;
758        } else if (str.equals(rbx.getString("AudioResetPosition"))) {
759            return Audio.CMD_RESET_POSITION;
760        }
761        // empty strings can occur frequently with types that have no integer data
762        if (str.length() > 0) {
763            log.warn("Unexpected parameter to stringToActionData({})", str);
764        }
765        return -1;
766    }
767
768    public static String getActionDataString(Conditional.Action t, int data) {
769        switch (t) {
770            case SET_TURNOUT:
771            case DELAYED_TURNOUT:
772            case RESET_DELAYED_TURNOUT:
773                if (data == Turnout.CLOSED) {
774                    return (Bundle.getMessage("TurnoutStateClosed"));
775                } else if (data == Turnout.THROWN) {
776                    return (Bundle.getMessage("TurnoutStateThrown"));
777                } else if (data == Route.TOGGLE) {
778                    return (Bundle.getMessage("Toggle"));
779                }
780                break;
781            case SET_SIGNAL_APPEARANCE:
782                return DefaultSignalHead.getDefaultStateName(data);
783            case SET_SENSOR:
784            case DELAYED_SENSOR:
785            case RESET_DELAYED_SENSOR:
786                if (data == Sensor.ACTIVE) {
787                    return (Bundle.getMessage("SensorStateActive"));
788                } else if (data == Sensor.INACTIVE) {
789                    return (Bundle.getMessage("SensorStateInactive"));
790                } else if (data == Route.TOGGLE) {
791                    return (Bundle.getMessage("Toggle"));
792                }
793                break;
794            case SET_LIGHT:
795                if (data == Light.ON) {
796                    return (rbx.getString("LightOn"));
797                } else if (data == Light.OFF) {
798                    return (rbx.getString("LightOff"));
799                } else if (data == Route.TOGGLE) {
800                    return (Bundle.getMessage("Toggle"));
801                }
802                break;
803            case LOCK_TURNOUT:
804                if (data == Turnout.UNLOCKED) {
805                    return (rbx.getString("TurnoutUnlock"));
806                } else if (data == Turnout.LOCKED) {
807                    return (rbx.getString("TurnoutLock"));
808                } else if (data == Route.TOGGLE) {
809                    return (Bundle.getMessage("Toggle"));
810                }
811                break;
812            case CONTROL_AUDIO:
813                switch (data) {
814                    case Audio.CMD_PLAY:
815                        return (rbx.getString("AudioSourcePlay"));
816                    case Audio.CMD_STOP:
817                        return (rbx.getString("AudioSourceStop"));
818                    case Audio.CMD_PLAY_TOGGLE:
819                        return (rbx.getString("AudioSourcePlayToggle"));
820                    case Audio.CMD_PAUSE:
821                        return (rbx.getString("AudioSourcePause"));
822                    case Audio.CMD_RESUME:
823                        return (rbx.getString("AudioSourceResume"));
824                    case Audio.CMD_PAUSE_TOGGLE:
825                        return (rbx.getString("AudioSourcePauseToggle"));
826                    case Audio.CMD_REWIND:
827                        return (rbx.getString("AudioSourceRewind"));
828                    case Audio.CMD_FADE_IN:
829                        return (rbx.getString("AudioSourceFadeIn"));
830                    case Audio.CMD_FADE_OUT:
831                        return (rbx.getString("AudioSourceFadeOut"));
832                    case Audio.CMD_RESET_POSITION:
833                        return (rbx.getString("AudioResetPosition"));
834                    default:
835                        log.error("Unhandled Audio operation command: {}", data);
836                        break;
837                }
838                break;
839            case CONTROL_TRAIN:
840                switch (data) {
841                    case Warrant.HALT:
842                        return (rbx.getString("WarrantHalt"));
843                    case Warrant.RESUME:
844                        return (rbx.getString("WarrantResume"));
845                    case Warrant.RETRY_FWD:
846                        return (rbx.getString("WarrantMoveToNext"));
847                    case Warrant.SPEED_UP:
848                        return (rbx.getString("WarrantSpeedUp"));
849                    case Warrant.STOP:
850                        return (rbx.getString("WarrantStop"));
851                    case Warrant.ESTOP:
852                        return (rbx.getString("WarrantEStop"));
853                    case Warrant.ABORT:
854                        return (rbx.getString("WarrantAbort"));
855                    default:
856                        log.error("Unhandled Warrant control: {}", data);
857                }
858                break;
859            default:
860                // fall through
861                break;
862        }
863        return "";
864    }
865
866    @Override
867    public String description(boolean triggerType) {
868        String str = getOptionString(triggerType) + ", " + getTypeString();
869        if (_deviceName.length() > 0) {
870            switch (_type) {
871                case CANCEL_TURNOUT_TIMERS:
872                case SET_SIGNAL_HELD:
873                case CLEAR_SIGNAL_HELD:
874                case SET_SIGNAL_DARK:
875                case SET_SIGNAL_LIT:
876                case TRIGGER_ROUTE:
877                case CANCEL_SENSOR_TIMERS:
878                case SET_MEMORY:
879                case ENABLE_LOGIX:
880                case DISABLE_LOGIX:
881                case COPY_MEMORY:
882                case SET_LIGHT_INTENSITY:
883                case SET_LIGHT_TRANSITION_TIME:
884                case ALLOCATE_WARRANT_ROUTE:
885                case DEALLOCATE_WARRANT_ROUTE:
886                case SET_SIGNALMAST_HELD:
887                case CLEAR_SIGNALMAST_HELD:
888                case SET_SIGNALMAST_DARK:
889                case SET_SIGNALMAST_LIT:
890                case SET_BLOCK_ERROR:
891                case CLEAR_BLOCK_ERROR:
892                case DEALLOCATE_BLOCK:
893                case SET_BLOCK_OUT_OF_SERVICE:
894                case SET_BLOCK_IN_SERVICE:
895                    str = str + ", \"" + _deviceName + "\".";
896                    break;
897                case SET_NXPAIR_ENABLED:
898                case SET_NXPAIR_DISABLED:
899                case SET_NXPAIR_SEGMENT:
900                    str = str + ", \"" + getBean().getUserName() + "\".";
901                    break;
902                case SET_ROUTE_TURNOUTS:
903                case AUTO_RUN_WARRANT:
904                case MANUAL_RUN_WARRANT:
905                    str = str + " " + rbx.getString("onWarrant") + ", \"" + _deviceName + "\".";
906                    break;
907                case SET_SENSOR:
908                case SET_TURNOUT:
909                case SET_LIGHT:
910                case LOCK_TURNOUT:
911                case RESET_DELAYED_SENSOR:
912                case SET_SIGNAL_APPEARANCE:
913                case RESET_DELAYED_TURNOUT:
914                case DELAYED_TURNOUT:
915                case DELAYED_SENSOR:
916                case CONTROL_AUDIO:
917                    str = str + ", \"" + _deviceName + "\" " + rbx.getString("to")
918                            + " " + getActionDataString();
919                    break;
920                case GET_TRAIN_LOCATION:
921                case GET_BLOCK_WARRANT:
922                case GET_BLOCK_TRAIN_NAME:
923                    str = str + " \"" + _deviceName + "\" " + rbx.getString("intoMemory")
924                              + " " + _actionString;
925                    break;
926                case SET_SIGNALMAST_ASPECT:
927                    str = str + ", \"" + _deviceName + "\" " + rbx.getString("to")
928                            + " " + _actionString;
929                    break;
930                case CONTROL_TRAIN:
931                    str = str + " " + rbx.getString("onWarrant") + " \"" + _deviceName + "\" "
932                            + rbx.getString("to") + " " + getActionDataString();
933                    break;
934                default:
935                    break; // nothing needed for others
936            }
937        }
938        if (_actionString.length() > 0) {
939            switch (_type) {
940                case SET_MEMORY:
941                case COPY_MEMORY:
942                    str = str + " " + rbx.getString("to") + " " + _actionString + ".";
943                    break;
944                case PLAY_SOUND:
945                case RUN_SCRIPT:
946                    str = str + " " + rbx.getString("FromFile") + " " + _actionString + ".";
947                    break;
948                case RESET_DELAYED_TURNOUT:
949                case RESET_DELAYED_SENSOR:
950                case DELAYED_TURNOUT:
951                case DELAYED_SENSOR:
952                    str = str + rbx.getString("After") + " ";
953                    try {
954                        Float.parseFloat(_actionString);
955                        str = str + _actionString + " " + rbx.getString("Seconds") + ".";
956                    } catch (NumberFormatException nfe) {
957                        str = str + _actionString + " " + rbx.getString("ValueInMemory")
958                                + " " + rbx.getString("Seconds") + ".";
959                    }
960                    break;
961                case SET_LIGHT_TRANSITION_TIME:
962                case SET_LIGHT_INTENSITY:
963                    try {
964                        //int t = Integer.parseInt(_actionString);
965                        str = str + " " + rbx.getString("to") + " " + _actionString + ".";
966                    } catch (NumberFormatException nfe) {
967                        str = str + " " + rbx.getString("to") + " " + _actionString + " "
968                                + rbx.getString("ValueInMemory") + ".";
969                    }
970                    break;
971                case JYTHON_COMMAND:
972                    str = str + " " + rbx.getString("ExecJythonCmd") + " " + _actionString + ".";
973                    break;
974                case SET_TRAIN_ID:
975                case SET_TRAIN_NAME:
976                    str = str + ", \"" + _actionString + "\" " + rbx.getString("onWarrant")
977                            + " \"" + _deviceName + "\".";
978                    break;
979                case SET_BLOCK_VALUE:
980                    str = str + ", \"" + _actionString + "\" " + rbx.getString("onBlock")
981                            + " \"" + _deviceName + "\".";
982                    break;
983                default:
984                    break; // nothing needed for others
985            }
986        }
987        switch (_type) {
988            case SET_LIGHT_INTENSITY:
989            case SET_LIGHT_TRANSITION_TIME:
990                str = str + " " + rbx.getString("to") + " " + _actionData + ".";
991                break;
992            case SET_FAST_CLOCK_TIME:
993                str = str + " " + rbx.getString("to") + " "
994                        + LogixTableAction.formatTime(_actionData / 60, _actionData - ((_actionData / 60) * 60));
995                break;
996            default:
997                break; // nothing needed for others
998        }
999        return str;
1000    }
1001
1002    /** {@inheritDoc} */
1003    @Override
1004    public void dispose() {
1005        if (_sound != null) {
1006            _sound.dispose();
1007        }
1008    }
1009
1010    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultConditionalAction.class);
1011
1012}