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