001package jmri.jmrit.logixng.actions;
002
003import java.beans.*;
004import java.util.*;
005
006import jmri.*;
007import jmri.jmrit.logixng.*;
008import jmri.jmrit.logixng.Module;
009import jmri.jmrit.logixng.Module.ParameterData;
010import jmri.jmrit.logixng.Module.ReturnValueType;
011import jmri.jmrit.logixng.SymbolTable.InitialValueType;
012import jmri.jmrit.logixng.implementation.DefaultSymbolTable;
013import jmri.jmrit.logixng.util.LogixNG_SelectNamedBean;
014import jmri.jmrit.logixng.util.parser.ParserException;
015
016/**
017 * This action executes a module.
018 *
019 * @author Daniel Bergqvist Copyright 2020
020 */
021public class DigitalCallModule extends AbstractDigitalAction
022        implements PropertyChangeListener, VetoableChangeListener {
023
024    private final LogixNG_SelectNamedBean<Module> _selectNamedBean =
025            new LogixNG_SelectNamedBean<>(
026                    this, Module.class, InstanceManager.getDefault(ModuleManager.class), this);
027    private final List<ParameterData> _parameterData = new ArrayList<>();
028
029    public DigitalCallModule(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 {
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        DigitalCallModule copy = new DigitalCallModule(sysName, userName);
041        copy.setComment(getComment());
042        _selectNamedBean.copy(copy._selectNamedBean);
043        for (ParameterData data : _parameterData) {
044            copy.addParameter(
045                    data.getName(),
046                    data.getInitialValueType(),
047                    data.getInitialValueData(),
048                    data.getReturnValueType(),
049                    data.getReturnValueData());
050        }
051        return manager.registerAction(copy);
052    }
053
054    public LogixNG_SelectNamedBean<Module> getSelectNamedBean() {
055        return _selectNamedBean;
056    }
057
058    /** {@inheritDoc} */
059    @Override
060    public Category getCategory() {
061        return Category.FLOW_CONTROL;
062    }
063
064    /**
065     * Return the symbols
066     * @param symbolTable the symbol table
067     * @param symbolDefinitions list of symbols to return
068     * @throws jmri.JmriException if an exception occurs
069     */
070    public void returnSymbols(
071            DefaultSymbolTable symbolTable, Collection<ParameterData> symbolDefinitions)
072            throws JmriException {
073
074        for (ParameterData parameter : symbolDefinitions) {
075            Object returnValue = symbolTable.getValue(parameter.getName());
076
077            switch (parameter.getReturnValueType()) {
078                case None:
079                    break;
080
081                case LocalVariable:
082                    symbolTable.getPrevSymbolTable()
083                            .setValue(parameter.getReturnValueData(), returnValue);
084                    break;
085
086                case Memory:
087                    Memory m = InstanceManager.getDefault(MemoryManager.class).getNamedBean(parameter.getReturnValueData());
088                    if (m != null) m.setValue(returnValue);
089                    break;
090
091                default:
092                    log.error("definition.returnValueType has invalid value: {}", parameter.getReturnValueType().name());
093                    throw new IllegalArgumentException("definition._returnValueType has invalid value: " + parameter.getReturnValueType().name());
094            }
095        }
096    }
097
098    /** {@inheritDoc} */
099    @Override
100    public void execute() throws JmriException {
101        Module module = _selectNamedBean.evaluateNamedBean(getConditionalNG());
102
103        if (module == null) return;
104
105        FemaleSocket femaleSocket = module.getRootSocket();
106
107        if (! (femaleSocket instanceof FemaleDigitalActionSocket)) {
108            log.error("module.rootSocket is not a FemaleDigitalActionSocket");
109            return;
110        }
111
112        ConditionalNG conditionalNG = getConditionalNG();
113
114        int currentStackPos = conditionalNG.getStack().getCount();
115
116        DefaultSymbolTable newSymbolTable = new DefaultSymbolTable(conditionalNG);
117        newSymbolTable.createSymbols(conditionalNG.getSymbolTable(), _parameterData);
118        newSymbolTable.createSymbols(module.getLocalVariables());
119        conditionalNG.setSymbolTable(newSymbolTable);
120
121        try {
122            ((FemaleDigitalActionSocket)femaleSocket).execute();
123        } catch (ReturnException e) {
124            // Do nothing
125        }
126
127        returnSymbols(newSymbolTable, _parameterData);
128
129        conditionalNG.getStack().setCount(currentStackPos);
130
131        conditionalNG.setSymbolTable(newSymbolTable.getPrevSymbolTable());
132    }
133
134    @Override
135    public FemaleSocket getChild(int index) throws IllegalArgumentException, UnsupportedOperationException {
136        throw new UnsupportedOperationException("Not supported.");
137    }
138
139    @Override
140    public int getChildCount() {
141        return 0;
142    }
143
144    @Override
145    public String getShortDescription(Locale locale) {
146        return Bundle.getMessage(locale, "DigitalCallModule_Short");
147    }
148
149    @Override
150    public String getLongDescription(Locale locale) {
151        String moduleName = _selectNamedBean.getDescription(locale);
152
153        return Bundle.getMessage(locale, "DigitalCallModule_Long", moduleName);
154    }
155
156    /** {@inheritDoc} */
157    @Override
158    public void setup() {
159        // Do nothing
160    }
161
162    /** {@inheritDoc} */
163    @Override
164    public void registerListenersForThisClass() {
165        _selectNamedBean.registerListeners();
166    }
167
168    /** {@inheritDoc} */
169    @Override
170    public void unregisterListenersForThisClass() {
171        _selectNamedBean.unregisterListeners();
172    }
173
174    /** {@inheritDoc} */
175    @Override
176    public void propertyChange(PropertyChangeEvent evt) {
177        getConditionalNG().execute();
178    }
179
180    /** {@inheritDoc} */
181    @Override
182    public void disposeMe() {
183    }
184
185    public void addParameter(
186            String name,
187            InitialValueType initialValueType,
188            String initialValueData,
189            ReturnValueType returnValueType,
190            String returnValueData) {
191
192        _parameterData.add(
193                new Module.ParameterData(
194                        name,
195                        initialValueType,
196                        initialValueData,
197                        returnValueType,
198                        returnValueData));
199    }
200
201    public List<ParameterData> getParameterData() {
202        return _parameterData;
203    }
204
205
206    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DigitalCallModule.class);
207
208}