001package jmri.jmrit.logixng.expressions; 002 003import java.beans.*; 004import java.util.*; 005 006import javax.annotation.Nonnull; 007 008import jmri.*; 009import jmri.jmrit.logix.OBlock; 010import jmri.jmrit.logix.OBlockManager; 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 oblock. 021 * 022 * @author Daniel Bergqvist Copyright 2018 023 */ 024public class ExpressionOBlock extends AbstractDigitalExpression 025 implements PropertyChangeListener { 026 027 private final LogixNG_SelectNamedBean<OBlock> _selectNamedBean = 028 new LogixNG_SelectNamedBean<>( 029 this, OBlock.class, InstanceManager.getDefault(OBlockManager.class), this); 030 private Is_IsNot_Enum _is_IsNot = Is_IsNot_Enum.Is; 031 private NamedBeanAddressing _stateAddressing = NamedBeanAddressing.Direct; 032 private OBlock.OBlockStatus _oblockState = OBlock.OBlockStatus.Unoccupied; 033 private String _stateReference = ""; 034 private String _stateLocalVariable = ""; 035 private String _stateFormula = ""; 036 private ExpressionNode _stateExpressionNode; 037 038 public ExpressionOBlock(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 ExpressionOBlock copy = new ExpressionOBlock(sysName, userName); 050 copy.setComment(getComment()); 051 _selectNamedBean.copy(copy._selectNamedBean); 052 copy.setBeanState(_oblockState); 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<OBlock> 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(OBlock.OBlockStatus state) { 083 _oblockState = state; 084 } 085 086 public OBlock.OBlockStatus getBeanState() { 087 return _oblockState; 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 OBlock oblock = _selectNamedBean.evaluateNamedBean(getConditionalNG()); 163 164 if (oblock == null) return false; 165 166 OBlock.OBlockStatus checkOBlockState; 167 168 if ((_stateAddressing == NamedBeanAddressing.Direct)) { 169 checkOBlockState = _oblockState; 170 } else { 171 checkOBlockState = OBlock.OBlockStatus.valueOf(getNewState()); 172 } 173 174 int result = checkOBlockState.getStatus() & oblock.getState(); 175 if (_is_IsNot == Is_IsNot_Enum.Is) { 176 return result != 0; 177 } else { 178 return result == 0; 179 } 180 } 181 182 @Override 183 public FemaleSocket getChild(int index) throws IllegalArgumentException, UnsupportedOperationException { 184 throw new UnsupportedOperationException("Not supported."); 185 } 186 187 @Override 188 public int getChildCount() { 189 return 0; 190 } 191 192 @Override 193 public String getShortDescription(Locale locale) { 194 return Bundle.getMessage(locale, "OBlock_Short"); 195 } 196 197 @Override 198 public String getLongDescription(Locale locale) { 199 String namedBean = _selectNamedBean.getDescription(locale); 200 String state; 201 202 switch (_stateAddressing) { 203 case Direct: 204 state = Bundle.getMessage(locale, "AddressByDirect", _oblockState.getDescr()); 205 break; 206 207 case Reference: 208 state = Bundle.getMessage(locale, "AddressByReference", _stateReference); 209 break; 210 211 case LocalVariable: 212 state = Bundle.getMessage(locale, "AddressByLocalVariable", _stateLocalVariable); 213 break; 214 215 case Formula: 216 state = Bundle.getMessage(locale, "AddressByFormula", _stateFormula); 217 break; 218 219 default: 220 throw new IllegalArgumentException("invalid _stateAddressing state: " + _stateAddressing.name()); 221 } 222 223 return Bundle.getMessage(locale, "OBlock_Long", namedBean, _is_IsNot.toString(), state); 224 } 225 226 /** {@inheritDoc} */ 227 @Override 228 public void setup() { 229 // Do nothing 230 } 231 232 /** {@inheritDoc} */ 233 @Override 234 public void registerListenersForThisClass() { 235 if (!_listenersAreRegistered) { 236 _selectNamedBean.addPropertyChangeListener("state", this); 237 _selectNamedBean.registerListeners(); 238 _listenersAreRegistered = true; 239 } 240 } 241 242 /** {@inheritDoc} */ 243 @Override 244 public void unregisterListenersForThisClass() { 245 if (_listenersAreRegistered) { 246 _selectNamedBean.removePropertyChangeListener("state", this); 247 _selectNamedBean.unregisterListeners(); 248 _listenersAreRegistered = false; 249 } 250 } 251 252 /** {@inheritDoc} */ 253 @Override 254 public void propertyChange(PropertyChangeEvent evt) { 255 getConditionalNG().execute(); 256 } 257 258 /** {@inheritDoc} */ 259 @Override 260 public void disposeMe() { 261 } 262 263 /** {@inheritDoc} */ 264 @Override 265 public void getUsageDetail(int level, NamedBean bean, List<NamedBeanUsageReport> report, NamedBean cdl) { 266 log.debug("getUsageReport :: ExpressionOBlock: bean = {}, report = {}", cdl, report); 267 _selectNamedBean.getUsageDetail(level, bean, report, cdl, this, LogixNG_SelectNamedBean.Type.Expression); 268 } 269 270 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ExpressionOBlock.class); 271 272}