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 if (f.getAspect() == null) { 472 result = false; 473 } else { 474 result = f.getAspect().equals(_dataString); 475 } 476 break; 477 default: 478 log.warn("unexpected type {} in ITEM_TYPE_SIGNALMAST", _type); 479 } 480 break; 481 case SIGNALHEAD: 482 SignalHead h = (SignalHead) getBean(); 483 if (h == null) { 484 log.error("invalid signal head name= \"{}\" in state variable", getName()); 485 return false; 486 } 487 switch (_type) { 488 case SIGNAL_HEAD_RED: 489 result = h.getAppearance() == SignalHead.RED; 490 break; 491 case SIGNAL_HEAD_YELLOW: 492 result = h.getAppearance() == SignalHead.YELLOW; 493 break; 494 case SIGNAL_HEAD_GREEN: 495 result = h.getAppearance() == SignalHead.GREEN; 496 break; 497 case SIGNAL_HEAD_DARK: 498 result = h.getAppearance() == SignalHead.DARK; 499 break; 500 case SIGNAL_HEAD_FLASHRED: 501 result = h.getAppearance() == SignalHead.FLASHRED; 502 break; 503 case SIGNAL_HEAD_FLASHYELLOW: 504 result = h.getAppearance() == SignalHead.FLASHYELLOW; 505 break; 506 case SIGNAL_HEAD_FLASHGREEN: 507 result = h.getAppearance() == SignalHead.FLASHGREEN; 508 break; 509 case SIGNAL_HEAD_LUNAR: 510 result = h.getAppearance() == SignalHead.LUNAR; 511 break; 512 case SIGNAL_HEAD_FLASHLUNAR: 513 result = h.getAppearance() == SignalHead.FLASHLUNAR; 514 break; 515 case SIGNAL_HEAD_LIT: 516 result = h.getLit(); 517 break; 518 case SIGNAL_HEAD_HELD: 519 result = h.getHeld(); 520 break; 521 default: 522 result = false; 523 } 524 break; 525 case MEMORY: 526 Memory m = (Memory) getBean(); 527 if (m == null) { 528 log.error("invalid memory name= \"{}\" in state variable", getName()); 529 return false; 530 } 531 String value1 = null; 532 String value2 = null; 533 if (m.getValue() != null) { 534 value1 = m.getValue().toString(); 535 } 536 boolean caseInsensitive = ((_type == Conditional.Type.MEMORY_EQUALS_INSENSITIVE) 537 || (_type == Conditional.Type.MEMORY_COMPARE_INSENSITIVE)); 538 if ((_type == Conditional.Type.MEMORY_COMPARE) 539 || (_type == Conditional.Type.MEMORY_COMPARE_INSENSITIVE)) { 540 Memory m2; 541 if (_namedBeanData != null) { 542 m2 = (Memory) _namedBeanData.getBean(); 543 } else { 544 try { 545 m2 = InstanceManager.memoryManagerInstance().provideMemory(_dataString); 546 } catch (IllegalArgumentException ex) { 547 log.error("invalid data memory name= \"{}\" in state variable", _dataString); 548 return false; 549 } 550 } 551 if (m2.getValue() != null) { 552 value2 = m2.getValue().toString(); 553 } 554 } else { 555 value2 = _dataString; 556 } 557 result = compare(value1, value2, caseInsensitive); 558 break; 559 case CONDITIONAL: 560 Conditional c = InstanceManager.getDefault(jmri.ConditionalManager.class).getBySystemName(getName()); 561 if (c == null) { 562 c = InstanceManager.getDefault(jmri.ConditionalManager.class).getByUserName(getName()); 563 if (c == null) { 564 log.error("invalid conditional name= \"{}\" in state variable", getName()); 565 return false; 566 } 567 } 568 if (_type == Conditional.Type.CONDITIONAL_TRUE) { 569 result = c.getState() == Conditional.TRUE; 570 } else { 571 result = c.getState() == Conditional.FALSE; 572 } 573 break; 574 case WARRANT: 575 Warrant w = InstanceManager.getDefault(WarrantManager.class).getWarrant(getName()); 576 if (w == null) { 577 log.error("invalid Warrant name= \"{}\" in state variable", getName()); 578 return false; 579 } 580 switch (_type) { 581 case ROUTE_FREE: 582 result = w.routeIsFree(); 583 break; 584 case ROUTE_OCCUPIED: 585 result = w.routeIsOccupied(); 586 break; 587 case ROUTE_ALLOCATED: 588 result = w.isAllocated(); 589 break; 590 case ROUTE_SET: 591 result = w.hasRouteSet(); 592 break; 593 case TRAIN_RUNNING: 594 // not in either RUN or LEARN state 595 result = !(w.getRunMode() == Warrant.MODE_NONE); 596 break; 597 default: 598 result = false; 599 } 600 break; 601 case CLOCK: 602 Timebase fastClock = InstanceManager.getDefault(jmri.Timebase.class); 603 Date currentTime = fastClock.getTime(); 604 int currentMinutes = (currentTime.getHours() * 60) + currentTime.getMinutes(); 605 int beginTime = fixMidnight(_num1); 606 int endTime = fixMidnight(_num2); 607 // check if current time is within range specified 608 if (beginTime <= endTime) { 609 // range is entirely within one day 610 result = (beginTime <= currentMinutes) && (currentMinutes <= endTime); 611 } else { 612 // range includes midnight 613 result = beginTime <= currentMinutes || currentMinutes <= endTime; 614 } 615 break; 616 case OBLOCK: 617 OBlock b = InstanceManager.getDefault(jmri.jmrit.logix.OBlockManager.class).getOBlock(getName()); 618 if (b == null) { 619 log.error("invalid OBlock name= \"{}\" in state variable", getName()); 620 return false; 621 } 622 result = b.statusIs(_dataString); 623 break; 624 case ENTRYEXIT: 625 NamedBean e = getBean(); 626 if (_type == Conditional.Type.ENTRYEXIT_ACTIVE) { 627 result = e.getState() == 0x02; 628 } else { 629 result = e.getState() == 0x04; 630 } 631 break; 632 default: 633 break; 634 } 635 // apply NOT if specified 636 if (_not) { 637 result = !result; 638 } 639 if (result) { 640 setState(Conditional.TRUE); 641 } else { 642 setState(Conditional.FALSE); 643 } 644 return (result); 645 } 646 647 /** 648 * Compare two values using the comparator set using the comparison 649 * instructions in {@link #setNum1(int)}. 650 * 651 * <strong>Note:</strong> {@link #getNum1()} must be one of {@link #LESS_THAN}, 652 * {@link #LESS_THAN_OR_EQUAL}, {@link #EQUAL}, 653 * {@link #GREATER_THAN_OR_EQUAL}, or {@link #GREATER_THAN}. 654 * 655 * @param value1 left side of the comparison 656 * @param value2 right side of the comparison 657 * @param caseInsensitive true if comparison should be case insensitive; 658 * false otherwise 659 * @return true if values compare per getNum1(); false otherwise 660 */ 661 boolean compare(String value1, String value2, boolean caseInsensitive) { 662 if (value1 == null) { 663 return value2 == null; 664 } else { 665 if (value2 == null) { 666 return false; 667 } 668 value1 = value1.trim(); 669 value2 = value2.trim(); 670 } 671 try { 672 int n1 = Integer.parseInt(value1); 673 try { 674 int n2 = Integer.parseInt(value2); 675 if (_num1 == 0) { // for former code 676 return n1 == n2; 677 } 678 log.debug("Compare numbers: n1= {} to n2= {}", n1, n2); 679 switch (_num1) // both are numbers 680 { 681 case LESS_THAN: 682 return (n1 < n2); 683 case LESS_THAN_OR_EQUAL: 684 return (n1 <= n2); 685 case EQUAL: 686 return (n1 == n2); 687 case GREATER_THAN_OR_EQUAL: 688 return (n1 >= n2); 689 case GREATER_THAN: 690 return (n1 > n2); 691 default: 692 log.error("Compare numbers: invalid compare case: {}", _num1); 693 return false; 694 } 695 } catch (NumberFormatException nfe) { 696 return false; // n1 is a number, n2 is not 697 } 698 } catch (NumberFormatException nfe) { 699 try { 700 Integer.parseInt(value2); 701 return false; // n1 is not a number, n2 is 702 } catch (NumberFormatException ex) { // OK neither a number 703 } 704 } 705 log.debug("Compare Strings: value1= {} to value2= {}", value1, value2); 706 int compare; 707 if (caseInsensitive) { 708 compare = value1.compareToIgnoreCase(value2); 709 } else { 710 compare = value1.compareTo(value2); 711 } 712 if (_num1 == 0) { // for former code 713 return compare == 0; 714 } 715 switch (_num1) { 716 case LESS_THAN: 717 if (compare < 0) { 718 return true; 719 } 720 break; 721 case LESS_THAN_OR_EQUAL: 722 if (compare <= 0) { 723 return true; 724 } 725 break; 726 case EQUAL: 727 if (compare == 0) { 728 return true; 729 } 730 break; 731 case GREATER_THAN_OR_EQUAL: 732 if (compare >= 0) { 733 return true; 734 } 735 break; 736 case GREATER_THAN: 737 if (compare > 0) { 738 return true; 739 } 740 break; 741 default: 742 // fall through 743 break; 744 } 745 return false; 746 } 747 748 public static int fixMidnight(int time) { 749 if (time > 24 * 60) { 750 time -= 24 * 60; 751 } 752 return time; 753 } 754 755 /** 756 * Convert Variable Type to Text String 757 * 758 * @param t the type 759 * @return the localized description 760 */ 761 public static String getItemTypeString(Conditional.ItemType t) { 762 switch (t) { 763 case SENSOR: 764 return Bundle.getMessage("BeanNameSensor"); // NOI18N 765 case TURNOUT: 766 return Bundle.getMessage("BeanNameTurnout"); // NOI18N 767 case LIGHT: 768 return Bundle.getMessage("BeanNameLight"); // NOI18N 769 case SIGNALHEAD: 770 return Bundle.getMessage("BeanNameSignalHead"); // NOI18N 771 case SIGNALMAST: 772 return Bundle.getMessage("BeanNameSignalMast"); // NOI18N 773 case MEMORY: 774 return Bundle.getMessage("BeanNameMemory"); // NOI18N 775 case CONDITIONAL: 776 return Bundle.getMessage("BeanNameConditional"); // NOI18N 777 case WARRANT: 778 return Bundle.getMessage("BeanNameWarrant"); // NOI18N 779 case CLOCK: 780 return Bundle.getMessage("FastClock"); // NOI18N 781 case OBLOCK: 782 return Bundle.getMessage("BeanNameOBlock"); // NOI18N 783 case ENTRYEXIT: 784 return Bundle.getMessage("BeanNameEntryExit"); // NOI18N 785 default: 786 return ""; 787 } 788 } 789 790 public static String getCompareOperationString(int index) { 791 switch (index) { 792 case LESS_THAN: 793 return rbx.getString("LessThan"); // NOI18N 794 case LESS_THAN_OR_EQUAL: 795 return rbx.getString("LessOrEqual"); // NOI18N 796 case 0: 797 case EQUAL: 798 return rbx.getString("Equal"); // NOI18N 799 case GREATER_THAN_OR_EQUAL: 800 return rbx.getString("GreaterOrEqual"); // NOI18N 801 case GREATER_THAN: 802 return rbx.getString("GreaterThan"); // NOI18N 803 default: 804 // fall through 805 break; 806 } 807 return ""; // NOI18N 808 } 809 810 public static String getCompareSymbols(int index) { 811 switch (index) { 812 case LESS_THAN: 813 return "<"; // NOI18N 814 case LESS_THAN_OR_EQUAL: 815 return "<="; // NOI18N 816 case 0: 817 case EQUAL: 818 return "="; // NOI18N 819 case GREATER_THAN_OR_EQUAL: 820 return ">="; // NOI18N 821 case GREATER_THAN: 822 return ">"; // NOI18N 823 default: 824 break; 825 } 826 return ""; // NOI18N 827 } 828 829 /** 830 * Identify action Data from Text String. 831 * 832 * @param str the text to check 833 * @return the conditional action type or -1 if if string does not 834 * correspond to an action Data as defined in ConditionalAction 835 */ 836 public static Conditional.Type stringToVariableTest(String str) { 837 if (str.equals(Bundle.getMessage("SignalHeadStateRed"))) { // NOI18N 838 return Conditional.Type.SIGNAL_HEAD_RED; 839 } else if (str.equals(Bundle.getMessage("SignalHeadStateYellow"))) { // NOI18N 840 return Conditional.Type.SIGNAL_HEAD_YELLOW; 841 } else if (str.equals(Bundle.getMessage("SignalHeadStateGreen"))) { // NOI18N 842 return Conditional.Type.SIGNAL_HEAD_GREEN; 843 } else if (str.equals(Bundle.getMessage("SignalHeadStateDark"))) { // NOI18N 844 return Conditional.Type.SIGNAL_HEAD_DARK; 845 } else if (str.equals(Bundle.getMessage("SignalHeadStateFlashingRed"))) { // NOI18N 846 return Conditional.Type.SIGNAL_HEAD_FLASHRED; 847 } else if (str.equals(Bundle.getMessage("SignalHeadStateFlashingYellow"))) { // NOI18N 848 return Conditional.Type.SIGNAL_HEAD_FLASHYELLOW; 849 } else if (str.equals(Bundle.getMessage("SignalHeadStateFlashingGreen"))) { // NOI18N 850 return Conditional.Type.SIGNAL_HEAD_FLASHGREEN; 851 } else if (str.equals(Bundle.getMessage("SignalHeadStateLunar"))) { // NOI18N 852 return Conditional.Type.SIGNAL_HEAD_LUNAR; 853 } else if (str.equals(Bundle.getMessage("SignalHeadStateFlashingLunar"))) { // NOI18N 854 return Conditional.Type.SIGNAL_HEAD_FLASHLUNAR; 855 } 856 // empty strings can occur frequently with types that have no integer data 857 if (str.length() > 0) { 858 log.warn("Unexpected parameter to stringToVariableTest({})", str); 859 } 860 return Conditional.Type.ERROR; 861 } 862 863 @Override 864 public String toString() { 865 String type = _type.getTestTypeString(); 866 Conditional.ItemType itemType = _type.getItemType(); 867 switch (itemType) { 868 case SENSOR: 869 return java.text.MessageFormat.format(rbx.getString("VarStateDescrpt"), 870 new Object[]{Bundle.getMessage("BeanNameSensor"), getName(), type}); 871 case TURNOUT: 872 return java.text.MessageFormat.format(rbx.getString("VarStateDescrpt"), 873 new Object[]{Bundle.getMessage("BeanNameTurnout"), getName(), type}); 874 case LIGHT: 875 return java.text.MessageFormat.format(rbx.getString("VarStateDescrpt"), 876 new Object[]{Bundle.getMessage("BeanNameLight"), getName(), type}); 877 case SIGNALHEAD: 878 if ((_type == Conditional.Type.SIGNAL_HEAD_LIT) 879 || (_type == Conditional.Type.SIGNAL_HEAD_HELD)) { 880 return java.text.MessageFormat.format(rbx.getString("VarStateDescrpt"), 881 new Object[]{Bundle.getMessage("BeanNameSignalHead"), getName(), type}); 882 } else { 883 return java.text.MessageFormat.format(rbx.getString("SignalHeadStateDescrpt"), 884 new Object[]{Bundle.getMessage("BeanNameSignalHead"), getName(), type}); 885 } 886 case SIGNALMAST: 887 if ((_type == Conditional.Type.SIGNAL_MAST_LIT) 888 || (_type == Conditional.Type.SIGNAL_MAST_HELD)) { 889 return java.text.MessageFormat.format(rbx.getString("VarStateDescrpt"), 890 new Object[]{Bundle.getMessage("BeanNameSignalMast"), getName(), type}); // NOI18N 891 } else { 892 return java.text.MessageFormat.format(rbx.getString("SignalMastStateDescrpt"), 893 new Object[]{Bundle.getMessage("BeanNameSignalMast"), getName(), _dataString}); // NOI18N 894 } 895 case MEMORY: 896 if ((_type == Conditional.Type.MEMORY_EQUALS) 897 || (_type == Conditional.Type.MEMORY_EQUALS_INSENSITIVE)) { 898 return java.text.MessageFormat.format(rbx.getString("MemoryValueDescrpt"), 899 new Object[]{Bundle.getMessage("BeanNameMemory"), getName(), // NOI18N 900 getCompareSymbols(_num1), _dataString}); 901 } else { 902 return java.text.MessageFormat.format(rbx.getString("MemoryCompareDescrpt"), 903 new Object[]{Bundle.getMessage("BeanNameMemory"), getName(), // NOI18N 904 getCompareSymbols(_num1), _dataString}); 905 } 906 case CONDITIONAL: 907 return java.text.MessageFormat.format(rbx.getString("VarStateDescrpt"), 908 new Object[]{Bundle.getMessage("BeanNameConditional"), getGuiName(), type}); // NOI18N 909 case WARRANT: 910 return java.text.MessageFormat.format(rbx.getString("VarStateDescrpt"), 911 new Object[]{rbx.getString("WarrantRoute"), getName(), type}); 912 case CLOCK: 913 return java.text.MessageFormat.format(rbx.getString("FastClockDescrpt"), 914 new Object[]{Bundle.getMessage("FastClock"), 915 LogixTableAction.formatTime(_num1 / 60, _num1 - ((_num1 / 60) * 60)), 916 LogixTableAction.formatTime(_num2 / 60, _num2 - ((_num2 / 60) * 60))}); 917 case OBLOCK: 918 return java.text.MessageFormat.format(rbx.getString("VarStateDescrpt"), 919 new Object[]{rbx.getString("OBlockStatus"), getName(), _dataString}); 920 case ENTRYEXIT: 921 return java.text.MessageFormat.format(rbx.getString("VarStateDescrpt"), 922 new Object[]{Bundle.getMessage("BeanNameEntryExit"), getBean().getUserName(), type}); // NOI18N 923 case NONE: 924 return getName() + " type " + type; 925 default: 926 // fall through 927 break; 928 } 929 return super.toString(); 930 } 931 932 private final static Logger log = LoggerFactory.getLogger(ConditionalVariable.class); 933}