001package jmri.jmrit.ctc;
002
003import java.awt.event.ActionListener;
004import java.beans.PropertyChangeListener;
005import javax.swing.Timer;
006import jmri.Sensor;
007
008/**
009 *
010 * @author Gregory J. Bedlek Copyright (C) 2018, 2019
011 *
012 * This module will "simulate" a code button press when there is none.
013 *
014 * It will delay the simulated pressing of a code button for a duration
015 * specified in the constructor, so that the user can change multiple items
016 * on the CTC panel (ONLY in this O.S. section) before the "code is sent to the field".
017 */
018public class CodeButtonSimulator {
019    private final NBHSensor _mCodeButtonSensor;
020    private final NBHSensor _mSwitchLeverSensor;
021    private final NBHSensor _mLeftSensor;
022    private final NBHSensor _mNormalSensor;
023    private final NBHSensor _mRightSensor;
024    private final NBHSensor _mDispatcherSensorLockToggle;
025    private final PropertyChangeListener _mAnySensorPropertyChangeListener;
026    private final Timer _mPauseTimer;
027    private final ActionListener _mPauseActionListener;
028
029    public CodeButtonSimulator() {
030        // Used to satisfy test requirement
031        _mCodeButtonSensor = null;
032        _mSwitchLeverSensor = null;
033        _mLeftSensor = null;
034        _mNormalSensor = null;
035        _mRightSensor = null;
036        _mDispatcherSensorLockToggle = null;
037        _mAnySensorPropertyChangeListener = null;
038        _mPauseTimer = null;
039        _mPauseActionListener = null;
040    }
041
042    public CodeButtonSimulator( int                     pauseTimeInMilliseconds,
043                                NBHSensor               codeButtonSensor,
044                                SwitchDirectionLever    switchDirectionLever,
045                                SignalDirectionLever    signalDirectionLever,
046                                TurnoutLock             turnoutLock) {
047        _mCodeButtonSensor = codeButtonSensor;
048        if (switchDirectionLever != null) {
049            _mSwitchLeverSensor = switchDirectionLever.getSwitchLeverSensor();
050        } else { // None, create "fake" one:
051            _mSwitchLeverSensor = new NBHSensor("", "", "", "", true);
052        }
053        if (signalDirectionLever != null) {
054            SignalDirectionLever.LNR_NBHSensors Sensors = signalDirectionLever.getLevers();
055            _mLeftSensor = Sensors._mLeftSensor;
056            _mNormalSensor = Sensors._mNormalSensor;
057            _mRightSensor = Sensors._mRightSensor;
058        } else {
059            _mLeftSensor = new NBHSensor("", "", "", "", true);
060            _mNormalSensor = new NBHSensor("", "", "", "", true);
061            _mRightSensor = new NBHSensor("", "", "", "", true);
062        }
063        if (turnoutLock != null) {
064            _mDispatcherSensorLockToggle = turnoutLock.getDispatcherSensorLockToggle();
065        } else {
066            _mDispatcherSensorLockToggle = new NBHSensor("", "", "", "", true);
067        }
068
069        _mAnySensorPropertyChangeListener = (PropertyChangeEvent) -> { anySensorPropertyChangeEvent(); };
070        _mSwitchLeverSensor.addPropertyChangeListener(_mAnySensorPropertyChangeListener);
071        _mLeftSensor.addPropertyChangeListener(_mAnySensorPropertyChangeListener);
072        _mNormalSensor.addPropertyChangeListener(_mAnySensorPropertyChangeListener);
073        _mRightSensor.addPropertyChangeListener(_mAnySensorPropertyChangeListener);
074        _mDispatcherSensorLockToggle.addPropertyChangeListener(_mAnySensorPropertyChangeListener);
075        _mPauseActionListener = (ActionEvent) -> { pauseActionListener(); };
076        _mPauseTimer = new Timer(pauseTimeInMilliseconds, _mPauseActionListener);
077        _mPauseTimer.setRepeats(false);
078    }
079
080    public void removeAllListeners() {
081        _mSwitchLeverSensor.removePropertyChangeListener(_mAnySensorPropertyChangeListener);
082        _mLeftSensor.removePropertyChangeListener(_mAnySensorPropertyChangeListener);
083        _mNormalSensor.removePropertyChangeListener(_mAnySensorPropertyChangeListener);
084        _mRightSensor.removePropertyChangeListener(_mAnySensorPropertyChangeListener);
085        _mDispatcherSensorLockToggle.removePropertyChangeListener(_mAnySensorPropertyChangeListener);
086        _mPauseTimer.stop();
087        _mPauseTimer.removeActionListener(_mPauseActionListener);
088    }
089
090    private void pauseActionListener() {
091        _mPauseTimer.stop();    // Probably already so since it fired and their are no repeats, so it doesn't hurt to do this again in case some idiot wants repeats.....
092        _mCodeButtonSensor.setKnownState(Sensor.ACTIVE);    // Cause events to be fired as if code button pressed.
093        _mCodeButtonSensor.setKnownState(Sensor.INACTIVE);  // Reset it so that can happen again!
094    }
095
096//  If the timer is already running due to some other event prior to us being triggered "in parallel" with our event
097//  (i.e. within the pause time interval), then we do nothing here:
098    private void anySensorPropertyChangeEvent() {
099        if (_mPauseTimer.isRunning()) return;   // Nothing more, within the timer window.
100        _mPauseTimer.start();                   // That's it.
101    }
102}