001package jmri.jmrit.logixng.util.parser.functions;
002
003import java.util.HashSet;
004import java.util.List;
005import java.util.Set;
006
007import jmri.*;
008import jmri.jmrit.logix.OBlockManager;
009import jmri.jmrit.logixng.SymbolTable;
010import jmri.jmrit.logixng.util.parser.*;
011import jmri.util.TypeConversionUtil;
012
013import org.openide.util.lookup.ServiceProvider;
014
015/**
016 * Implementation of layout functions.
017 *
018 * @author Daniel Bergqvist 2021
019 */
020@ServiceProvider(service = FunctionFactory.class)
021public class LayoutFunctions implements FunctionFactory {
022
023    @Override
024    public String getModule() {
025        return "Layout";
026    }
027
028    @Override
029    public Set<Function> getFunctions() {
030        Set<Function> functionClasses = new HashSet<>();
031
032        addTurnoutExistsFunction(functionClasses);
033        addGetTurnoutStateFunction(functionClasses);
034        addSetTurnoutStateFunction(functionClasses);
035        addSensorExistsFunction(functionClasses);
036        addGetSensorStateFunction(functionClasses);
037        addSetSensorStateFunction(functionClasses);
038        addLightExistsFunction(functionClasses);
039        addGetLightStateFunction(functionClasses);
040        addSetLightStateFunction(functionClasses);
041        addSignalHeadExistsFunction(functionClasses);
042        addGetSignalHeadAppearanceFunction(functionClasses);
043        addSetSignalHeadAppearanceFunction(functionClasses);
044        addSignalMastExistsFunction(functionClasses);
045        addGetSignalMastAspectFunction(functionClasses);
046        addSetSignalMastAspectFunction(functionClasses);
047
048        return functionClasses;
049    }
050
051    @Override
052    public Set<Constant> getConstants() {
053        Set<Constant> constantClasses = new HashSet<>();
054        constantClasses.add(new Constant(getModule(), "Unknown", NamedBean.UNKNOWN));
055        constantClasses.add(new Constant(getModule(), "Inconsistent", NamedBean.INCONSISTENT));
056
057        constantClasses.add(new Constant(getModule(), "Off", Light.OFF));
058        constantClasses.add(new Constant(getModule(), "On", Light.ON));
059
060        constantClasses.add(new Constant(getModule(), "Inactive", Sensor.INACTIVE));
061        constantClasses.add(new Constant(getModule(), "Active", Sensor.ACTIVE));
062
063        constantClasses.add(new Constant(getModule(), "Closed", Turnout.CLOSED));
064        constantClasses.add(new Constant(getModule(), "Thrown", Turnout.THROWN));
065        constantClasses.add(new Constant(getModule(), "CabLockout", Turnout.CABLOCKOUT));
066        constantClasses.add(new Constant(getModule(), "PushButtonLockout", Turnout.PUSHBUTTONLOCKOUT));
067        constantClasses.add(new Constant(getModule(), "Unlocked", Turnout.UNLOCKED));
068        constantClasses.add(new Constant(getModule(), "Locked", Turnout.LOCKED));
069
070        constantClasses.add(new Constant(getModule(), "Dark", SignalHead.DARK));
071        constantClasses.add(new Constant(getModule(), "Red", SignalHead.RED));
072        constantClasses.add(new Constant(getModule(), "FlashRed", SignalHead.FLASHRED));
073        constantClasses.add(new Constant(getModule(), "Yellow", SignalHead.YELLOW));
074        constantClasses.add(new Constant(getModule(), "FlashYellow", SignalHead.FLASHYELLOW));
075        constantClasses.add(new Constant(getModule(), "Green", SignalHead.GREEN));
076        constantClasses.add(new Constant(getModule(), "FlashGreen", SignalHead.FLASHGREEN));
077        constantClasses.add(new Constant(getModule(), "Lunar", SignalHead.LUNAR));
078        constantClasses.add(new Constant(getModule(), "FlashLunar", SignalHead.FLASHLUNAR));
079        constantClasses.add(new Constant(getModule(), "Held", SignalHead.HELD));
080
081        constantClasses.add(new Constant(getModule(), "sensors", InstanceManager.getNullableDefault(SensorManager.class)));
082        constantClasses.add(new Constant(getModule(), "turnouts", InstanceManager.getNullableDefault(TurnoutManager.class)));
083        constantClasses.add(new Constant(getModule(), "lights", InstanceManager.getNullableDefault(LightManager.class)));
084        constantClasses.add(new Constant(getModule(), "signals", InstanceManager.getNullableDefault(SignalHeadManager.class)));
085        constantClasses.add(new Constant(getModule(), "masts", InstanceManager.getNullableDefault(SignalMastManager.class)));
086        constantClasses.add(new Constant(getModule(), "routes", InstanceManager.getNullableDefault(RouteManager.class)));
087        constantClasses.add(new Constant(getModule(), "blocks", InstanceManager.getNullableDefault(BlockManager.class)));
088        constantClasses.add(new Constant(getModule(), "oblocks", InstanceManager.getNullableDefault(OBlockManager.class)));
089        constantClasses.add(new Constant(getModule(), "reporters", InstanceManager.getNullableDefault(ReporterManager.class)));
090        constantClasses.add(new Constant(getModule(), "memories", InstanceManager.getNullableDefault(MemoryManager.class)));
091        constantClasses.add(new Constant(getModule(), "powermanager", InstanceManager.getNullableDefault(PowerManager.class)));
092        constantClasses.add(new Constant(getModule(), "addressedProgrammers", InstanceManager.getNullableDefault(AddressedProgrammerManager.class)));
093        constantClasses.add(new Constant(getModule(), "globalProgrammers", InstanceManager.getNullableDefault(GlobalProgrammerManager.class)));
094        constantClasses.add(new Constant(getModule(), "dcc", InstanceManager.getNullableDefault(CommandStation.class)));
095        constantClasses.add(new Constant(getModule(), "audio", InstanceManager.getNullableDefault(AudioManager.class)));
096        constantClasses.add(new Constant(getModule(), "shutdown", InstanceManager.getNullableDefault(ShutDownManager.class)));
097        constantClasses.add(new Constant(getModule(), "layoutblocks", InstanceManager.getNullableDefault(jmri.jmrit.display.layoutEditor.LayoutBlockManager.class)));
098        constantClasses.add(new Constant(getModule(), "warrants", InstanceManager.getNullableDefault(jmri.jmrit.logix.WarrantManager.class)));
099        constantClasses.add(new Constant(getModule(), "sections", InstanceManager.getNullableDefault(SectionManager.class)));
100        constantClasses.add(new Constant(getModule(), "transits", InstanceManager.getNullableDefault(TransitManager.class)));
101
102        constantClasses.add(new Constant(getModule(), "InstanceManager", InstanceManager.getDefault()));
103
104//        constantClasses.add(new Constant(getModule(), "FileUtil", FileUtilSupport.getDefault());
105
106        return constantClasses;
107    }
108
109    @Override
110    public String getConstantDescription() {
111        return Bundle.getMessage("Layout.ConstantDescriptions");
112    }
113
114    private void addTurnoutExistsFunction(Set<Function> functionClasses) {
115        functionClasses.add(new AbstractFunction(this, "turnoutExists", Bundle.getMessage("LayoutFunctions.turnoutExists_Descr")) {
116            @Override
117            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
118                    throws CalculateException, JmriException {
119                if (parameterList.isEmpty()) {
120                    throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters2", getName(), 1));
121                }
122
123                String name = TypeConversionUtil.convertToString(
124                        parameterList.get(0).calculate(symbolTable), false);
125
126                Turnout t = InstanceManager.getDefault(TurnoutManager.class).getNamedBean(name);
127                return t != null;
128            }
129        });
130    }
131
132    private void addGetTurnoutStateFunction(Set<Function> functionClasses) {
133        functionClasses.add(new AbstractFunction(this, "getTurnoutState", Bundle.getMessage("LayoutFunctions.getTurnoutState_Descr")) {
134            @Override
135            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
136                    throws CalculateException, JmriException {
137                if (parameterList.isEmpty()) {
138                    throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters2", getName(), 1));
139                }
140
141                String name = TypeConversionUtil.convertToString(
142                        parameterList.get(0).calculate(symbolTable), false);
143
144                Turnout t = InstanceManager.getDefault(TurnoutManager.class).getNamedBean(name);
145                if (t == null) throw new CalculateException(Bundle.getMessage("LayoutFunctions_GetTurnoutState_TurnoutNotFound", name));
146                return t.getKnownState();
147            }
148        });
149    }
150
151    private void addSetTurnoutStateFunction(Set<Function> functionClasses) {
152        functionClasses.add(new AbstractFunction(this, "setTurnoutState", Bundle.getMessage("LayoutFunctions.setTurnoutState_Descr")) {
153            @Override
154            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
155                    throws CalculateException, JmriException {
156                if (parameterList.isEmpty()) {
157                    throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters2", getName(), 2));
158                }
159
160                String name = TypeConversionUtil.convertToString(
161                        parameterList.get(0).calculate(symbolTable), false);
162                int value = (int) TypeConversionUtil.convertToLong(
163                        parameterList.get(1).calculate(symbolTable));
164
165                Turnout t = InstanceManager.getDefault(TurnoutManager.class).getNamedBean(name);
166                if (t == null) throw new CalculateException(Bundle.getMessage("LayoutFunctions_SetTurnoutState_TurnoutNotFound", name));
167                t.setState(value);
168                return t.getKnownState();
169            }
170        });
171    }
172
173    private void addSensorExistsFunction(Set<Function> functionClasses) {
174        functionClasses.add(new AbstractFunction(this, "sensorExists", Bundle.getMessage("LayoutFunctions.sensorExists_Descr")) {
175            @Override
176            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
177                    throws CalculateException, JmriException {
178                if (parameterList.isEmpty()) {
179                    throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters2", getName(), 1));
180                }
181
182                String name = TypeConversionUtil.convertToString(
183                        parameterList.get(0).calculate(symbolTable), false);
184
185                Sensor s = InstanceManager.getDefault(SensorManager.class).getNamedBean(name);
186                return s != null;
187            }
188        });
189    }
190
191    private void addGetSensorStateFunction(Set<Function> functionClasses) {
192        functionClasses.add(new AbstractFunction(this, "getSensorState", Bundle.getMessage("LayoutFunctions.getSensorState_Descr")) {
193            @Override
194            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
195                    throws CalculateException, JmriException {
196                if (parameterList.isEmpty()) {
197                    throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters2", getName(), 1));
198                }
199
200                String name = TypeConversionUtil.convertToString(
201                        parameterList.get(0).calculate(symbolTable), false);
202
203                Sensor s = InstanceManager.getDefault(SensorManager.class).getNamedBean(name);
204                if (s == null) throw new CalculateException(Bundle.getMessage("LayoutFunctions_GetSensorState_SensorNotFound", name));
205                return s.getKnownState();
206            }
207        });
208    }
209
210    private void addSetSensorStateFunction(Set<Function> functionClasses) {
211        functionClasses.add(new AbstractFunction(this, "setSensorState", Bundle.getMessage("LayoutFunctions.setSensorState_Descr")) {
212            @Override
213            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
214                    throws CalculateException, JmriException {
215                if (parameterList.isEmpty()) {
216                    throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters2", getName(), 2));
217                }
218
219                String name = TypeConversionUtil.convertToString(
220                        parameterList.get(0).calculate(symbolTable), false);
221                int value = (int) TypeConversionUtil.convertToLong(
222                        parameterList.get(1).calculate(symbolTable));
223
224                Sensor s = InstanceManager.getDefault(SensorManager.class).getNamedBean(name);
225                if (s == null) throw new CalculateException(Bundle.getMessage("LayoutFunctions_SetSensorState_SensorNotFound", name));
226                s.setState(value);
227                return s.getKnownState();
228            }
229        });
230    }
231
232    private void addLightExistsFunction(Set<Function> functionClasses) {
233        functionClasses.add(new AbstractFunction(this, "lightExists", Bundle.getMessage("LayoutFunctions.lightExists_Descr")) {
234            @Override
235            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
236                    throws CalculateException, JmriException {
237                if (parameterList.isEmpty()) {
238                    throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters2", getName(), 1));
239                }
240
241                String name = TypeConversionUtil.convertToString(
242                        parameterList.get(0).calculate(symbolTable), false);
243
244                Light l = InstanceManager.getDefault(LightManager.class).getNamedBean(name);
245                return l != null;
246            }
247        });
248    }
249
250    private void addGetLightStateFunction(Set<Function> functionClasses) {
251        functionClasses.add(new AbstractFunction(this, "getLightState", Bundle.getMessage("LayoutFunctions.getLightState_Descr")) {
252            @Override
253            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
254                    throws CalculateException, JmriException {
255                if (parameterList.isEmpty()) {
256                    throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters2", getName(), 1));
257                }
258
259                String name = TypeConversionUtil.convertToString(
260                        parameterList.get(0).calculate(symbolTable), false);
261
262                Light l = InstanceManager.getDefault(LightManager.class).getNamedBean(name);
263                if (l == null) throw new CalculateException(Bundle.getMessage("LayoutFunctions_GetLightState_LightNotFound", name));
264                return l.getKnownState();
265            }
266        });
267    }
268
269    private void addSetLightStateFunction(Set<Function> functionClasses) {
270        functionClasses.add(new AbstractFunction(this, "setLightState", Bundle.getMessage("LayoutFunctions.setLightState_Descr")) {
271            @Override
272            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
273                    throws CalculateException, JmriException {
274                if (parameterList.isEmpty()) {
275                    throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters2", getName(), 2));
276                }
277
278                String name = TypeConversionUtil.convertToString(
279                        parameterList.get(0).calculate(symbolTable), false);
280                int value = (int) TypeConversionUtil.convertToLong(
281                        parameterList.get(1).calculate(symbolTable));
282
283                Light l = InstanceManager.getDefault(LightManager.class).getNamedBean(name);
284                if (l == null) throw new CalculateException(Bundle.getMessage("LayoutFunctions_SetLightState_LightNotFound", name));
285                l.setState(value);
286                return l.getKnownState();
287            }
288        });
289    }
290
291    private void addSignalHeadExistsFunction(Set<Function> functionClasses) {
292        functionClasses.add(new AbstractFunction(this, "signalHeadExists", Bundle.getMessage("LayoutFunctions.signalHeadExists_Descr")) {
293            @Override
294            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
295                    throws CalculateException, JmriException {
296                if (parameterList.isEmpty()) {
297                    throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters2", getName(), 1));
298                }
299
300                String name = TypeConversionUtil.convertToString(
301                        parameterList.get(0).calculate(symbolTable), false);
302
303                SignalHead sh = InstanceManager.getDefault(SignalHeadManager.class).getNamedBean(name);
304                return sh != null;
305            }
306        });
307    }
308
309    private void addGetSignalHeadAppearanceFunction(Set<Function> functionClasses) {
310        functionClasses.add(new AbstractFunction(this, "getSignalHeadAppearance", Bundle.getMessage("LayoutFunctions.getSignalHeadAppearance_Descr")) {
311            @Override
312            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
313                    throws CalculateException, JmriException {
314                if (parameterList.isEmpty()) {
315                    throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters2", getName(), 1));
316                }
317
318                String name = TypeConversionUtil.convertToString(
319                        parameterList.get(0).calculate(symbolTable), false);
320
321                SignalHead sh = InstanceManager.getDefault(SignalHeadManager.class).getNamedBean(name);
322                if (sh == null) throw new CalculateException(Bundle.getMessage("LayoutFunctions_GetSignalHeadAppearance_SignalHeadNotFound", name));
323                return sh.getAppearance();
324            }
325        });
326    }
327
328    private void addSetSignalHeadAppearanceFunction(Set<Function> functionClasses) {
329        functionClasses.add(new AbstractFunction(this, "setSignalHeadAppearance", Bundle.getMessage("LayoutFunctions.setSignalHeadAppearance_Descr")) {
330            @Override
331            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
332                    throws CalculateException, JmriException {
333                if (parameterList.isEmpty()) {
334                    throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters2", getName(), 2));
335                }
336
337                String name = TypeConversionUtil.convertToString(
338                        parameterList.get(0).calculate(symbolTable), false);
339                int aspect = (int) TypeConversionUtil.convertToLong(
340                        parameterList.get(1).calculate(symbolTable));
341
342                SignalHead sh = InstanceManager.getDefault(SignalHeadManager.class).getNamedBean(name);
343                if (sh == null) throw new CalculateException(Bundle.getMessage("LayoutFunctions_SetSignalHeadAppearance_SignalHeadNotFound", name));
344                sh.setAppearance(aspect);
345                return sh.getAppearance();
346            }
347        });
348    }
349
350    private void addSignalMastExistsFunction(Set<Function> functionClasses) {
351        functionClasses.add(new AbstractFunction(this, "signalMastExists", Bundle.getMessage("LayoutFunctions.signalMastExists_Descr")) {
352            @Override
353            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
354                    throws CalculateException, JmriException {
355                if (parameterList.isEmpty()) {
356                    throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters2", getName(), 1));
357                }
358
359                String name = TypeConversionUtil.convertToString(
360                        parameterList.get(0).calculate(symbolTable), false);
361
362                SignalMast sh = InstanceManager.getDefault(SignalMastManager.class).getNamedBean(name);
363                return sh != null;
364            }
365        });
366    }
367
368    private void addGetSignalMastAspectFunction(Set<Function> functionClasses) {
369        functionClasses.add(new AbstractFunction(this, "getSignalMastAspect", Bundle.getMessage("LayoutFunctions.getSignalMastAspect_Descr")) {
370            @Override
371            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
372                    throws CalculateException, JmriException {
373                if (parameterList.isEmpty()) {
374                    throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters2", getName(), 1));
375                }
376
377                String name = TypeConversionUtil.convertToString(
378                        parameterList.get(0).calculate(symbolTable), false);
379
380                SignalMast sm = InstanceManager.getDefault(SignalMastManager.class).getNamedBean(name);
381                if (sm == null) throw new CalculateException(Bundle.getMessage("LayoutFunctions_GetSignalMastAspect_SignalMastNotFound", name));
382                return sm.getAspect();
383            }
384        });
385    }
386
387    private void addSetSignalMastAspectFunction(Set<Function> functionClasses) {
388        functionClasses.add(new AbstractFunction(this, "setSignalMastAspect", Bundle.getMessage("LayoutFunctions.setSignalMastAspect_Descr")) {
389            @Override
390            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
391                    throws CalculateException, JmriException {
392                if (parameterList.isEmpty()) {
393                    throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters2", getName(), 2));
394                }
395
396                String name = TypeConversionUtil.convertToString(
397                        parameterList.get(0).calculate(symbolTable), false);
398                String aspect = TypeConversionUtil.convertToString(
399                        parameterList.get(1).calculate(symbolTable), false);
400
401                SignalMast sm = InstanceManager.getDefault(SignalMastManager.class).getNamedBean(name);
402                if (sm == null) throw new CalculateException(Bundle.getMessage("LayoutFunctions_SetSignalMastAspect_SignalMastNotFound", name));
403                sm.setAspect(aspect);
404                return sm.getAspect();
405            }
406        });
407    }
408
409}