001package jmri.jmrit.symbolicprog; 002 003import org.slf4j.Logger; 004import org.slf4j.LoggerFactory; 005 006/** 007 * Mechanism to qualify on the value of a number. 008 * <p> 009 * The usual arithmetic operations are possible: ge, le, gt, lt, eq, ne. The 010 * sense of this is comparing "current value" to "constant", for example 011 * "current value gt 3". 012 * <p> 013 * You can also check whether the value "exists" (value of 1) or not (value of 014 * 0). Comparisons with the value of a non-existent variable always fail. 015 * 016 * @author Bob Jacobsen Copyright (C) 2010, 2014 017 * 018 */ 019public abstract class ArithmeticQualifier extends AbstractQualifier { 020 021 public enum Test { 022 023 GE("ge"), // greater than or equal 024 LE("le"), 025 GT("gt"), 026 LT("lt"), 027 EQ("eq"), 028 NE("ne"), 029 EXISTS("exists"); 030 031 Test(String relation) { 032 this.relation = relation; 033 } 034 String relation; 035 036 static Test decode(String r) { 037 for (Test t : Test.values()) { 038 if (t.relation.equals(r)) { 039 return t; 040 } 041 } 042 return null; 043 } 044 } 045 046 Test test; 047 048 public ArithmeticQualifier(VariableValue watchedVal, int value, String relation) { 049 super(watchedVal); 050 051 this.test = Test.decode(relation); 052 this.value = Integer.toUnsignedLong(value); 053 } 054 055 @Override 056 public boolean currentDesiredState() { 057 if (returnFromExistsLogic()) { 058 return valueOfExistsLogic(); 059 } 060 061 return availableStateFromValue(watchedVal.getLongValue()); 062 } 063 064 @Override 065 protected boolean availableStateFromValue(Object now) { 066 if (returnFromExistsLogic()) { 067 return valueOfExistsLogic(); 068 } 069 070 long nowVal = 0; 071 if (now instanceof Integer) { 072 nowVal = Integer.toUnsignedLong((int) now); 073 } else if (now instanceof Long) { 074 nowVal = (Long) now; 075 } 076 077 int compare = Long.compareUnsigned(nowVal, value); 078 079 switch (test) { 080 case GE: 081 return compare >= 0; 082 case LE: 083 return compare <= 0; 084 case GT: 085 return compare > 0; 086 case LT: 087 return compare < 0; 088 case EQ: 089 return compare == 0; 090 case NE: 091 return compare != 0; 092 default: 093 log.error("Unexpected switch value: {}", test); 094 return false; 095 } 096 097 } 098 099 @Override 100 public void update() { 101 setWatchedAvailable(currentDesiredState()); 102 } 103 104 long value; 105 106 private boolean returnFromExistsLogic() { 107 if (test == Test.EXISTS) { 108 return true; 109 } 110 if (watchedVal == null) { 111 return true; 112 } 113 return false; 114 } 115 116 boolean warnedDoesntExist = false; 117 118 private boolean valueOfExistsLogic() { 119 if (test == Test.EXISTS) { 120 if (value == 0 && watchedVal == null) { 121 return true; 122 } 123 if (value != 0 && watchedVal != null) { 124 return true; 125 } 126 return false; 127 } 128 // here it's an arithmetic op on a variable 129 if (watchedVal == null) { 130 if (!warnedDoesntExist) { 131 warnedDoesntExist = true; 132 log.error("Arithmetic {} operation when watched value doesn't exist", test); 133 } 134 return true; // this determines default for what happens when qualifier (watched) Variable isn't present 135 } 136 return false; // should never be reached, because should only be invoked after returnFromExistsLogic() == true 137 } 138 139 private final static Logger log = LoggerFactory.getLogger(ArithmeticQualifier.class); 140}