001package jmri.jmrit.logixng.actions;
002
003import java.beans.*;
004import java.io.*;
005import java.util.*;
006
007import jmri.*;
008import jmri.jmrit.logixng.*;
009import jmri.jmrit.logixng.util.*;
010import jmri.jmrit.logixng.util.parser.*;
011import jmri.util.FileUtil;
012
013/**
014 * This action executes a program.
015 *
016 * @author Daniel Bergqvist Copyright 2025
017 */
018public class ExecuteProgram extends AbstractDigitalAction
019        implements PropertyChangeListener {
020
021    private final LogixNG_SelectString _selectProgram =
022            new LogixNG_SelectString(this, this);
023    private final LogixNG_SelectStringList _selectParameters =
024            new LogixNG_SelectStringList();
025    private final LogixNG_SelectString _selectWorkingDirectory =
026            new LogixNG_SelectString(this, "", this);
027
028
029    public ExecuteProgram(String sys, String user)
030            throws BadUserNameException, BadSystemNameException {
031        super(sys, user);
032    }
033
034    @Override
035    public Base getDeepCopy(Map<String, String> systemNames, Map<String, String> userNames) throws ParserException, JmriException {
036        DigitalActionManager manager = InstanceManager.getDefault(DigitalActionManager.class);
037        String sysName = systemNames.get(getSystemName());
038        String userName = userNames.get(getSystemName());
039        if (sysName == null) sysName = manager.getAutoSystemName();
040        ExecuteProgram copy = new ExecuteProgram(sysName, userName);
041        copy.setComment(getComment());
042        _selectProgram.copy(copy._selectProgram);
043        _selectParameters.copy(copy._selectParameters);
044        _selectWorkingDirectory.copy(copy._selectWorkingDirectory);
045        return manager.registerAction(copy).deepCopyChildren(this, systemNames, userNames);
046    }
047
048    public LogixNG_SelectString getSelectProgram() {
049        return _selectProgram;
050    }
051
052    public LogixNG_SelectStringList getSelectParameters() {
053        return _selectParameters;
054    }
055
056    public LogixNG_SelectString getSelectWorkingDirectory() {
057        return _selectWorkingDirectory;
058    }
059
060    /** {@inheritDoc} */
061    @Override
062    public Category getCategory() {
063        return Category.OTHER;
064    }
065
066    /** {@inheritDoc} */
067    @Override
068    public void execute() throws JmriException {
069        final ConditionalNG conditionalNG;
070
071        synchronized(this) {
072            conditionalNG = getConditionalNG();
073        }
074
075        String program = _selectProgram.evaluateValue(conditionalNG);
076        List<String> parameters = _selectParameters.evaluateValue(conditionalNG);
077        String workingDirectory = _selectWorkingDirectory.evaluateValue(conditionalNG);
078
079        File workingDirectoryFile;
080        if (!workingDirectory.isBlank()) {
081            workingDirectoryFile = new File(workingDirectory);
082        } else {
083            // Ensure the default folder is the preferences folder.
084            workingDirectoryFile = new File(FileUtil.getUserFilesPath());
085        }
086
087        List<String> programAndParameters = new ArrayList<>();
088        programAndParameters.add(program);
089        programAndParameters.addAll(parameters);
090
091        try {
092            Runtime.getRuntime().exec(
093                    programAndParameters.toArray(String[]::new),
094                    null,
095                    workingDirectoryFile);
096        } catch (IOException e) {
097            throw new JmriException(e);
098        }
099    }
100
101    @Override
102    public String getShortDescription(Locale locale) {
103        return Bundle.getMessage(locale, "ExecuteProgram_Short");
104    }
105
106    @Override
107    public String getLongDescription(Locale locale) {
108        String program = _selectProgram.getDescription(locale);
109        return Bundle.getMessage(locale, "ExecuteProgram_Long", program);
110    }
111
112    /** {@inheritDoc} */
113    @Override
114    public void setup() {
115        // Do nothing
116    }
117
118    /** {@inheritDoc} */
119    @Override
120    public void registerListenersForThisClass() {
121        if (!_listenersAreRegistered) {
122            _selectProgram.registerListeners();
123            _selectWorkingDirectory.registerListeners();
124            _listenersAreRegistered = true;
125        }
126    }
127
128    /** {@inheritDoc} */
129    @Override
130    public void unregisterListenersForThisClass() {
131        _selectProgram.unregisterListeners();
132        _selectWorkingDirectory.unregisterListeners();
133        _listenersAreRegistered = false;
134    }
135
136    /** {@inheritDoc} */
137    @Override
138    public void propertyChange(PropertyChangeEvent evt) {
139        getConditionalNG().execute();
140    }
141
142    /** {@inheritDoc} */
143    @Override
144    public void disposeMe() {
145    }
146
147
148//    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ExecuteProgram.class);
149
150}