001package jmri.jmrit.logixng.actions;
002
003import java.util.*;
004
005import jmri.InstanceManager;
006import jmri.JmriException;
007import jmri.jmrit.logixng.*;
008
009/**
010 * Executes an action only one time.
011 *
012 * @author Daniel Bergqvist Copyright 2022
013 */
014public class RunOnce extends AbstractDigitalAction
015        implements FemaleSocketListener {
016
017    private String _socketSystemName;
018    private final FemaleDigitalActionSocket _socket;
019    private boolean _hasExecuted = false;
020
021    public RunOnce(String sys, String user) {
022        super(sys, user);
023        _socket = InstanceManager.getDefault(DigitalActionManager.class)
024                .createFemaleSocket(this, this, Bundle.getMessage("RunOnce_Socket_Action"));
025    }
026
027    public RunOnce(String sys, String user, String socketName, String socketSystemName)
028            throws BadUserNameException, BadSystemNameException {
029        super(sys, user);
030        _socket = InstanceManager.getDefault(DigitalActionManager.class)
031                .createFemaleSocket(this, this, socketName);
032        _socketSystemName = socketSystemName;
033    }
034
035    @Override
036    public Base getDeepCopy(Map<String, String> systemNames, Map<String, String> userNames) throws JmriException {
037        DigitalActionManager manager = InstanceManager.getDefault(DigitalActionManager.class);
038        String sysName = systemNames.get(getSystemName());
039        String userName = userNames.get(getSystemName());
040        if (sysName == null) sysName = manager.getAutoSystemName();
041        RunOnce copy = new RunOnce(sysName, userName);
042        copy.setComment(getComment());
043        return manager.registerAction(copy).deepCopyChildren(this, systemNames, userNames);
044    }
045
046    /** {@inheritDoc} */
047    @Override
048    public Category getCategory() {
049        return Category.FLOW_CONTROL;
050    }
051
052    /** {@inheritDoc} */
053    @Override
054    public void execute() throws JmriException {
055        if (!_hasExecuted && _socket != null) {
056            _socket.execute();
057        }
058        _hasExecuted = true;
059    }
060
061    @Override
062    public FemaleSocket getChild(int index) throws IllegalArgumentException, UnsupportedOperationException {
063        if (index == 0) {
064            return _socket;
065        } else {
066            throw new IllegalArgumentException(String.format("index has invalid value: %d", index));
067        }
068    }
069
070    @Override
071    public int getChildCount() {
072        return 1;
073    }
074
075    @Override
076    public void connected(FemaleSocket socket) {
077        if (socket == this._socket) {
078            this._socketSystemName = socket.getConnectedSocket().getSystemName();
079        }
080    }
081
082    @Override
083    public void disconnected(FemaleSocket socket) {
084        if (socket == this._socket) {
085            this._socketSystemName = null;
086        }
087    }
088
089    @Override
090    public String getShortDescription(Locale locale) {
091        return Bundle.getMessage(locale, "RunOnce_Short");
092    }
093
094    @Override
095    public String getLongDescription(Locale locale) {
096        return Bundle.getMessage(locale, "RunOnce_Long");
097    }
098
099    public FemaleDigitalActionSocket getSocket() {
100        return _socket;
101    }
102
103    public String getSocketSystemName() {
104        return _socketSystemName;
105    }
106
107    public void setSocketSystemName(String systemName) {
108        _socketSystemName = systemName;
109    }
110
111    /** {@inheritDoc} */
112    @Override
113    public void setup() {
114        try {
115            if ( !_socket.isConnected()
116                    || !_socket.getConnectedSocket().getSystemName()
117                            .equals(_socketSystemName)) {
118
119                String socketSystemName = _socketSystemName;
120                _socket.disconnect();
121                if (socketSystemName != null) {
122                    MaleSocket maleSocket =
123                            InstanceManager.getDefault(DigitalActionManager.class)
124                                    .getBySystemName(socketSystemName);
125                    _socket.disconnect();
126                    if (maleSocket != null) {
127                        _socket.connect(maleSocket);
128                        maleSocket.setup();
129                    } else {
130                        log.error("cannot load digital action {}", socketSystemName);
131                    }
132                }
133            } else {
134                _socket.getConnectedSocket().setup();
135            }
136        } catch (SocketAlreadyConnectedException ex) {
137            // This shouldn't happen and is a runtime error if it does.
138            throw new RuntimeException("socket is already connected");
139        }
140    }
141
142
143    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(RunOnce.class);
144
145}