001package jmri.jmrit.logixng.util.parser.functions;
002
003import java.time.Instant;
004import java.util.*;
005
006import jmri.*;
007import jmri.jmrit.logixng.SymbolTable;
008import jmri.jmrit.logixng.util.parser.*;
009
010import org.openide.util.lookup.ServiceProvider;
011
012/**
013 * Implementation of clock functions.
014 *
015 * @author Daniel Bergqvist 2020
016 */
017@ServiceProvider(service = FunctionFactory.class)
018public class ClockFunctions implements FunctionFactory {
019
020    private final Timebase _fastClock = InstanceManager.getDefault(jmri.Timebase.class);
021
022    @Override
023    public String getModule() {
024        return "Clock";
025    }
026
027    @Override
028    public Set<Function> getFunctions() {
029        Set<Function> functionClasses = new HashSet<>();
030
031        addSystemClockFunction(functionClasses);
032        addFastClockFunction(functionClasses);
033        addFastClockRateFunction(functionClasses);
034        addFastClockRunningFunction(functionClasses);
035
036        return functionClasses;
037    }
038
039    @Override
040    public Set<Constant> getConstants() {
041        return new HashSet<>();
042    }
043
044    @Override
045    public String getConstantDescription() {
046        // This module doesn't define any constants
047        return null;
048    }
049
050    private void addSystemClockFunction(Set<Function> functionClasses) {
051        functionClasses.add(new AbstractFunction(this, "systemClock", Bundle.getMessage("Clock.systemClock_Descr")) {
052            @Override
053            @SuppressWarnings("deprecation")        // Date.getMinutes, Date.getHours
054            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
055                    throws CalculateException, JmriException {
056
057                Date currentTime = Date.from(Instant.now());
058
059                if (parameterList.isEmpty()) {  // Num minutes since midnight
060                    return (currentTime.getHours() * 60) + currentTime.getMinutes();
061                } else if (parameterList.size() == 1) {
062                    Object param = parameterList.get(0).calculate(symbolTable);
063                    if (param instanceof String) {
064                        switch ((String)param) {
065                            case "hour":
066                                return currentTime.getHours();
067                            case "min":
068                                return currentTime.getMinutes();
069                            case "sec":
070                                return currentTime.getSeconds();
071                            case "minOfDay":
072                                return (currentTime.getHours() * 60) + currentTime.getMinutes();
073                            case "secOfDay":
074                                return ((currentTime.getHours() * 60) + currentTime.getMinutes()) * 60 + currentTime.getSeconds();
075                            default:
076                                throw new CalculateException(Bundle.getMessage("IllegalParameter", 1, param, getName()));
077                        }
078                    } else {
079                        throw new CalculateException(Bundle.getMessage("IllegalParameter", 1, param, getName()));
080                    }
081                }
082                throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters1", getName()));
083            }
084        });
085    }
086
087    private void addFastClockFunction(Set<Function> functionClasses) {
088        functionClasses.add(new AbstractFunction(this, "fastClock", Bundle.getMessage("Clock.fastClock_Descr")) {
089            @Override
090            @SuppressWarnings("deprecation")        // Date.getMinutes, Date.getHours
091            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
092                    throws JmriException {
093
094                Date currentTime = _fastClock.getTime();
095
096                if (parameterList.isEmpty()) {  // Num minutes since midnight
097                    return (currentTime.getHours() * 60) + currentTime.getMinutes();
098                } else if (parameterList.size() == 1) {
099                    Object param = parameterList.get(0).calculate(symbolTable);
100                    if (param instanceof String) {
101                        switch ((String)param) {
102                            case "hour":
103                                return currentTime.getHours();
104                            case "min":
105                                return currentTime.getMinutes();
106                            case "minOfDay":
107                                return (currentTime.getHours() * 60) + currentTime.getMinutes();
108                            default:
109                                throw new CalculateException(Bundle.getMessage("IllegalParameter", 1, param, getName()));
110                        }
111                    } else {
112                        throw new CalculateException(Bundle.getMessage("IllegalParameter", 1, param, getName()));
113                    }
114                }
115                throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters1", getName()));
116            }
117        });
118    }
119
120    private void addFastClockRateFunction(Set<Function> functionClasses) {
121        functionClasses.add(new AbstractFunction(this, "fastClockRate", Bundle.getMessage("Clock.fastClockRate_Descr")) {
122            @Override
123            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
124                    throws JmriException {
125
126                double rate = _fastClock.userGetRate();
127
128                if (parameterList.isEmpty()) return rate;
129
130                throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters1", getName()));
131            }
132        });
133    }
134
135    private void addFastClockRunningFunction(Set<Function> functionClasses) {
136        functionClasses.add(new AbstractFunction(this, "isFastClockRunning", Bundle.getMessage("Clock.isFastClockRunning_Descr")) {
137            @Override
138            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
139                    throws JmriException {
140
141                boolean rate = _fastClock.getRun();
142
143                if (parameterList.isEmpty()) return rate;
144
145                throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters1", getName()));
146            }
147        });
148    }
149
150}