001package jmri.jmrit.logixng.expressions; 002 003import java.beans.*; 004import java.util.*; 005 006import javax.annotation.Nonnull; 007 008import jmri.*; 009import jmri.jmrit.logix.Warrant; 010import jmri.jmrit.logix.WarrantManager; 011import jmri.jmrit.logixng.*; 012import jmri.jmrit.logixng.util.LogixNG_SelectNamedBean; 013import jmri.jmrit.logixng.util.ReferenceUtil; 014import jmri.jmrit.logixng.util.parser.*; 015import jmri.jmrit.logixng.util.parser.ExpressionNode; 016import jmri.jmrit.logixng.util.parser.RecursiveDescentParser; 017import jmri.util.TypeConversionUtil; 018 019/** 020 * This expression sets the state of a warrant. 021 * 022 * @author Daniel Bergqvist Copyright 2018 023 */ 024public class ExpressionWarrant extends AbstractDigitalExpression 025 implements PropertyChangeListener { 026 027 private final LogixNG_SelectNamedBean<Warrant> _selectNamedBean = 028 new LogixNG_SelectNamedBean<>( 029 this, Warrant.class, InstanceManager.getDefault(WarrantManager.class), this); 030 private Is_IsNot_Enum _is_IsNot = Is_IsNot_Enum.Is; 031 private NamedBeanAddressing _stateAddressing = NamedBeanAddressing.Direct; 032 private WarrantState _warrantState = WarrantState.RouteAllocated; 033 private String _stateReference = ""; 034 private String _stateLocalVariable = ""; 035 private String _stateFormula = ""; 036 private ExpressionNode _stateExpressionNode; 037 038 public ExpressionWarrant(String sys, String user) 039 throws BadUserNameException, BadSystemNameException { 040 super(sys, user); 041 } 042 043 @Override 044 public Base getDeepCopy(Map<String, String> systemNames, Map<String, String> userNames) throws ParserException { 045 DigitalExpressionManager manager = InstanceManager.getDefault(DigitalExpressionManager.class); 046 String sysName = systemNames.get(getSystemName()); 047 String userName = userNames.get(getSystemName()); 048 if (sysName == null) sysName = manager.getAutoSystemName(); 049 ExpressionWarrant copy = new ExpressionWarrant(sysName, userName); 050 copy.setComment(getComment()); 051 _selectNamedBean.copy(copy._selectNamedBean); 052 copy.setBeanState(_warrantState); 053 copy.set_Is_IsNot(_is_IsNot); 054 copy.setStateAddressing(_stateAddressing); 055 copy.setStateFormula(_stateFormula); 056 copy.setStateLocalVariable(_stateLocalVariable); 057 copy.setStateReference(_stateReference); 058 return manager.registerExpression(copy); 059 } 060 061 public LogixNG_SelectNamedBean<Warrant> getSelectNamedBean() { 062 return _selectNamedBean; 063 } 064 065 public void set_Is_IsNot(Is_IsNot_Enum is_IsNot) { 066 _is_IsNot = is_IsNot; 067 } 068 069 public Is_IsNot_Enum get_Is_IsNot() { 070 return _is_IsNot; 071 } 072 073 public void setStateAddressing(NamedBeanAddressing addressing) throws ParserException { 074 _stateAddressing = addressing; 075 parseStateFormula(); 076 } 077 078 public NamedBeanAddressing getStateAddressing() { 079 return _stateAddressing; 080 } 081 082 public void setBeanState(WarrantState state) { 083 _warrantState = state; 084 } 085 086 public WarrantState getBeanState() { 087 return _warrantState; 088 } 089 090 public void setStateReference(@Nonnull String reference) { 091 if ((! reference.isEmpty()) && (! ReferenceUtil.isReference(reference))) { 092 throw new IllegalArgumentException("The reference \"" + reference + "\" is not a valid reference"); 093 } 094 _stateReference = reference; 095 } 096 097 public String getStateReference() { 098 return _stateReference; 099 } 100 101 public void setStateLocalVariable(@Nonnull String localVariable) { 102 _stateLocalVariable = localVariable; 103 } 104 105 public String getStateLocalVariable() { 106 return _stateLocalVariable; 107 } 108 109 public void setStateFormula(@Nonnull String formula) throws ParserException { 110 _stateFormula = formula; 111 parseStateFormula(); 112 } 113 114 public String getStateFormula() { 115 return _stateFormula; 116 } 117 118 private void parseStateFormula() throws ParserException { 119 if (_stateAddressing == NamedBeanAddressing.Formula) { 120 Map<String, Variable> variables = new HashMap<>(); 121 122 RecursiveDescentParser parser = new RecursiveDescentParser(variables); 123 _stateExpressionNode = parser.parseExpression(_stateFormula); 124 } else { 125 _stateExpressionNode = null; 126 } 127 } 128 129 /** {@inheritDoc} */ 130 @Override 131 public Category getCategory() { 132 return Category.ITEM; 133 } 134 135 private String getNewState() throws JmriException { 136 137 switch (_stateAddressing) { 138 case Reference: 139 return ReferenceUtil.getReference( 140 getConditionalNG().getSymbolTable(), _stateReference); 141 142 case LocalVariable: 143 SymbolTable symbolTable = getConditionalNG().getSymbolTable(); 144 return TypeConversionUtil 145 .convertToString(symbolTable.getValue(_stateLocalVariable), false); 146 147 case Formula: 148 return _stateExpressionNode != null 149 ? TypeConversionUtil.convertToString( 150 _stateExpressionNode.calculate( 151 getConditionalNG().getSymbolTable()), false) 152 : null; 153 154 default: 155 throw new IllegalArgumentException("invalid _addressing state: " + _stateAddressing.name()); 156 } 157 } 158 159 /** {@inheritDoc} */ 160 @Override 161 public boolean evaluate() throws JmriException { 162 Warrant warrant = _selectNamedBean.evaluateNamedBean(getConditionalNG()); 163 164 if (warrant == null) return false; 165 166 WarrantState checkWarrantState; 167 168 if ((_stateAddressing == NamedBeanAddressing.Direct)) { 169 checkWarrantState = _warrantState; 170 } else { 171 checkWarrantState = WarrantState.valueOf(getNewState()); 172 } 173 174 boolean result; 175 176 switch (checkWarrantState) { 177 case RouteFree: 178 result = warrant.routeIsFree(); 179 break; 180 case RouteOccupied: 181 result = warrant.routeIsOccupied(); 182 break; 183 case RouteAllocated: 184 result = warrant.isAllocated(); 185 break; 186 case RouteSet: 187 result = warrant.hasRouteSet(); 188 break; 189 case TrainRunning: 190 result = ! (warrant.getRunMode() == Warrant.MODE_NONE); 191 break; 192 default: 193 throw new UnsupportedOperationException("checkWarrantState has unknown value: " + checkWarrantState.name()); 194 } 195 if (_is_IsNot == Is_IsNot_Enum.Is) { 196 return result; 197 } else { 198 return !result; 199 } 200 } 201 202 @Override 203 public FemaleSocket getChild(int index) throws IllegalArgumentException, UnsupportedOperationException { 204 throw new UnsupportedOperationException("Not supported."); 205 } 206 207 @Override 208 public int getChildCount() { 209 return 0; 210 } 211 212 @Override 213 public String getShortDescription(Locale locale) { 214 return Bundle.getMessage(locale, "Warrant_Short"); 215 } 216 217 @Override 218 public String getLongDescription(Locale locale) { 219 String namedBean = _selectNamedBean.getDescription(locale); 220 String state; 221 222 switch (_stateAddressing) { 223 case Direct: 224 state = Bundle.getMessage(locale, "AddressByDirect", _warrantState._text); 225 break; 226 227 case Reference: 228 state = Bundle.getMessage(locale, "AddressByReference", _stateReference); 229 break; 230 231 case LocalVariable: 232 state = Bundle.getMessage(locale, "AddressByLocalVariable", _stateLocalVariable); 233 break; 234 235 case Formula: 236 state = Bundle.getMessage(locale, "AddressByFormula", _stateFormula); 237 break; 238 239 default: 240 throw new IllegalArgumentException("invalid _stateAddressing state: " + _stateAddressing.name()); 241 } 242 243 return Bundle.getMessage(locale, "Warrant_Long", namedBean, _is_IsNot.toString(), state); 244 } 245 246 /** {@inheritDoc} */ 247 @Override 248 public void setup() { 249 // Do nothing 250 } 251 252 /** {@inheritDoc} */ 253 @Override 254 public void registerListenersForThisClass() { 255 if (!_listenersAreRegistered) { 256 _selectNamedBean.addPropertyChangeListener(this); 257 _selectNamedBean.registerListeners(); 258 _listenersAreRegistered = true; 259 } 260 } 261 262 /** {@inheritDoc} */ 263 @Override 264 public void unregisterListenersForThisClass() { 265 if (_listenersAreRegistered) { 266 _selectNamedBean.removePropertyChangeListener(this); 267 _selectNamedBean.unregisterListeners(); 268 _listenersAreRegistered = false; 269 } 270 } 271 272 /** {@inheritDoc} */ 273 @Override 274 public void propertyChange(PropertyChangeEvent evt) { 275 getConditionalNG().execute(); 276 } 277 278 /** {@inheritDoc} */ 279 @Override 280 public void disposeMe() { 281 } 282 283 284 public enum WarrantState { 285 RouteFree(Bundle.getMessage("WarrantTypeRouteFree")), 286 RouteOccupied(Bundle.getMessage("WarrantTypeOccupied")), 287 RouteAllocated(Bundle.getMessage("WarrantTypeAllocated")), 288 RouteSet(Bundle.getMessage("WarrantTypeRouteSet")), 289 TrainRunning(Bundle.getMessage("WarrantTypeTrainRunning")); 290 291 private final String _text; 292 293 private WarrantState(String text) { 294 this._text = text; 295 } 296 297 @Override 298 public String toString() { 299 return _text; 300 } 301 302 } 303 304 /** {@inheritDoc} */ 305 @Override 306 public void getUsageDetail(int level, NamedBean bean, List<NamedBeanUsageReport> report, NamedBean cdl) { 307 log.debug("getUsageReport :: ExpressionWarrant: bean = {}, report = {}", cdl, report); 308 _selectNamedBean.getUsageDetail(level, bean, report, cdl, this, LogixNG_SelectNamedBean.Type.Expression); 309 } 310 311 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ExpressionWarrant.class); 312 313}