001package jmri; 002 003import java.util.Date; 004import java.util.ResourceBundle; 005import jmri.Conditional.Operator; 006import jmri.jmrit.beantable.LogixTableAction; 007import jmri.jmrit.logix.OBlock; 008import jmri.jmrit.logix.Warrant; 009import jmri.jmrit.logix.WarrantManager; 010import org.slf4j.Logger; 011import org.slf4j.LoggerFactory; 012 013/** 014 * The variable used in the antecedent (the 'if' part) of the Conditional. 015 * proposition. The states of ConditionalVariables and logic expression of the 016 * antecedent determine the state of the Conditional. 017 * <p> 018 * ConditionalVariable objects are fully mutable, so use the default equals() 019 * operator that checks for identical objects, not identical contents. 020 * 021 * This file is part of JMRI. 022 * <p> 023 * JMRI is free software; you can redistribute it and/or modify it under the 024 * terms of version 2 of the GNU General Public License as published by the Free 025 * Software Foundation. See the "COPYING" file for a copy of this license. 026 * <p> 027 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY 028 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 029 * A PARTICULAR PURPOSE. See the GNU General Public License for more details. 030 * 031 * @author Pete Cressman Copyright (C) 2009 032 * @author Bob Jacobsen Copyright (C) 2016 033 */ 034public class ConditionalVariable { 035 036 static final ResourceBundle rbx = ResourceBundle.getBundle("jmri.jmrit.conditional.ConditionalBundle"); 037 038 public static final int NUM_COMPARE_OPERATIONS = 5; 039 public static final int LESS_THAN = 1; 040 public static final int LESS_THAN_OR_EQUAL = 2; 041 public static final int EQUAL = 3; 042 public static final int GREATER_THAN_OR_EQUAL = 4; 043 public static final int GREATER_THAN = 5; 044 045 private boolean _not = false; 046 // Not a variable attribute, but retained as an artifact of previous releases. This will be used 047 // as the default operator immediately to the left of this variable in the antecedent statement. 048 // It may be over written by the antecedent statement in the Conditional to which this variable 049 // belongs. 050 private Operator _opern = Operator.NONE; 051 private Conditional.Type _type = Conditional.Type.NONE; 052 private String _name = ""; 053 private String _dataString = ""; 054 private int _num1 = 0; 055 private int _num2 = 0; 056 private String _guiName = ""; // Contains the user name of the referenced conditional 057 private NamedBeanHandle<?> _namedBean = null; 058 //private NamedBeanHandle<Sensor> _namedSensorBean = null; 059 protected jmri.NamedBeanHandleManager nbhm = jmri.InstanceManager.getDefault(jmri.NamedBeanHandleManager.class); 060 // Name clarification: Formerly was named '_triggersCalculation' because it controlled whether 061 // a listener was installed for this device and thus trigger calculation of the Conditional. 062 // Now named '_triggersActions' because listeners are always installed for activated Logix 063 // Conditionals and this parameter nows controls whether, if its change of state changes the 064 // state of the conditional, should that also trigger the actions. 065 private boolean _triggersActions = true; 066 private int _state = NamedBean.UNKNOWN; // tri-state 067 068 /** 069 * Create a blank ConditionalVariable, to be filled in later. 070 */ 071 public ConditionalVariable() { 072 } 073 074 /** 075 * Create a ConditionalVariable with a set of given properties. 076 * @param not true if the ConditionalVariable should be negated 077 * @param opern the boolean operator for this ConditionalVariable 078 * @param type the type this ConditionalVariable operates on (Turnout, Sensor, ...) 079 * @param name the device name 080 * @param trigger true if actions should be performed if triggered 081 */ 082 public ConditionalVariable(boolean not, Operator opern, Conditional.Type type, String name, boolean trigger) { 083 _not = not; 084 // setOpern does some checks of opern 085 _opern = opern; 086 _type = type; 087 _name = name; 088 _triggersActions = trigger; 089 _guiName = ""; 090 try { 091 Conditional.ItemType itemType = type.getItemType(); 092 switch (itemType) { 093 case SENSOR: 094 try { 095 Sensor sn = InstanceManager.sensorManagerInstance().provideSensor(_name); 096 _namedBean = nbhm.getNamedBeanHandle(_name, sn); 097 } catch (IllegalArgumentException e) { 098 log.error("invalid sensor name= \"{}\" in state variable", _name); 099 } 100 break; 101 case TURNOUT: 102 try { 103 Turnout tn = InstanceManager.turnoutManagerInstance().provideTurnout(_name); 104 _namedBean = nbhm.getNamedBeanHandle(_name, tn); 105 } catch (IllegalArgumentException e) { 106 log.error("invalid turnout name= \"{}\" in state variable", _name); 107 } 108 break; 109 case MEMORY: 110 try { 111 Memory my = InstanceManager.memoryManagerInstance().provideMemory(_name); 112 _namedBean = nbhm.getNamedBeanHandle(_name, my); 113 } catch (IllegalArgumentException e) { 114 log.error("invalid memory name= \"{}\" in state variable", _name); 115 } 116 break; 117 case LIGHT: 118 try { 119 Light l = InstanceManager.lightManagerInstance().provideLight(_name); 120 _namedBean = nbhm.getNamedBeanHandle(_name, l); 121 } catch (IllegalArgumentException e) { 122 log.error("invalid light name= \"{}\" in state variable", _name); 123 } 124 break; 125 case SIGNALHEAD: 126 SignalHead s = InstanceManager.getDefault(jmri.SignalHeadManager.class).getSignalHead(_name); 127 if (s == null) { 128 log.error("invalid signalhead name= \"{}\" in state variable", _name); 129 return; 130 } 131 _namedBean = nbhm.getNamedBeanHandle(_name, s); 132 break; 133 case SIGNALMAST: 134 try { 135 SignalMast sm = InstanceManager.getDefault(jmri.SignalMastManager.class).provideSignalMast(_name); 136 _namedBean = nbhm.getNamedBeanHandle(_name, sm); 137 } catch (IllegalArgumentException e) { 138 log.error("invalid signalmast name= \"{}\" in state variable", _name); 139 } 140 break; 141 case ENTRYEXIT: 142 NamedBean nb = jmri.InstanceManager.getDefault(jmri.jmrit.entryexit.EntryExitPairs.class).getBySystemName(_name); 143 if (nb == null) { 144 log.error("invalid entry exit name= \"{}\" in state variable", _name); 145 return; 146 } 147 _namedBean = nbhm.getNamedBeanHandle(_name, nb); 148 break; 149 case CONDITIONAL: 150 Conditional c = InstanceManager.getDefault(jmri.ConditionalManager.class).getConditional(_name); 151 if (c == null) { 152 log.error("invalid conditional; name= \"{}\" in state variable", _name); 153 return; 154 } 155 _namedBean = nbhm.getNamedBeanHandle(_name, c); 156 break; 157 case WARRANT: 158 Warrant w = InstanceManager.getDefault(WarrantManager.class).getWarrant(_name); 159 if (w == null) { 160 log.error("invalid warrant name= \"{}\" in state variable", _name); 161 return; 162 } 163 _namedBean = nbhm.getNamedBeanHandle(_name, w); 164 break; 165 case OBLOCK: 166 OBlock b = InstanceManager.getDefault(jmri.jmrit.logix.OBlockManager.class).getOBlock(_name); 167 if (b == null) { 168 log.error("invalid block name= \"{}\" in state variable", _name); 169 return; 170 } 171 _namedBean = nbhm.getNamedBeanHandle(_name, b); 172 break; 173 174 default: 175 log.warn("Unexpected type in ConditionalVariable ctor: {} -> {}", _type, itemType); 176 break; 177 } 178 } catch (java.lang.NumberFormatException ex) { 179 //Can be Considered Normal where the logix is loaded prior to any other beans 180 } catch (IllegalArgumentException ex) { 181 log.warn("could not provide \"{}\" in constructor", _name); 182 _namedBean = null; 183 } 184 } 185 186 public boolean isNegated() { 187 return _not; 188 } 189 190 public void setNegation(boolean not) { 191 _not = not; 192 } 193 194 public Operator getOpern() { 195 return _opern; 196 } 197 198 public final void setOpern(Operator opern) { 199 _opern = opern; 200 } 201 202 public Conditional.Type getType() { 203 return _type; 204 } 205 206 public void setType(Conditional.Type type) { 207 _type = type; 208 } 209 210 public String getName() { 211 if (_namedBean != null) { 212 return _namedBean.getName(); 213 } 214 /* As we have a trigger for something using the variable, then hopefully 215 all the managers have been loaded and we can get the bean, which prevented 216 the bean from being loaded in the first place */ 217 setName(_name); 218 return _name; 219 } 220 221 public void setName(String name) { 222 _name = name; 223 NamedBean bean = null; 224 Conditional.ItemType itemType = _type.getItemType(); 225 226 try { 227 switch (itemType) { 228 case NONE: 229 break; 230 case CLOCK: 231 break; // no beans for these, at least that I know of 232 case SENSOR: 233 bean = InstanceManager.sensorManagerInstance().provideSensor(_name); 234 break; 235 case TURNOUT: 236 bean = InstanceManager.turnoutManagerInstance().provideTurnout(_name); 237 break; 238 case LIGHT: 239 bean = InstanceManager.lightManagerInstance().getLight(_name); 240 break; 241 case MEMORY: 242 bean = InstanceManager.memoryManagerInstance().provideMemory(_name); 243 break; 244 case SIGNALMAST: 245 bean = InstanceManager.getDefault(jmri.SignalMastManager.class).provideSignalMast(_name); 246 break; 247 case SIGNALHEAD: 248 bean = InstanceManager.getDefault(jmri.SignalHeadManager.class).getSignalHead(_name); 249 break; 250 case CONDITIONAL: 251 bean = InstanceManager.getDefault(jmri.ConditionalManager.class).getConditional(_name); 252 break; 253 case WARRANT: 254 bean = InstanceManager.getDefault(WarrantManager.class).getWarrant(_name); 255 break; 256 case OBLOCK: 257 bean = InstanceManager.getDefault(jmri.jmrit.logix.OBlockManager.class).getOBlock(_name); 258 break; 259 case ENTRYEXIT: 260 bean = jmri.InstanceManager.getDefault(jmri.jmrit.entryexit.EntryExitPairs.class).getNamedBean(_name); 261 break; 262 default: 263 log.error("Type {} not set for {}", itemType, _name); 264 } 265 266 //Once all refactored, we should probably register an error if the bean is returned null. 267 if (bean != null) { 268 _namedBean = nbhm.getNamedBeanHandle(_name, bean); 269 } else { 270 log.debug("Did not have or create \"{}\" in setName. namedBean is unchanged", _name); 271 } 272 273 } catch (IllegalArgumentException ex) { 274 log.warn("Did not have or create \"{}\" in setName", _name); 275 _namedBean = null; 276 } 277 } 278 279 public NamedBeanHandle<?> getNamedBean() { 280 return _namedBean; 281 } 282 283 public NamedBean getBean() { 284 if (_namedBean != null) { 285 return _namedBean.getBean(); 286 } 287 setName(_name); //ReApply name as that will create namedBean, save replicating it here 288 if (_namedBean != null) { 289 return _namedBean.getBean(); 290 } 291 return null; 292 } 293 294 public String getDataString() { 295 if (_type.getItemType() == Conditional.ItemType.MEMORY 296 && _namedBeanData != null) { 297 return _namedBeanData.getName(); 298 } 299 return _dataString; 300 } 301 302 public void setDataString(String data) { 303 _dataString = data; 304 if (data != null && !data.equals("") 305 && _type.getItemType() == Conditional.ItemType.MEMORY) { 306 NamedBean bean = InstanceManager.memoryManagerInstance().getMemory(data); 307 if (bean != null) { 308 _namedBeanData = nbhm.getNamedBeanHandle(data, bean); 309 } 310 } 311 } 312 313 private NamedBeanHandle<?> _namedBeanData = null; 314 315 public NamedBean getNamedBeanData() { 316 if (_namedBeanData != null) { 317 return _namedBeanData.getBean(); 318 } 319 return null; 320 } 321 322 public int getNum1() { 323 return _num1; 324 } 325 326 public void setNum1(int num) { 327 _num1 = num; 328 } 329 330 public int getNum2() { 331 return _num2; 332 } 333 334 public void setNum2(int num) { 335 _num2 = num; 336 } 337 338 /** 339 * @since 4.7.4 340 * @return the GUI name for the referenced conditional. 341 */ 342 public String getGuiName() { 343 return _guiName; 344 } 345 346 /** 347 * Set the GUI name for the conditional state variable. 348 * @since 4.7.4 349 * @param guiName The referenced Conditional user name. 350 */ 351 public void setGuiName(String guiName) { 352 _guiName = guiName; 353 } 354 355 356 /** 357 * If change of state of this object causes a change of state of the 358 * Conditional, should any actions be executed. 359 * 360 * @return true if actions should be performed if triggered 361 */ 362 public boolean doTriggerActions() { 363 return _triggersActions; 364 } 365 366 public void setTriggerActions(boolean trigger) { 367 _triggersActions = trigger; 368 } 369 370 public int getState() { 371 return _state; 372 } 373 374 public void setState(int state) { 375 _state = state; 376 } 377 378 public void setState(boolean state) { 379 if (state) { 380 _state = Conditional.TRUE; 381 } else { 382 _state = Conditional.FALSE; 383 } 384 } 385 386 public String getTestTypeString() { 387 return _type.getTestTypeString(); 388 } 389 390 /** 391 * Provide a localized text for screen display of the logic operator. 392 * 393 * @return translated string (from jmri.NamedBeanBundle.properties) 394 */ 395 public String getOpernString() { 396 switch (_opern) { 397 case AND: 398 return Bundle.getMessage("LogicAND"); // NOI18N 399 case NONE: 400 return ""; 401 case OR: 402 return Bundle.getMessage("LogicOR"); // NOI18N 403 default: 404 return ""; 405 } 406 } 407 408 /** 409 * Evaluates this State Variable. 410 * 411 * @return true if variable evaluates true, otherwise false. 412 */ 413 @SuppressWarnings("deprecation") // Date.getMinutes, Date.getHours 414 public boolean evaluate() { 415 boolean result = true; 416 // evaluate according to state variable type 417 Conditional.ItemType itemType = _type.getItemType(); 418 log.debug("evaluate: \"{}\" type= {} itemType= {}", getName(), _type, itemType); 419 switch (itemType) { 420 case SENSOR: 421 //Sensor sn = InstanceManager.sensorManagerInstance().provideSensor(getName()); 422 Sensor sn = (Sensor) getBean(); 423 if (sn == null) { 424 log.error("invalid sensor name= \"{}\" in state variable", getName()); 425 return false; 426 } 427 if (_type == Conditional.Type.SENSOR_ACTIVE) { 428 result = sn.getState() == Sensor.ACTIVE; 429 } else { 430 result = sn.getState() == Sensor.INACTIVE; 431 } 432 break; 433 case TURNOUT: 434 Turnout t = (Turnout) getBean(); 435 if (t == null) { 436 log.error("invalid turnout name= \"{}\" in state variable", getName()); 437 return false; 438 } 439 if (_type == Conditional.Type.TURNOUT_THROWN) { 440 result = t.getKnownState() == Turnout.THROWN; 441 } else { 442 result = t.getKnownState() == Turnout.CLOSED; 443 } 444 break; 445 case LIGHT: 446 Light lgt = (Light) getBean(); 447 if (lgt == null) { 448 log.error("invalid light name= \"{}\" in state variable", getName()); 449 return false; 450 } 451 if (_type == Conditional.Type.LIGHT_ON) { 452 result = lgt.getState() == Light.ON; 453 } else { 454 result = lgt.getState() == Light.OFF; 455 } 456 break; 457 case SIGNALMAST: 458 SignalMast f = (SignalMast) getBean(); 459 if (f == null) { 460 log.error("invalid signal mast name= \"{}\" in state variable", getName()); 461 return false; 462 } 463 switch (_type) { 464 case SIGNAL_MAST_LIT: 465 result = f.getLit(); 466 break; 467 case SIGNAL_MAST_HELD: 468 result = f.getHeld(); 469 break; 470 case SIGNAL_MAST_ASPECT_EQUALS: 471 String aspect = f.getAspect(); 472 if ( aspect == null) { 473 result = false; 474 } else { 475 result = aspect.equals(_dataString); 476 } 477 break; 478 default: 479 log.warn("unexpected type {} in ITEM_TYPE_SIGNALMAST", _type); 480 } 481 break; 482 case SIGNALHEAD: 483 SignalHead h = (SignalHead) getBean(); 484 if (h == null) { 485 log.error("invalid signal head name= \"{}\" in state variable", getName()); 486 return false; 487 } 488 switch (_type) { 489 case SIGNAL_HEAD_RED: 490 result = h.getAppearance() == SignalHead.RED; 491 break; 492 case SIGNAL_HEAD_YELLOW: 493 result = h.getAppearance() == SignalHead.YELLOW; 494 break; 495 case SIGNAL_HEAD_GREEN: 496 result = h.getAppearance() == SignalHead.GREEN; 497 break; 498 case SIGNAL_HEAD_DARK: 499 result = h.getAppearance() == SignalHead.DARK; 500 break; 501 case SIGNAL_HEAD_FLASHRED: 502 result = h.getAppearance() == SignalHead.FLASHRED; 503 break; 504 case SIGNAL_HEAD_FLASHYELLOW: 505 result = h.getAppearance() == SignalHead.FLASHYELLOW; 506 break; 507 case SIGNAL_HEAD_FLASHGREEN: 508 result = h.getAppearance() == SignalHead.FLASHGREEN; 509 break; 510 case SIGNAL_HEAD_LUNAR: 511 result = h.getAppearance() == SignalHead.LUNAR; 512 break; 513 case SIGNAL_HEAD_FLASHLUNAR: 514 result = h.getAppearance() == SignalHead.FLASHLUNAR; 515 break; 516 case SIGNAL_HEAD_LIT: 517 result = h.getLit(); 518 break; 519 case SIGNAL_HEAD_HELD: 520 result = h.getHeld(); 521 break; 522 default: 523 result = false; 524 } 525 break; 526 case MEMORY: 527 Memory m = (Memory) getBean(); 528 if (m == null) { 529 log.error("invalid memory name= \"{}\" in state variable", getName()); 530 return false; 531 } 532 String value1 = null; 533 String value2 = null; 534 if (m.getValue() != null) { 535 value1 = m.getValue().toString(); 536 } 537 boolean caseInsensitive = ((_type == Conditional.Type.MEMORY_EQUALS_INSENSITIVE) 538 || (_type == Conditional.Type.MEMORY_COMPARE_INSENSITIVE)); 539 if ((_type == Conditional.Type.MEMORY_COMPARE) 540 || (_type == Conditional.Type.MEMORY_COMPARE_INSENSITIVE)) { 541 Memory m2; 542 if (_namedBeanData != null) { 543 m2 = (Memory) _namedBeanData.getBean(); 544 } else { 545 try { 546 m2 = InstanceManager.memoryManagerInstance().provideMemory(_dataString); 547 } catch (IllegalArgumentException ex) { 548 log.error("invalid data memory name= \"{}\" in state variable", _dataString); 549 return false; 550 } 551 } 552 if (m2.getValue() != null) { 553 value2 = m2.getValue().toString(); 554 } 555 } else { 556 value2 = _dataString; 557 } 558 result = compare(value1, value2, caseInsensitive); 559 break; 560 case CONDITIONAL: 561 Conditional c = InstanceManager.getDefault(jmri.ConditionalManager.class).getBySystemName(getName()); 562 if (c == null) { 563 c = InstanceManager.getDefault(jmri.ConditionalManager.class).getByUserName(getName()); 564 if (c == null) { 565 log.error("invalid conditional name= \"{}\" in state variable", getName()); 566 return false; 567 } 568 } 569 if (_type == Conditional.Type.CONDITIONAL_TRUE) { 570 result = c.getState() == Conditional.TRUE; 571 } else { 572 result = c.getState() == Conditional.FALSE; 573 } 574 break; 575 case WARRANT: 576 Warrant w = InstanceManager.getDefault(WarrantManager.class).getWarrant(getName()); 577 if (w == null) { 578 log.error("invalid Warrant name= \"{}\" in state variable", getName()); 579 return false; 580 } 581 switch (_type) { 582 case ROUTE_FREE: 583 result = w.routeIsFree(); 584 break; 585 case ROUTE_OCCUPIED: 586 result = w.routeIsOccupied(); 587 break; 588 case ROUTE_ALLOCATED: 589 result = w.isAllocated(); 590 break; 591 case ROUTE_SET: 592 result = w.hasRouteSet(); 593 break; 594 case TRAIN_RUNNING: 595 // not in either RUN or LEARN state 596 result = !(w.getRunMode() == Warrant.MODE_NONE); 597 break; 598 default: 599 result = false; 600 } 601 break; 602 case CLOCK: 603 Timebase fastClock = InstanceManager.getDefault(jmri.Timebase.class); 604 Date currentTime = fastClock.getTime(); 605 int currentMinutes = (currentTime.getHours() * 60) + currentTime.getMinutes(); 606 int beginTime = fixMidnight(_num1); 607 int endTime = fixMidnight(_num2); 608 // check if current time is within range specified 609 if (beginTime <= endTime) { 610 // range is entirely within one day 611 result = (beginTime <= currentMinutes) && (currentMinutes <= endTime); 612 } else { 613 // range includes midnight 614 result = beginTime <= currentMinutes || currentMinutes <= endTime; 615 } 616 break; 617 case OBLOCK: 618 OBlock b = InstanceManager.getDefault(jmri.jmrit.logix.OBlockManager.class).getOBlock(getName()); 619 if (b == null) { 620 log.error("invalid OBlock name= \"{}\" in state variable", getName()); 621 return false; 622 } 623 result = b.statusIs(_dataString); 624 break; 625 case ENTRYEXIT: 626 NamedBean e = getBean(); 627 if (_type == Conditional.Type.ENTRYEXIT_ACTIVE) { 628 result = e.getState() == 0x02; 629 } else { 630 result = e.getState() == 0x04; 631 } 632 break; 633 default: 634 break; 635 } 636 // apply NOT if specified 637 if (_not) { 638 result = !result; 639 } 640 if (result) { 641 setState(Conditional.TRUE); 642 } else { 643 setState(Conditional.FALSE); 644 } 645 return (result); 646 } 647 648 /** 649 * Compare two values using the comparator set using the comparison 650 * instructions in {@link #setNum1(int)}. 651 * 652 * <strong>Note:</strong> {@link #getNum1()} must be one of {@link #LESS_THAN}, 653 * {@link #LESS_THAN_OR_EQUAL}, {@link #EQUAL}, 654 * {@link #GREATER_THAN_OR_EQUAL}, or {@link #GREATER_THAN}. 655 * 656 * @param value1 left side of the comparison 657 * @param value2 right side of the comparison 658 * @param caseInsensitive true if comparison should be case insensitive; 659 * false otherwise 660 * @return true if values compare per getNum1(); false otherwise 661 */ 662 boolean compare(String value1, String value2, boolean caseInsensitive) { 663 if (value1 == null) { 664 return value2 == null; 665 } else { 666 if (value2 == null) { 667 return false; 668 } 669 value1 = value1.trim(); 670 value2 = value2.trim(); 671 } 672 try { 673 int n1 = Integer.parseInt(value1); 674 try { 675 int n2 = Integer.parseInt(value2); 676 if (_num1 == 0) { // for former code 677 return n1 == n2; 678 } 679 log.debug("Compare numbers: n1= {} to n2= {}", n1, n2); 680 switch (_num1) // both are numbers 681 { 682 case LESS_THAN: 683 return (n1 < n2); 684 case LESS_THAN_OR_EQUAL: 685 return (n1 <= n2); 686 case EQUAL: 687 return (n1 == n2); 688 case GREATER_THAN_OR_EQUAL: 689 return (n1 >= n2); 690 case GREATER_THAN: 691 return (n1 > n2); 692 default: 693 log.error("Compare numbers: invalid compare case: {}", _num1); 694 return false; 695 } 696 } catch (NumberFormatException nfe) { 697 return false; // n1 is a number, n2 is not 698 } 699 } catch (NumberFormatException nfe) { 700 try { 701 Integer.parseInt(value2); 702 return false; // n1 is not a number, n2 is 703 } catch (NumberFormatException ex) { // OK neither a number 704 } 705 } 706 log.debug("Compare Strings: value1= {} to value2= {}", value1, value2); 707 int compare; 708 if (caseInsensitive) { 709 compare = value1.compareToIgnoreCase(value2); 710 } else { 711 compare = value1.compareTo(value2); 712 } 713 if (_num1 == 0) { // for former code 714 return compare == 0; 715 } 716 switch (_num1) { 717 case LESS_THAN: 718 if (compare < 0) { 719 return true; 720 } 721 break; 722 case LESS_THAN_OR_EQUAL: 723 if (compare <= 0) { 724 return true; 725 } 726 break; 727 case EQUAL: 728 if (compare == 0) { 729 return true; 730 } 731 break; 732 case GREATER_THAN_OR_EQUAL: 733 if (compare >= 0) { 734 return true; 735 } 736 break; 737 case GREATER_THAN: 738 if (compare > 0) { 739 return true; 740 } 741 break; 742 default: 743 // fall through 744 break; 745 } 746 return false; 747 } 748 749 public static int fixMidnight(int time) { 750 if (time > 24 * 60) { 751 time -= 24 * 60; 752 } 753 return time; 754 } 755 756 /** 757 * Convert Variable Type to Text String 758 * 759 * @param t the type 760 * @return the localized description 761 */ 762 public static String getItemTypeString(Conditional.ItemType t) { 763 switch (t) { 764 case SENSOR: 765 return Bundle.getMessage("BeanNameSensor"); // NOI18N 766 case TURNOUT: 767 return Bundle.getMessage("BeanNameTurnout"); // NOI18N 768 case LIGHT: 769 return Bundle.getMessage("BeanNameLight"); // NOI18N 770 case SIGNALHEAD: 771 return Bundle.getMessage("BeanNameSignalHead"); // NOI18N 772 case SIGNALMAST: 773 return Bundle.getMessage("BeanNameSignalMast"); // NOI18N 774 case MEMORY: 775 return Bundle.getMessage("BeanNameMemory"); // NOI18N 776 case CONDITIONAL: 777 return Bundle.getMessage("BeanNameConditional"); // NOI18N 778 case WARRANT: 779 return Bundle.getMessage("BeanNameWarrant"); // NOI18N 780 case CLOCK: 781 return Bundle.getMessage("FastClock"); // NOI18N 782 case OBLOCK: 783 return Bundle.getMessage("BeanNameOBlock"); // NOI18N 784 case ENTRYEXIT: 785 return Bundle.getMessage("BeanNameEntryExit"); // NOI18N 786 default: 787 return ""; 788 } 789 } 790 791 public static String getCompareOperationString(int index) { 792 switch (index) { 793 case LESS_THAN: 794 return rbx.getString("LessThan"); // NOI18N 795 case LESS_THAN_OR_EQUAL: 796 return rbx.getString("LessOrEqual"); // NOI18N 797 case 0: 798 case EQUAL: 799 return rbx.getString("Equal"); // NOI18N 800 case GREATER_THAN_OR_EQUAL: 801 return rbx.getString("GreaterOrEqual"); // NOI18N 802 case GREATER_THAN: 803 return rbx.getString("GreaterThan"); // NOI18N 804 default: 805 // fall through 806 break; 807 } 808 return ""; // NOI18N 809 } 810 811 public static String getCompareSymbols(int index) { 812 switch (index) { 813 case LESS_THAN: 814 return "<"; // NOI18N 815 case LESS_THAN_OR_EQUAL: 816 return "<="; // NOI18N 817 case 0: 818 case EQUAL: 819 return "="; // NOI18N 820 case GREATER_THAN_OR_EQUAL: 821 return ">="; // NOI18N 822 case GREATER_THAN: 823 return ">"; // NOI18N 824 default: 825 break; 826 } 827 return ""; // NOI18N 828 } 829 830 /** 831 * Identify action Data from Text String. 832 * 833 * @param str the text to check 834 * @return the conditional action type or -1 if if string does not 835 * correspond to an action Data as defined in ConditionalAction 836 */ 837 public static Conditional.Type stringToVariableTest(String str) { 838 if (str.equals(Bundle.getMessage("SignalHeadStateRed"))) { // NOI18N 839 return Conditional.Type.SIGNAL_HEAD_RED; 840 } else if (str.equals(Bundle.getMessage("SignalHeadStateYellow"))) { // NOI18N 841 return Conditional.Type.SIGNAL_HEAD_YELLOW; 842 } else if (str.equals(Bundle.getMessage("SignalHeadStateGreen"))) { // NOI18N 843 return Conditional.Type.SIGNAL_HEAD_GREEN; 844 } else if (str.equals(Bundle.getMessage("SignalHeadStateDark"))) { // NOI18N 845 return Conditional.Type.SIGNAL_HEAD_DARK; 846 } else if (str.equals(Bundle.getMessage("SignalHeadStateFlashingRed"))) { // NOI18N 847 return Conditional.Type.SIGNAL_HEAD_FLASHRED; 848 } else if (str.equals(Bundle.getMessage("SignalHeadStateFlashingYellow"))) { // NOI18N 849 return Conditional.Type.SIGNAL_HEAD_FLASHYELLOW; 850 } else if (str.equals(Bundle.getMessage("SignalHeadStateFlashingGreen"))) { // NOI18N 851 return Conditional.Type.SIGNAL_HEAD_FLASHGREEN; 852 } else if (str.equals(Bundle.getMessage("SignalHeadStateLunar"))) { // NOI18N 853 return Conditional.Type.SIGNAL_HEAD_LUNAR; 854 } else if (str.equals(Bundle.getMessage("SignalHeadStateFlashingLunar"))) { // NOI18N 855 return Conditional.Type.SIGNAL_HEAD_FLASHLUNAR; 856 } 857 // empty strings can occur frequently with types that have no integer data 858 if (str.length() > 0) { 859 log.warn("Unexpected parameter to stringToVariableTest({})", str); 860 } 861 return Conditional.Type.ERROR; 862 } 863 864 @Override 865 public String toString() { 866 String type = _type.getTestTypeString(); 867 Conditional.ItemType itemType = _type.getItemType(); 868 switch (itemType) { 869 case SENSOR: 870 return java.text.MessageFormat.format(rbx.getString("VarStateDescrpt"), 871 new Object[]{Bundle.getMessage("BeanNameSensor"), getName(), type}); 872 case TURNOUT: 873 return java.text.MessageFormat.format(rbx.getString("VarStateDescrpt"), 874 new Object[]{Bundle.getMessage("BeanNameTurnout"), getName(), type}); 875 case LIGHT: 876 return java.text.MessageFormat.format(rbx.getString("VarStateDescrpt"), 877 new Object[]{Bundle.getMessage("BeanNameLight"), getName(), type}); 878 case SIGNALHEAD: 879 if ((_type == Conditional.Type.SIGNAL_HEAD_LIT) 880 || (_type == Conditional.Type.SIGNAL_HEAD_HELD)) { 881 return java.text.MessageFormat.format(rbx.getString("VarStateDescrpt"), 882 new Object[]{Bundle.getMessage("BeanNameSignalHead"), getName(), type}); 883 } else { 884 return java.text.MessageFormat.format(rbx.getString("SignalHeadStateDescrpt"), 885 new Object[]{Bundle.getMessage("BeanNameSignalHead"), getName(), type}); 886 } 887 case SIGNALMAST: 888 if ((_type == Conditional.Type.SIGNAL_MAST_LIT) 889 || (_type == Conditional.Type.SIGNAL_MAST_HELD)) { 890 return java.text.MessageFormat.format(rbx.getString("VarStateDescrpt"), 891 new Object[]{Bundle.getMessage("BeanNameSignalMast"), getName(), type}); // NOI18N 892 } else { 893 return java.text.MessageFormat.format(rbx.getString("SignalMastStateDescrpt"), 894 new Object[]{Bundle.getMessage("BeanNameSignalMast"), getName(), _dataString}); // NOI18N 895 } 896 case MEMORY: 897 if ((_type == Conditional.Type.MEMORY_EQUALS) 898 || (_type == Conditional.Type.MEMORY_EQUALS_INSENSITIVE)) { 899 return java.text.MessageFormat.format(rbx.getString("MemoryValueDescrpt"), 900 new Object[]{Bundle.getMessage("BeanNameMemory"), getName(), // NOI18N 901 getCompareSymbols(_num1), _dataString}); 902 } else { 903 return java.text.MessageFormat.format(rbx.getString("MemoryCompareDescrpt"), 904 new Object[]{Bundle.getMessage("BeanNameMemory"), getName(), // NOI18N 905 getCompareSymbols(_num1), _dataString}); 906 } 907 case CONDITIONAL: 908 return java.text.MessageFormat.format(rbx.getString("VarStateDescrpt"), 909 new Object[]{Bundle.getMessage("BeanNameConditional"), getGuiName(), type}); // NOI18N 910 case WARRANT: 911 return java.text.MessageFormat.format(rbx.getString("VarStateDescrpt"), 912 new Object[]{rbx.getString("WarrantRoute"), getName(), type}); 913 case CLOCK: 914 return java.text.MessageFormat.format(rbx.getString("FastClockDescrpt"), 915 new Object[]{Bundle.getMessage("FastClock"), 916 LogixTableAction.formatTime(_num1 / 60, _num1 - ((_num1 / 60) * 60)), 917 LogixTableAction.formatTime(_num2 / 60, _num2 - ((_num2 / 60) * 60))}); 918 case OBLOCK: 919 return java.text.MessageFormat.format(rbx.getString("VarStateDescrpt"), 920 new Object[]{rbx.getString("OBlockStatus"), getName(), _dataString}); 921 case ENTRYEXIT: 922 return java.text.MessageFormat.format(rbx.getString("VarStateDescrpt"), 923 new Object[]{Bundle.getMessage("BeanNameEntryExit"), getBean().getUserName(), type}); // NOI18N 924 case NONE: 925 return getName() + " type " + type; 926 default: 927 // fall through 928 break; 929 } 930 return super.toString(); 931 } 932 933 private final static Logger log = LoggerFactory.getLogger(ConditionalVariable.class); 934}