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        addCurrentTimeMillisFunction(functionClasses);
032        addSystemClockFunction(functionClasses);
033        addFastClockFunction(functionClasses);
034        addFastClockRateFunction(functionClasses);
035        addFastClockRunningFunction(functionClasses);
036
037        return functionClasses;
038    }
039
040    @Override
041    public Set<Constant> getConstants() {
042        return new HashSet<>();
043    }
044
045    @Override
046    public String getConstantDescription() {
047        // This module doesn't define any constants
048        return null;
049    }
050
051    private void addCurrentTimeMillisFunction(Set<Function> functionClasses) {
052        functionClasses.add(new AbstractFunction(this, "currentTimeMillis", Bundle.getMessage("Clock.currentTimeMillis_Descr")) {
053            @Override
054            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
055                    throws CalculateException, JmriException {
056
057                if (parameterList.isEmpty()) {
058                    return System.currentTimeMillis();
059                } else {
060                    throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters1", getName()));
061                }
062            }
063        });
064    }
065
066    private void addSystemClockFunction(Set<Function> functionClasses) {
067        functionClasses.add(new AbstractFunction(this, "systemClock", Bundle.getMessage("Clock.systemClock_Descr")) {
068            @Override
069            @SuppressWarnings("deprecation")        // Date.getMinutes, Date.getHours
070            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
071                    throws CalculateException, JmriException {
072
073                Date currentTime = Date.from(Instant.now());
074
075                if (parameterList.isEmpty()) {  // Num minutes since midnight
076                    return (currentTime.getHours() * 60) + currentTime.getMinutes();
077                } else if (parameterList.size() == 1) {
078                    Object param = parameterList.get(0).calculate(symbolTable);
079                    if (param instanceof String) {
080                        switch ((String)param) {
081                            case "hour":
082                                return currentTime.getHours();
083                            case "min":
084                                return currentTime.getMinutes();
085                            case "sec":
086                                return currentTime.getSeconds();
087                            case "minOfDay":
088                                return (currentTime.getHours() * 60) + currentTime.getMinutes();
089                            case "secOfDay":
090                                return ((currentTime.getHours() * 60) + currentTime.getMinutes()) * 60 + currentTime.getSeconds();
091                            default:
092                                throw new CalculateException(Bundle.getMessage("IllegalParameter", 1, param, getName()));
093                        }
094                    } else {
095                        throw new CalculateException(Bundle.getMessage("IllegalParameter", 1, param, getName()));
096                    }
097                }
098                throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters1", getName()));
099            }
100        });
101    }
102
103    private void addFastClockFunction(Set<Function> functionClasses) {
104        functionClasses.add(new AbstractFunction(this, "fastClock", Bundle.getMessage("Clock.fastClock_Descr")) {
105            @Override
106            @SuppressWarnings("deprecation")        // Date.getMinutes, Date.getHours
107            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
108                    throws JmriException {
109
110                Date currentTime = _fastClock.getTime();
111
112                if (parameterList.isEmpty()) {  // Num minutes since midnight
113                    return (currentTime.getHours() * 60) + currentTime.getMinutes();
114                } else if (parameterList.size() == 1) {
115                    Object param = parameterList.get(0).calculate(symbolTable);
116                    if (param instanceof String) {
117                        switch ((String)param) {
118                            case "hour":
119                                return currentTime.getHours();
120                            case "min":
121                                return currentTime.getMinutes();
122                            case "minOfDay":
123                                return (currentTime.getHours() * 60) + currentTime.getMinutes();
124                            default:
125                                throw new CalculateException(Bundle.getMessage("IllegalParameter", 1, param, getName()));
126                        }
127                    } else {
128                        throw new CalculateException(Bundle.getMessage("IllegalParameter", 1, param, getName()));
129                    }
130                }
131                throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters1", getName()));
132            }
133        });
134    }
135
136    private void addFastClockRateFunction(Set<Function> functionClasses) {
137        functionClasses.add(new AbstractFunction(this, "fastClockRate", Bundle.getMessage("Clock.fastClockRate_Descr")) {
138            @Override
139            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
140                    throws JmriException {
141
142                double rate = _fastClock.userGetRate();
143
144                if (parameterList.isEmpty()) return rate;
145
146                throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters1", getName()));
147            }
148        });
149    }
150
151    private void addFastClockRunningFunction(Set<Function> functionClasses) {
152        functionClasses.add(new AbstractFunction(this, "isFastClockRunning", Bundle.getMessage("Clock.isFastClockRunning_Descr")) {
153            @Override
154            public Object calculate(SymbolTable symbolTable, List<ExpressionNode> parameterList)
155                    throws JmriException {
156
157                boolean rate = _fastClock.getRun();
158
159                if (parameterList.isEmpty()) return rate;
160
161                throw new WrongNumberOfParametersException(Bundle.getMessage("WrongNumberOfParameters1", getName()));
162            }
163        });
164    }
165
166}