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