001package jmri.jmrit.logixng.expressions;
002
003import java.util.Locale;
004import java.util.Map;
005
006import jmri.InstanceManager;
007import jmri.JmriException;
008import jmri.jmrit.logixng.Base;
009import jmri.jmrit.logixng.Category;
010import jmri.jmrit.logixng.FemaleSocket;
011import jmri.jmrit.logixng.FemaleSocketListener;
012import jmri.jmrit.logixng.DigitalExpressionManager;
013import jmri.jmrit.logixng.FemaleDigitalExpressionSocket;
014import jmri.jmrit.logixng.MaleSocket;
015import jmri.jmrit.logixng.SocketAlreadyConnectedException;
016
017/**
018 * An Expression that keeps its status even if its child expression doesn't.
019 * 
020 * This expression stays False until both the 'hold' expression and the 'trigger'
021 * expression becomes True. It stays true until the 'hold' expression goes to
022 * False. The 'trigger' expression can for example be a push button that stays
023 * True for a short time.
024 * 
025 * @author Daniel Bergqvist Copyright 2018
026 */
027public class Hold extends AbstractDigitalExpression implements FemaleSocketListener {
028
029    private String _triggerExpressionSocketSystemName;
030    private String _holdExpressionSocketSystemName;
031    private final FemaleDigitalExpressionSocket _triggerExpressionSocket;
032    private final FemaleDigitalExpressionSocket _holdExpressionSocket;
033    private boolean _isActive = false;
034    
035    public Hold(String sys, String user)
036            throws BadUserNameException, BadSystemNameException {
037        
038        super(sys, user);
039        
040        _triggerExpressionSocket = InstanceManager.getDefault(DigitalExpressionManager.class)
041                .createFemaleSocket(this, this, Bundle.getMessage("Hold_SocketName_Trigger"));
042        _holdExpressionSocket = InstanceManager.getDefault(DigitalExpressionManager.class)
043                .createFemaleSocket(this, this, Bundle.getMessage("Hold_SocketName_Hold"));
044    }
045    
046    @Override
047    public Base getDeepCopy(Map<String, String> systemNames, Map<String, String> userNames) throws JmriException {
048        DigitalExpressionManager manager = InstanceManager.getDefault(DigitalExpressionManager.class);
049        String sysName = systemNames.get(getSystemName());
050        String userName = userNames.get(getSystemName());
051        if (sysName == null) sysName = manager.getAutoSystemName();
052        Hold copy = new Hold(sysName, userName);
053        copy.setComment(getComment());
054        return manager.registerExpression(copy).deepCopyChildren(this, systemNames, userNames);
055    }
056    
057    /** {@inheritDoc} */
058    @Override
059    public Category getCategory() {
060        return Category.OTHER;
061    }
062    
063    /** {@inheritDoc} */
064    @Override
065    public boolean evaluate() throws JmriException {
066        if (_isActive) {
067            _isActive = _holdExpressionSocket.evaluate()
068                    || _triggerExpressionSocket.evaluate();
069        } else {
070            _isActive = _triggerExpressionSocket.evaluate();
071        }
072        return _isActive;
073    }
074    
075    @Override
076    public FemaleSocket getChild(int index) throws IllegalArgumentException, UnsupportedOperationException {
077        switch (index) {
078            case 0:
079                return _triggerExpressionSocket;
080                
081            case 1:
082                return _holdExpressionSocket;
083                
084            default:
085                throw new IllegalArgumentException(
086                        String.format("index has invalid value: %d", index));
087        }
088    }
089
090    @Override
091    public int getChildCount() {
092        return 2;
093    }
094    
095    @Override
096    public void connected(FemaleSocket socket) {
097        if (socket == _triggerExpressionSocket) {
098            _triggerExpressionSocketSystemName = socket.getConnectedSocket().getSystemName();
099        } else if (socket == _holdExpressionSocket) {
100            _holdExpressionSocketSystemName = socket.getConnectedSocket().getSystemName();
101        } else {
102            throw new IllegalArgumentException("unkown socket");
103        }
104    }
105    
106    @Override
107    public void disconnected(FemaleSocket socket) {
108        if (socket == _triggerExpressionSocket) {
109            _triggerExpressionSocketSystemName = null;
110        } else if (socket == _holdExpressionSocket) {
111            _holdExpressionSocketSystemName = null;
112        } else {
113            throw new IllegalArgumentException("unkown socket");
114        }
115    }
116    
117    @Override
118    public String getShortDescription(Locale locale) {
119        return Bundle.getMessage(locale, "Hold_Short");
120    }
121    
122    @Override
123    public String getLongDescription(Locale locale) {
124        return Bundle.getMessage(locale, "Hold_Long",
125                _triggerExpressionSocket.getName(),
126                _holdExpressionSocket.getName());
127    }
128
129    public String getTriggerExpressionSocketSystemName() {
130        return _triggerExpressionSocketSystemName;
131    }
132
133    public void setTriggerExpressionSocketSystemName(String systemName) {
134        _triggerExpressionSocketSystemName = systemName;
135    }
136
137    public String getHoldActionSocketSystemName() {
138        return _holdExpressionSocketSystemName;
139    }
140
141    public void setHoldActionSocketSystemName(String systemName) {
142        _holdExpressionSocketSystemName = systemName;
143    }
144
145    /** {@inheritDoc} */
146    @Override
147    public void setup() {
148        try {
149            if ( !_triggerExpressionSocket.isConnected()
150                    || !_triggerExpressionSocket.getConnectedSocket().getSystemName()
151                            .equals(_triggerExpressionSocketSystemName)) {
152                
153                String socketSystemName = _triggerExpressionSocketSystemName;
154                _triggerExpressionSocket.disconnect();
155                if (socketSystemName != null) {
156                    MaleSocket maleSocket =
157                            InstanceManager.getDefault(DigitalExpressionManager.class)
158                                    .getBySystemName(socketSystemName);
159                    _triggerExpressionSocket.disconnect();
160                    if (maleSocket != null) {
161                        _triggerExpressionSocket.connect(maleSocket);
162                        maleSocket.setup();
163                    } else {
164                        log.error("cannot load digital expression {}", socketSystemName);
165                    }
166                }
167            } else {
168                _triggerExpressionSocket.getConnectedSocket().setup();
169            }
170            
171            if ( !_holdExpressionSocket.isConnected()
172                    || !_holdExpressionSocket.getConnectedSocket().getSystemName()
173                            .equals(_holdExpressionSocketSystemName)) {
174                
175                String socketSystemName = _holdExpressionSocketSystemName;
176                _holdExpressionSocket.disconnect();
177                if (socketSystemName != null) {
178                    MaleSocket maleSocket =
179                            InstanceManager.getDefault(DigitalExpressionManager.class)
180                                    .getBySystemName(socketSystemName);
181                    if (maleSocket != null) {
182                        _holdExpressionSocket.connect(maleSocket);
183                        maleSocket.setup();
184                    } else {
185                        log.error("cannot load digital expression {}", socketSystemName);
186                    }
187                }
188            } else {
189                _holdExpressionSocket.getConnectedSocket().setup();
190            }
191        } catch (SocketAlreadyConnectedException ex) {
192            // This shouldn't happen and is a runtime error if it does.
193            throw new RuntimeException("socket is already connected");
194        }
195    }
196
197    /** {@inheritDoc} */
198    @Override
199    public void registerListenersForThisClass() {
200        // Do nothing
201    }
202
203    /** {@inheritDoc} */
204    @Override
205    public void unregisterListenersForThisClass() {
206        // Do nothing
207    }
208    
209    /** {@inheritDoc} */
210    @Override
211    public void disposeMe() {
212    }
213
214    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(Hold.class);
215
216}