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