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