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.SocketAlreadyConnectedException;
013import jmri.jmrit.logixng.DigitalExpressionManager;
014import jmri.jmrit.logixng.FemaleDigitalExpressionSocket;
015import jmri.jmrit.logixng.MaleSocket;
016
017/**
018 * An Expression that returns True only once while its child expression returns
019 * True.
020 * <P>
021 * The first time the child expression returns True, this expression returns
022 * True. After that, this expression returns False until the child expression
023 * returns False and again returns True.
024 * 
025 * @author Daniel Bergqvist Copyright 2018
026 */
027public class TriggerOnce extends AbstractDigitalExpression implements FemaleSocketListener {
028
029    private String _childExpressionSystemName;
030    private final FemaleDigitalExpressionSocket _childExpression;
031    private boolean _childLastState = false;
032    
033    
034    public TriggerOnce(String sys, String user) {
035        
036        super(sys, user);
037        
038        _childExpression = InstanceManager.getDefault(DigitalExpressionManager.class)
039                .createFemaleSocket(this, this, "E");
040    }
041    
042    @Override
043    public Base getDeepCopy(Map<String, String> systemNames, Map<String, String> userNames) throws JmriException {
044        DigitalExpressionManager manager = InstanceManager.getDefault(DigitalExpressionManager.class);
045        String sysName = systemNames.get(getSystemName());
046        String userName = userNames.get(getSystemName());
047        if (sysName == null) sysName = manager.getAutoSystemName();
048        TriggerOnce copy = new TriggerOnce(sysName, userName);
049        copy.setComment(getComment());
050        return manager.registerExpression(copy).deepCopyChildren(this, systemNames, userNames);
051    }
052    
053    /** {@inheritDoc} */
054    @Override
055    public Category getCategory() {
056        return Category.OTHER;
057    }
058    
059    /** {@inheritDoc} */
060    @Override
061    public boolean evaluate() throws JmriException {
062        if (_childExpression.evaluate() && !_childLastState) {
063            _childLastState = true;
064            return true;
065        }
066        _childLastState = _childExpression.evaluate();
067        return false;
068    }
069
070    @Override
071    public FemaleSocket getChild(int index) throws IllegalArgumentException, UnsupportedOperationException {
072        if (index == 0) {
073            return _childExpression;
074        } else {
075                throw new IllegalArgumentException(
076                        String.format("index has invalid value: %d", index));
077        }
078    }
079
080    @Override
081    public int getChildCount() {
082        return 1;
083    }
084    
085    @Override
086    public void connected(FemaleSocket socket) {
087        if (socket == _childExpression) {
088            _childExpressionSystemName = socket.getConnectedSocket().getSystemName();
089        } else {
090            throw new IllegalArgumentException("unkown socket");
091        }
092    }
093    
094    @Override
095    public void disconnected(FemaleSocket socket) {
096        if (socket == _childExpression) {
097            _childExpressionSystemName = null;
098        } else {
099            throw new IllegalArgumentException("unkown socket");
100        }
101    }
102
103    @Override
104    public String getShortDescription(Locale locale) {
105        return Bundle.getMessage(locale, "TriggerOnce_Short");
106    }
107    
108    @Override
109    public String getLongDescription(Locale locale) {
110        return Bundle.getMessage(locale, "TriggerOnce_Long");
111    }
112
113    public String getChildSocketSystemName() {
114        return _childExpressionSystemName;
115    }
116
117    public void setChildSocketSystemName(String systemName) {
118        _childExpressionSystemName = systemName;
119    }
120
121    /** {@inheritDoc} */
122    @Override
123    public void setup() {
124        try {
125            if ( !_childExpression.isConnected()
126                    || !_childExpression.getConnectedSocket().getSystemName()
127                            .equals(_childExpressionSystemName)) {
128                
129                String socketSystemName = _childExpressionSystemName;
130                _childExpression.disconnect();
131                if (socketSystemName != null) {
132                    MaleSocket maleSocket =
133                            InstanceManager.getDefault(DigitalExpressionManager.class)
134                                    .getBySystemName(socketSystemName);
135                    if (maleSocket != null) {
136                        _childExpression.connect(maleSocket);
137                        maleSocket.setup();
138                    } else {
139                        log.error("cannot load digital expression {}", socketSystemName);
140                    }
141                }
142            } else {
143                _childExpression.getConnectedSocket().setup();
144            }
145        } catch (SocketAlreadyConnectedException ex) {
146            // This shouldn't happen and is a runtime error if it does.
147            throw new RuntimeException("socket is already connected");
148        }
149    }
150    
151    /** {@inheritDoc} */
152    @Override
153    public void registerListenersForThisClass() {
154    }
155    
156    /** {@inheritDoc} */
157    @Override
158    public void unregisterListenersForThisClass() {
159    }
160    
161    /** {@inheritDoc} */
162    @Override
163    public void disposeMe() {
164    }
165
166    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TriggerOnce.class);
167
168}