001package jmri.jmrit.logixng.expressions;
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 expression evaluates a module.
018 *
019 * @author Daniel Bergqvist Copyright 2021
020 */
021public class DigitalCallModule extends AbstractDigitalExpression
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        DigitalExpressionManager manager = InstanceManager.getDefault(DigitalExpressionManager.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.registerExpression(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 boolean evaluate() throws JmriException {
101        Module module = _selectNamedBean.evaluateNamedBean(getConditionalNG());
102
103        if (module == null) return false;
104
105        FemaleSocket femaleSocket = module.getRootSocket();
106
107        if (! (femaleSocket instanceof FemaleDigitalExpressionSocket)) {
108            log.error("module.rootSocket is not a FemaleDigitalExpressionSocket");
109            return false;
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        boolean result = ((FemaleDigitalExpressionSocket)femaleSocket).evaluate();
122
123        returnSymbols(newSymbolTable, _parameterData);
124
125        conditionalNG.getStack().setCount(currentStackPos);
126
127        conditionalNG.setSymbolTable(newSymbolTable.getPrevSymbolTable());
128
129        return result;
130    }
131
132    @Override
133    public FemaleSocket getChild(int index) throws IllegalArgumentException, UnsupportedOperationException {
134        throw new UnsupportedOperationException("Not supported.");
135    }
136
137    @Override
138    public int getChildCount() {
139        return 0;
140    }
141
142    @Override
143    public String getShortDescription(Locale locale) {
144        return Bundle.getMessage(locale, "DigitalCallModule_Short");
145    }
146
147    @Override
148    public String getLongDescription(Locale locale) {
149        String moduleName = _selectNamedBean.getDescription(locale);
150
151        return Bundle.getMessage(locale, "DigitalCallModule_Long", moduleName);
152    }
153
154    /** {@inheritDoc} */
155    @Override
156    public void setup() {
157        // Do nothing
158    }
159
160    /** {@inheritDoc} */
161    @Override
162    public void registerListenersForThisClass() {
163        _selectNamedBean.registerListeners();
164    }
165
166    /** {@inheritDoc} */
167    @Override
168    public void unregisterListenersForThisClass() {
169        _selectNamedBean.unregisterListeners();
170    }
171
172    /** {@inheritDoc} */
173    @Override
174    public void propertyChange(PropertyChangeEvent evt) {
175        getConditionalNG().execute();
176    }
177
178    /** {@inheritDoc} */
179    @Override
180    public void disposeMe() {
181    }
182
183    public void addParameter(
184            String name,
185            InitialValueType initialValueType,
186            String initialValueData,
187            ReturnValueType returnValueType,
188            String returnValueData) {
189
190        _parameterData.add(
191                new Module.ParameterData(
192                        name,
193                        initialValueType,
194                        initialValueData,
195                        returnValueType,
196                        returnValueData));
197    }
198
199    public List<ParameterData> getParameterData() {
200        return _parameterData;
201    }
202
203
204    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DigitalCallModule.class);
205
206}