001package jmri.jmrix.loconet.logixng; 002 003import java.util.*; 004 005import jmri.InstanceManager; 006import jmri.JmriException; 007import jmri.jmrit.logixng.*; 008import jmri.jmrit.logixng.expressions.*; 009import jmri.jmrix.loconet.*; 010 011/** 012 * This expression compares the number of slots that are currently in use with 013 * a threshold number. 014 * 015 * @author Daniel Bergqvist Copyright 2020 016 */ 017public class ExpressionSlotUsage extends AbstractDigitalExpression 018 implements SlotListener { 019 020 private static final int MAX_NUM_LOCO_SLOTS = 119; 021 022 private LocoNetSystemConnectionMemo _memo; 023 private boolean _advanced = false; 024 private Has_HasNot _hasHasNot = Has_HasNot.Has; 025 private SimpleState _simpleState = SimpleState.InUse; 026 private final Set<AdvancedState> _advancedStates = new HashSet<>(); 027 private Compare _compare = Compare.LessThan; 028 private int _number = 0; 029 private PercentPieces _percentPieces = PercentPieces.Pieces; 030 private int _totalSlots = 0; 031 032 033 public ExpressionSlotUsage(String sys, String user, LocoNetSystemConnectionMemo memo) { 034 super(sys, user); 035 _memo = memo; 036 } 037 038 @Override 039 public Base getDeepCopy(Map<String, String> systemNames, Map<String, String> userNames) throws JmriException { 040 DigitalExpressionManager manager = InstanceManager.getDefault(DigitalExpressionManager.class); 041 String sysName = systemNames.get(getSystemName()); 042 String userName = userNames.get(getSystemName()); 043 if (sysName == null) sysName = manager.getAutoSystemName(); 044 ExpressionSlotUsage copy = new ExpressionSlotUsage(sysName, userName, _memo); 045 copy.setAdvanced(_advanced); 046 copy.set_Has_HasNot(_hasHasNot); 047 copy.setSimpleState(_simpleState); 048 copy.setAdvancedStates(_advancedStates); 049 copy.setCompare(_compare); 050 copy.setNumber(_number); 051 copy.setPercentPieces(_percentPieces); 052 copy.setTotalSlots(_totalSlots); 053 return manager.registerExpression(copy).deepCopyChildren(this, systemNames, userNames); 054 } 055 056 /** {@inheritDoc} */ 057 @Override 058 public Category getCategory() { 059 return CategoryLocoNet.LOCONET; 060 } 061 062 public void setMemo(LocoNetSystemConnectionMemo memo) { 063 assertListenersAreNotRegistered(log, "setMemo"); 064 _memo = memo; 065 } 066 067 public LocoNetSystemConnectionMemo getMemo() { 068 return _memo; 069 } 070 071 public void setAdvanced(boolean advanced) { 072 assertListenersAreNotRegistered(log, "setAdvanced"); 073 _advanced = advanced; 074 } 075 076 public boolean getAdvanced() { 077 return _advanced; 078 } 079 080 public void set_Has_HasNot(Has_HasNot hasHasNot) { 081 assertListenersAreNotRegistered(log, "set_Has_HasNot"); 082 _hasHasNot = hasHasNot; 083 } 084 085 public Has_HasNot get_Has_HasNot() { 086 return _hasHasNot; 087 } 088 089 public void setSimpleState(SimpleState simpleState){ 090 assertListenersAreNotRegistered(log, "setSimpleState"); 091 _simpleState = simpleState; 092 } 093 094 public SimpleState getSimpleState() { 095 return _simpleState; 096 } 097 098 public void setAdvancedStates(Set<AdvancedState> states) { 099 assertListenersAreNotRegistered(log, "setAdvancedStates"); 100 _advancedStates.clear(); 101 _advancedStates.addAll(states); 102 } 103 104 public Set<AdvancedState> getAdvancedStates() { 105 return Collections.unmodifiableSet(_advancedStates); 106 } 107 108 public void setCompare(Compare compare){ 109 assertListenersAreNotRegistered(log, "setCompare"); 110 _compare = compare; 111 } 112 113 public Compare getCompare() { 114 return _compare; 115 } 116 117 public void setNumber(int number) { 118 assertListenersAreNotRegistered(log, "setNumber"); 119 _number = number; 120 } 121 122 public int getNumber() { 123 return _number; 124 } 125 126 public void setTotalSlots(int totalNumber) { 127 assertListenersAreNotRegistered(log, "setTotalNumber"); 128 _totalSlots = totalNumber; 129 } 130 131 public int getTotalSlots() { 132 return _totalSlots; 133 } 134 135 public void setPercentPieces(PercentPieces percentPieces) { 136 assertListenersAreNotRegistered(log, "setPercentPieces"); 137 _percentPieces = percentPieces; 138 } 139 140 public PercentPieces getPercentPieces() { 141 return _percentPieces; 142 } 143 144 private int getNumWithStatus() { 145 if (_memo == null) return 0; 146 int count = 0; 147 for (int i=1; i <= MAX_NUM_LOCO_SLOTS; i++) { 148 boolean match = false; 149 LocoNetSlot slot = _memo.getSlotManager().slot(i); 150 if (_advanced) { 151 for (AdvancedState s : _advancedStates) { 152 if (s._state == slot.slotStatus()) match = true; 153 } 154 } else { 155 if (_simpleState.matches(slot.slotStatus())) match = true; 156 } 157 if (_hasHasNot == Has_HasNot.Has) { 158 if (match) count++; 159 } else { 160 if (!match) count++; 161 } 162 } 163 return count; 164 } 165 166 /** {@inheritDoc} */ 167 @Override 168 public boolean evaluate() { 169 int count = getNumWithStatus(); 170 171 int compareToNum = _percentPieces == PercentPieces.Percent 172 ? Math.round(((float)_number) / 100 * _totalSlots) : _number; 173 174 return _compare.compare(count, compareToNum); 175 } 176 177 @Override 178 public FemaleSocket getChild(int index) throws IllegalArgumentException, UnsupportedOperationException { 179 throw new UnsupportedOperationException("Not supported."); 180 } 181 182 @Override 183 public int getChildCount() { 184 return 0; 185 } 186 187 @Override 188 public String getShortDescription(Locale locale) { 189 return Bundle.getMessage(locale, "ExpressionSlotUsage_Short"); 190 } 191 192 @Override 193 public String getLongDescription(Locale locale) { 194 String stateStr; 195 if (_advanced) { 196 StringBuilder states = new StringBuilder(); 197 for (AdvancedState state : _advancedStates) { 198 if (states.length() > 0) states.append(","); 199 states.append(state._text); 200 } 201 stateStr = states.length() > 0 ? states.toString() : Bundle.getMessage("NoState"); 202 } else { 203 stateStr = _simpleState._text; 204 } 205 206 return Bundle.getMessage(locale, "ExpressionSlotUsage_LongConnection", 207 _hasHasNot.toString(), 208 stateStr, 209 _compare.toString(), 210 _number, 211 _percentPieces.toString(), 212 _memo != null ? _memo.getUserName() : Bundle.getMessage("MemoNotSet") 213 ); 214 } 215 216 /** {@inheritDoc} */ 217 @Override 218 public void setup() { 219 // Do nothing 220 } 221 222 /** {@inheritDoc} */ 223 @Override 224 public void registerListenersForThisClass() { 225 if (!_listenersAreRegistered) { 226 _listenersAreRegistered = true; 227 228 if (_memo != null) { 229 SlotManager slotManager = _memo.getSlotManager(); 230 slotManager.addSlotListener(this); 231 232// slotManager.getInUseCount(); 233 } 234 } 235 } 236 237 /** {@inheritDoc} */ 238 @Override 239 public void unregisterListenersForThisClass() { 240 if (_memo != null) { 241 SlotManager slotManager = _memo.getSlotManager(); 242 slotManager.removeSlotListener(this); 243 } 244 _listenersAreRegistered = false; 245 } 246 247 /** {@inheritDoc} */ 248 @Override 249 public void disposeMe() { 250 } 251 252 @Override 253 public void notifyChangedSlot(LocoNetSlot s) { 254 if (_listenersAreRegistered) { 255 getConditionalNG().execute(); 256 } 257 } 258 259 260 261 public enum Has_HasNot { 262 Has(Bundle.getMessage("HasHasNotType_Has")), 263 HasNot(Bundle.getMessage("HasHasNotType_HasNot")); 264 265 private final String _text; 266 267 private Has_HasNot(String text) { 268 this._text = text; 269 } 270 271 @Override 272 public String toString() { 273 return _text; 274 } 275 276 } 277 278 279 public enum SimpleState { 280 InUse(Bundle.getMessage("SimpleStateType_InUse"), new int[]{LnConstants.LOCO_IN_USE}), 281 Free(Bundle.getMessage("SimpleStateType_Free"), new int[]{LnConstants.LOCO_FREE}); 282 283 private final String _text; 284 private final int[] _states; 285 286 private SimpleState(String text, int[] states) { 287 this._text = text; 288 this._states = states; 289 } 290 291 @Override 292 public String toString() { 293 return _text; 294 } 295 296 public int[] getStates() { 297 return _states; 298 } 299 300 public boolean matches(int state) { 301 for (int s : _states) { 302 if (s == state) return true; 303 } 304 return false; 305 } 306 307 } 308 309 310 public enum AdvancedState { 311 InUse(LnConstants.LOCO_IN_USE, Bundle.getMessage("AdvancedStateType_InUse")), 312 Idle(LnConstants.LOCO_IDLE, Bundle.getMessage("AdvancedStateType_Idle")), 313 Common(LnConstants.LOCO_COMMON, Bundle.getMessage("AdvancedStateType_Common")), 314 Free(LnConstants.LOCO_FREE, Bundle.getMessage("AdvancedStateType_Free")); 315 316 private final int _state; 317 private final String _text; 318 319 private AdvancedState(int state, String text) { 320 this._state = state; 321 this._text = text; 322 } 323 324 public int getState() { 325 return _state; 326 } 327 328 @Override 329 public String toString() { 330 return _text; 331 } 332 333 } 334 335 336 public enum Compare { 337 LessThan(Bundle.getMessage("CompareType_LessThan"), (int a, int b) -> a < b), 338 LessThanOrEqual(Bundle.getMessage("CompareType_LessThanOrEqual"), (int a, int b) -> a <= b), 339 Equal(Bundle.getMessage("CompareType_Equal"), (int a, int b) -> a == b), 340 NotEqual(Bundle.getMessage("CompareType_NotEqual"), (int a, int b) -> a != b), 341 GreaterThanOrEqual(Bundle.getMessage("CompareType_GreaterThanOrEqual"), (int a, int b) -> a >= b), 342 GreaterThan(Bundle.getMessage("CompareType_GreaterThan"), (int a, int b) -> a > b); 343 344 private final String _text; 345 private final CompareIntegers _compare; 346 347 private Compare(String text, CompareIntegers compare) { 348 this._text = text; 349 this._compare = compare; 350 } 351 352 @Override 353 public String toString() { 354 return _text; 355 } 356 357 public boolean compare(int a, int b) { 358 return _compare.compare(a, b); 359 } 360 361 } 362 363 364 public enum PercentPieces { 365 Percent(Bundle.getMessage("PercentPiecesType_Percent")), 366 Pieces(Bundle.getMessage("PercentPiecesType_Pieces")); 367 368 private final String _text; 369 370 private PercentPieces(String text) { 371 this._text = text; 372 } 373 374 @Override 375 public String toString() { 376 return _text; 377 } 378 379 } 380 381 382 private interface CompareIntegers { 383 public boolean compare(int a, int b); 384 } 385 386 387 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ExpressionSlotUsage.class); 388 389}