001package jmri.jmrit.logixng.expressions; 002 003import java.beans.PropertyChangeEvent; 004import java.beans.PropertyChangeListener; 005import java.util.*; 006 007import jmri.*; 008import jmri.jmrit.logixng.*; 009import jmri.util.TimerUtil; 010 011/** 012 * This expression returns the number of minutes since midnight for the fast 013 * clock or the system clock. 014 * 015 * @author Daniel Bergqvist Copyright 2020 016 * @author Dave Sand Copyright 2021 017 */ 018public class TimeSinceMidnight extends AbstractAnalogExpression implements PropertyChangeListener { 019 020 private Type _type = Type.FastClock; 021 private Timebase _fastClock; 022 023 TimerTask timerTask = null; 024 private final int millisInAMinute = 60000; 025 026 027 public TimeSinceMidnight(String sys, String user) { 028 super(sys, user); 029 } 030 031 @Override 032 public Base getDeepCopy(Map<String, String> systemNames, Map<String, String> userNames) throws JmriException { 033 AnalogExpressionManager manager = InstanceManager.getDefault(AnalogExpressionManager.class); 034 String sysName = systemNames.get(getSystemName()); 035 String userName = userNames.get(getSystemName()); 036 if (sysName == null) sysName = manager.getAutoSystemName(); 037 TimeSinceMidnight copy = new TimeSinceMidnight(sysName, userName); 038 copy.setComment(getComment()); 039 copy.setType(_type); 040 return manager.registerExpression(copy).deepCopyChildren(this, systemNames, userNames); 041 } 042 043 /** {@inheritDoc} */ 044 @Override 045 public Category getCategory() { 046 return Category.ITEM; 047 } 048 049 public void setType(Type type) { 050 assertListenersAreNotRegistered(log, "setType"); 051 _type = type; 052 053 if (_type == Type.FastClock) { 054 _fastClock = InstanceManager.getDefault(jmri.Timebase.class); 055 } else { 056 _fastClock = null; 057 } 058 } 059 060 public Type getType() { 061 return _type; 062 } 063 064 /** {@inheritDoc} */ 065 @Override 066 public double evaluate() { 067 Calendar currentTime = null; 068 069 switch (_type) { 070 case SystemClock: 071 currentTime = Calendar.getInstance(); 072 break; 073 074 case FastClock: 075 if (_fastClock == null) return 0; 076 currentTime = Calendar.getInstance(); 077 currentTime.setTime(_fastClock.getTime()); 078 break; 079 080 default: 081 throw new UnsupportedOperationException("_type has unknown value: " + _type.name()); 082 } 083 084 return (currentTime.get(Calendar.HOUR_OF_DAY) * 60) + currentTime.get(Calendar.MINUTE); 085 } 086 087 @Override 088 public FemaleSocket getChild(int index) throws IllegalArgumentException, UnsupportedOperationException { 089 throw new UnsupportedOperationException("Not supported."); 090 } 091 092 @Override 093 public int getChildCount() { 094 return 0; 095 } 096 097 @Override 098 public String getShortDescription(Locale locale) { 099 return Bundle.getMessage(locale, "TimeSinceMidnight_Short"); 100 } 101 102 @Override 103 public String getLongDescription(Locale locale) { 104 switch (_type) { 105 case SystemClock: 106 return Bundle.getMessage(locale, "TimeSinceMidnight_Long_SystemClock"); 107 108 case FastClock: 109 return Bundle.getMessage(locale, "TimeSinceMidnight_Long_FastClock"); 110 111 default: 112 throw new RuntimeException("Unknown value of _timerType: "+_type.name()); 113 } 114 } 115 116 /** {@inheritDoc} */ 117 @Override 118 public void setup() { 119 // Do nothing 120 } 121 122 /** {@inheritDoc} 123 * The SystemClock listener creates a timer on the first call. Subsequent calls 124 * enabled timer processing. 125 */ 126 @Override 127 public void registerListenersForThisClass() { 128 if (!_listenersAreRegistered) { 129 switch (_type) { 130 case SystemClock: 131 scheduleTimer(); 132 break; 133 134 case FastClock: 135 _fastClock.addPropertyChangeListener("time", this); 136 break; 137 138 default: 139 throw new UnsupportedOperationException("_type has unknown value: " + _type.name()); 140 } 141 142 _listenersAreRegistered = true; 143 } 144 } 145 146 /** {@inheritDoc} 147 * The SystemClock timer flag is set false to suspend processing of timer events. The 148 * timer keeps running for the duration of the JMRI session. 149 */ 150 @Override 151 public void unregisterListenersForThisClass() { 152 if (_listenersAreRegistered) { 153 switch (_type) { 154 case SystemClock: 155 if (timerTask != null) timerTask.cancel(); 156 break; 157 158 case FastClock: 159 if (_fastClock != null) _fastClock.removePropertyChangeListener("time", this); 160 break; 161 162 default: 163 throw new UnsupportedOperationException("_type has unknown value: " + _type.name()); 164 } 165 166 _listenersAreRegistered = false; 167 } 168 } 169 170 private void scheduleTimer() { 171 timerTask = new TimerTask() { 172 @Override 173 public void run() { 174 propertyChange(null); 175 } 176 }; 177 TimerUtil.schedule(timerTask, System.currentTimeMillis() % millisInAMinute, millisInAMinute); 178 } 179 180 /** {@inheritDoc} */ 181 @Override 182 public void propertyChange(PropertyChangeEvent evt) { 183 getConditionalNG().execute(); 184 } 185 186 /** {@inheritDoc} */ 187 @Override 188 public void disposeMe() { 189 if (timerTask != null) timerTask.cancel(); 190 } 191 192 public enum Type { 193 FastClock(Bundle.getMessage("ClockTypeFastClock")), 194 SystemClock(Bundle.getMessage("ClockTypeSystemClock")); 195 196 private final String _text; 197 198 private Type(String text) { 199 this._text = text; 200 } 201 202 @Override 203 public String toString() { 204 return _text; 205 } 206 207 } 208 209 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TimeSinceMidnight.class); 210 211}