001package jmri.jmrit.logixng.expressions; 002 003import java.beans.*; 004import java.util.*; 005 006import jmri.*; 007import jmri.Block; 008import jmri.BlockManager; 009import jmri.jmrit.display.layoutEditor.LayoutBlock; 010import jmri.jmrit.display.layoutEditor.LayoutBlockManager; 011import jmri.jmrit.logixng.*; 012import jmri.jmrit.logixng.util.LogixNG_SelectNamedBean; 013import jmri.jmrit.logixng.util.LogixNG_SelectEnum; 014import jmri.jmrit.logixng.util.LogixNG_SelectString; 015import jmri.jmrit.logixng.util.parser.*; 016 017/** 018 * This expression evaluates the state of a Block. 019 * The supported characteristics are: 020 * <ul> 021 * <li>Is [not] Occupied (based on occupancy sensor state)</li> 022 * <li>Is [not] Unoccupied (based on occupancy sensor state)</li> 023 * <li>Is [not] Other (UNKNOWN, INCONSISTENT, UNDETECTED)</li> 024 * <li>Is [not] Allocated (based on the LayoutBlock useAlternateColor)</li> 025 * <li>Value [not] equals string</li> 026 * </ul> 027 * @author Daniel Bergqvist Copyright 2021 028 * @author Dave Sand Copyright 2021 029 */ 030public class ExpressionBlock extends AbstractDigitalExpression 031 implements PropertyChangeListener { 032 033 private final LogixNG_SelectNamedBean<Block> _selectNamedBean = 034 new LogixNG_SelectNamedBean<>( 035 this, Block.class, InstanceManager.getDefault(BlockManager.class), this); 036 037 private Is_IsNot_Enum _is_IsNot = Is_IsNot_Enum.Is; 038 039 private final LogixNG_SelectEnum<BlockState> _selectEnum = 040 new LogixNG_SelectEnum<>(this, BlockState.values(), BlockState.Occupied, this); 041 042 private final LogixNG_SelectString _selectBlockValue = 043 new LogixNG_SelectString(this, this); 044 045 046 public ExpressionBlock(String sys, String user) 047 throws BadUserNameException, BadSystemNameException { 048 super(sys, user); 049 } 050 051 @Override 052 public Base getDeepCopy(Map<String, String> systemNames, Map<String, String> userNames) throws ParserException { 053 DigitalExpressionManager manager = InstanceManager.getDefault(DigitalExpressionManager.class); 054 String sysName = systemNames.get(getSystemName()); 055 String userName = userNames.get(getSystemName()); 056 if (sysName == null) sysName = manager.getAutoSystemName(); 057 ExpressionBlock copy = new ExpressionBlock(sysName, userName); 058 copy.setComment(getComment()); 059 060 _selectNamedBean.copy(copy._selectNamedBean); 061 _selectEnum.copy(copy._selectEnum); 062 _selectBlockValue.copy(copy._selectBlockValue); 063 064 copy.set_Is_IsNot(_is_IsNot); 065 066 return manager.registerExpression(copy); 067 } 068 069 public LogixNG_SelectNamedBean<Block> getSelectNamedBean() { 070 return _selectNamedBean; 071 } 072 073 public LogixNG_SelectEnum<BlockState> getSelectEnum() { 074 return _selectEnum; 075 } 076 077 public LogixNG_SelectString getSelectBlockValue() { 078 return _selectBlockValue; 079 } 080 081 public void set_Is_IsNot(Is_IsNot_Enum is_IsNot) { 082 _is_IsNot = is_IsNot; 083 } 084 085 public Is_IsNot_Enum get_Is_IsNot() { 086 return _is_IsNot; 087 } 088 089 /** {@inheritDoc} */ 090 @Override 091 public Category getCategory() { 092 return Category.ITEM; 093 } 094 095 /** 096 * A block is considered to be allocated if the related layout block has use extra color enabled. 097 * @param block The block whose allocation state is requested. 098 * @return true if the layout block is using the extra color. 099 */ 100 public boolean isBlockAllocated(Block block) { 101 boolean result = false; 102 LayoutBlock layoutBlock = InstanceManager.getDefault(LayoutBlockManager.class).getLayoutBlock(block); 103 if (layoutBlock != null) { 104 result = layoutBlock.getUseExtraColor(); 105 } 106 return result; 107 } 108 109 /** {@inheritDoc} */ 110 @Override 111 public boolean evaluate() throws JmriException { 112 ConditionalNG conditionalNG = getConditionalNG(); 113 114 Block block = _selectNamedBean.evaluateNamedBean(conditionalNG); 115 116 if (block == null) return false; 117 118 BlockState checkBlockState = _selectEnum.evaluateEnum(conditionalNG); 119 120 int currentState = block.getState(); 121 122 switch (checkBlockState) { 123 case Other: 124 if (currentState != Block.OCCUPIED && currentState != Block.UNOCCUPIED) { 125 currentState = BlockState.Other.getID(); 126 } else { 127 currentState = 0; 128 } 129 break; 130 131 case Allocated: 132 boolean cuurrentAllocation = isBlockAllocated(block); 133 currentState = cuurrentAllocation ? BlockState.Allocated.getID() : 0; 134 break; 135 136 case ValueMatches: 137 String blockValue = _selectBlockValue.evaluateValue(conditionalNG); 138 currentState = blockValue.equals(block.getValue()) 139 ? BlockState.ValueMatches.getID() : 0; 140 break; 141 142 default: 143 break; 144 } 145 146 if (_is_IsNot == Is_IsNot_Enum.Is) { 147 return currentState == checkBlockState.getID(); 148 } else { 149 return currentState != checkBlockState.getID(); 150 } 151 } 152 153 @Override 154 public FemaleSocket getChild(int index) throws IllegalArgumentException, UnsupportedOperationException { 155 throw new UnsupportedOperationException("Not supported."); 156 } 157 158 @Override 159 public int getChildCount() { 160 return 0; 161 } 162 163 @Override 164 public String getShortDescription(Locale locale) { 165 return Bundle.getMessage(locale, "Block_Short"); 166 } 167 168 @Override 169 public String getLongDescription(Locale locale) { 170 String namedBean = _selectNamedBean.getDescription(locale); 171 String state; 172 173 if (_selectEnum.isDirectAddressing()) { 174 BlockState blockState = _selectEnum.getEnum(); 175 176 if (blockState == BlockState.ValueMatches) { 177 String bundleKey = "Block_Long_Value"; 178 String equalsString = _is_IsNot == Is_IsNot_Enum.Is ? Bundle.getMessage("Block_Equal") : Bundle.getMessage("Block_NotEqual"); 179 return Bundle.getMessage(locale, bundleKey, namedBean, equalsString, _selectBlockValue.getDescription(locale)); 180 } else if (blockState == BlockState.Other) { 181 state = Bundle.getMessage(locale, "AddressByDirect", blockState._text); 182 return Bundle.getMessage(locale, "Block_Long", namedBean, "", state); 183 } else { 184 state = Bundle.getMessage(locale, "AddressByDirect", blockState._text); 185 } 186 } else { 187 state = _selectEnum.getDescription(locale); 188 } 189 190 return Bundle.getMessage(locale, "Block_Long", namedBean, _is_IsNot.toString(), state); 191 } 192 193 /** {@inheritDoc} */ 194 @Override 195 public void setup() { 196 // Do nothing 197 } 198 199 /** {@inheritDoc} */ 200 @Override 201 public void registerListenersForThisClass() { 202 if (!_listenersAreRegistered) { 203 _selectNamedBean.addPropertyChangeListener(this); 204 _selectNamedBean.registerListeners(); 205 _selectEnum.registerListeners(); 206 _selectBlockValue.registerListeners(); 207 _listenersAreRegistered = true; 208 } 209 } 210 211 /** {@inheritDoc} */ 212 @Override 213 public void unregisterListenersForThisClass() { 214 if (_listenersAreRegistered) { 215 _selectNamedBean.removePropertyChangeListener(this); 216 _selectNamedBean.unregisterListeners(); 217 _selectEnum.unregisterListeners(); 218 _selectBlockValue.unregisterListeners(); 219 _listenersAreRegistered = false; 220 } 221 } 222 223 /** {@inheritDoc} */ 224 @Override 225 public void propertyChange(PropertyChangeEvent evt) { 226 getConditionalNG().execute(); 227 } 228 229 /** {@inheritDoc} */ 230 @Override 231 public void disposeMe() { 232 } 233 234 public enum BlockState { 235 Occupied(2, Bundle.getMessage("Block_StateOccupied")), 236 NotOccupied(4, Bundle.getMessage("Block_StateNotOccupied")), 237 Other(-1, Bundle.getMessage("Block_StateOther")), 238 Allocated(-2, Bundle.getMessage("Block_Allocated")), 239 ValueMatches(-3, Bundle.getMessage("Block_ValueMatches")); 240 241 private final int _id; 242 private final String _text; 243 244 private BlockState(int id, String text) { 245 this._id = id; 246 this._text = text; 247 } 248 249 public int getID() { 250 return _id; 251 } 252 253 @Override 254 public String toString() { 255 return _text; 256 } 257 } 258 259 /** {@inheritDoc} */ 260 @Override 261 public void getUsageDetail(int level, NamedBean bean, List<NamedBeanUsageReport> report, NamedBean cdl) { 262 log.debug("getUsageReport :: ExpressionBlock: bean = {}, report = {}", cdl, report); 263 _selectNamedBean.getUsageDetail(level, bean, report, cdl, this, LogixNG_SelectNamedBean.Type.Expression); 264 } 265 266 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ExpressionBlock.class); 267 268}