001package jmri.jmrit.logixng.implementation; 002 003import static jmri.NamedBean.UNKNOWN; 004 005import java.io.PrintWriter; 006import java.util.*; 007 008import jmri.InstanceManager; 009import jmri.JmriException; 010import jmri.Manager; 011import jmri.NamedBean; 012import jmri.NamedBeanUsageReport; 013// import jmri.implementation.JmriSimplePropertyListener; 014import jmri.implementation.AbstractNamedBean; 015import jmri.jmrit.display.Positionable; 016import jmri.jmrit.logixng.*; 017 018import org.apache.commons.lang3.mutable.MutableInt; 019 020/** 021 * The default implementation of LogixNG. 022 * 023 * @author Daniel Bergqvist Copyright 2018 024 * @author Dave Sand Copyright 2021 025 */ 026public class DefaultLogixNG extends AbstractNamedBean 027 implements LogixNG { 028 029 private final LogixNG_Manager _manager = InstanceManager.getDefault(LogixNG_Manager.class); 030 private boolean _inline = false; 031 private InlineLogixNG _inlineLogixNG = null; 032 private boolean _enabled = false; 033 private boolean _isActive = false; 034 private final List<ConditionalNG_Entry> _conditionalNG_Entries = new ArrayList<>(); 035 036 037 public DefaultLogixNG(String sys, String user) throws BadUserNameException, BadSystemNameException { 038 super(sys, user); 039 040 // Do this test here to ensure all the tests are using correct system names 041 Manager.NameValidity isNameValid = InstanceManager.getDefault(LogixNG_Manager.class).validSystemNameFormat(mSystemName); 042 if (isNameValid != Manager.NameValidity.VALID) { 043 throw new IllegalArgumentException("system name is not valid"); 044 } 045 } 046 047 public DefaultLogixNG(String sys, String user, boolean inline) throws BadUserNameException, BadSystemNameException { 048 super(sys, user); 049 050 _inline = inline; 051 052 // Do this test here to ensure all the tests are using correct system names 053 Manager.NameValidity isNameValid = InstanceManager.getDefault(LogixNG_Manager.class).validSystemNameFormat(mSystemName); 054 if (isNameValid != Manager.NameValidity.VALID) { 055 throw new IllegalArgumentException("system name is not valid"); 056 } 057 } 058 059 /** {@inheritDoc} */ 060 @Override 061 public Base getParent() { 062 return null; 063 } 064 065 /** {@inheritDoc} */ 066 @Override 067 public void setParent(Base parent) { 068 throw new UnsupportedOperationException("A LogixNG cannot have a parent"); 069 } 070 071 @Override 072 public String getBeanType() { 073 return Bundle.getMessage("BeanNameLogixNG"); 074 } 075 076 @Override 077 public void setState(int s) throws JmriException { 078 log.warn("Unexpected call to setState in DefaultLogixNG."); // NOI18N 079 } 080 081 @Override 082 public int getState() { 083 log.warn("Unexpected call to getState in DefaultLogixNG."); // NOI18N 084 return UNKNOWN; 085 } 086 087 @Override 088 public String getShortDescription(Locale locale) { 089 return "LogixNG"; 090 } 091 092 @Override 093 public String getLongDescription(Locale locale) { 094 return "LogixNG: "+getDisplayName(); 095 } 096 097 @Override 098 public FemaleSocket getChild(int index) throws IllegalArgumentException, UnsupportedOperationException { 099 throw new UnsupportedOperationException("Not supported."); 100 } 101 102 @Override 103 public int getChildCount() { 104 throw new UnsupportedOperationException("Not supported."); 105 } 106 107 @Override 108 public Category getCategory() { 109 throw new UnsupportedOperationException("Not supported."); 110 } 111 112 /** {@inheritDoc} */ 113 @Override 114 final public void setup() { 115 for (ConditionalNG_Entry entry : _conditionalNG_Entries) { 116 if ( entry._conditionalNG == null 117 || !entry._conditionalNG.getSystemName() 118 .equals(entry._systemName)) { 119 120 String systemName = entry._systemName; 121 if (systemName != null) { 122 entry._conditionalNG = 123 InstanceManager.getDefault(ConditionalNG_Manager.class) 124 .getBySystemName(systemName); 125 if (entry._conditionalNG != null) { 126 entry._conditionalNG.setup(); 127 } else { 128 log.error("cannot load conditionalNG {}", systemName); 129 } 130 } 131 } else { 132 entry._conditionalNG.setup(); 133 } 134 } 135 } 136 137 /** {@inheritDoc} */ 138 @Override 139 public void setInline(boolean inline) { 140 boolean old = _inline; 141 _inline = inline; 142 firePropertyChange(LogixNG.PROPERTY_INLINE, old, _inline); 143 } 144 145 /** {@inheritDoc} */ 146 @Override 147 public boolean isInline() { 148 return _inline; 149 } 150 151 /** {@inheritDoc} */ 152 @Override 153 public void setInlineLogixNG(InlineLogixNG inlineLogixNG) { 154 _inlineLogixNG = inlineLogixNG; 155 } 156 157 /** {@inheritDoc} */ 158 @Override 159 public InlineLogixNG getInlineLogixNG() { 160 return _inlineLogixNG; 161 } 162 163 /** {@inheritDoc} */ 164 @Override 165 public void setEnabled(boolean enable) { 166 _enabled = enable; 167 if (isActive()) { 168 registerListeners(); 169 execute(true); 170 } else { 171 unregisterListeners(); 172 } 173 } 174 175 /** {@inheritDoc} */ 176 @Override 177 public void activate() { 178 _isActive = true; 179 } 180 181 /** {@inheritDoc} */ 182 @Override 183 public boolean isEnabled() { 184 return _enabled; 185 } 186 187 /** {@inheritDoc} */ 188 @Override 189 public String getConditionalNG_SystemName(int index) { 190 return _conditionalNG_Entries.get(index)._systemName; 191 } 192 193 /** {@inheritDoc} */ 194 @Override 195 public void setConditionalNG_SystemName(int index, String systemName) { 196 if (index == _conditionalNG_Entries.size()) { 197 _conditionalNG_Entries.add(new ConditionalNG_Entry(systemName)); 198 } else { 199 ConditionalNG_Entry entry = _conditionalNG_Entries.get(index); 200 entry._systemName = systemName; 201 entry._conditionalNG = null; 202 } 203 } 204 205 /** {@inheritDoc} */ 206 @Override 207 public int getNumConditionalNGs() { 208 return _conditionalNG_Entries.size(); 209 } 210 211 /** {@inheritDoc} */ 212 @Override 213 public void swapConditionalNG(int nextInOrder, int row) { 214 if (row <= nextInOrder) { 215 return; 216 } 217 ConditionalNG_Entry temp = _conditionalNG_Entries.get(row); 218 for (int i = row; i > nextInOrder; i--) { 219 _conditionalNG_Entries.set(i, _conditionalNG_Entries.get(i - 1)); 220 } 221 _conditionalNG_Entries.set(nextInOrder, temp); 222 } 223 224 /** {@inheritDoc} */ 225 @Override 226 public ConditionalNG getConditionalNG(int order) { 227 try { 228 return _conditionalNG_Entries.get(order)._conditionalNG; 229 } catch (java.lang.IndexOutOfBoundsException ioob) { 230 return null; 231 } 232 } 233 234 /** {@inheritDoc} */ 235 @Override 236 public boolean addConditionalNG(ConditionalNG conditionalNG) { 237 for (ConditionalNG_Entry entry : _conditionalNG_Entries) { 238 if (conditionalNG.getSystemName().equals(entry._systemName)) { 239 if (entry._conditionalNG == null) { 240 // Normally this will be during xml loading 241 entry._conditionalNG = conditionalNG; 242 return true; 243 } else { 244 log.error("ConditionalNG '{}' has already been added to LogixNG '{}'", conditionalNG.getSystemName(), getSystemName()); // NOI18N 245 return false; 246 } 247 } 248 249 } 250 251 ConditionalNG_Entry entry = new ConditionalNG_Entry(conditionalNG, conditionalNG.getSystemName()); 252 _conditionalNG_Entries.add(entry); 253 conditionalNG.setParent(this); 254 return true; 255 } 256 257 /** {@inheritDoc} */ 258 @Override 259 public ConditionalNG getConditionalNG(String systemName) { 260 for (int i = 0; i < getNumConditionalNGs(); i++) { 261 if (systemName.equals(_conditionalNG_Entries.get(i)._systemName)) { 262 return _conditionalNG_Entries.get(i)._conditionalNG; 263 } 264 } 265 return null; 266 } 267 268 /** {@inheritDoc} */ 269 @Override 270 public ConditionalNG getConditionalNGByUserName(String userName) { 271 for (ConditionalNG_Entry entry : _conditionalNG_Entries) { 272 if (userName.equals(entry._conditionalNG.getUserName())) { 273 return entry._conditionalNG; 274 } 275 } 276 return null; 277 } 278 279 /** {@inheritDoc} */ 280 @Override 281 public void deleteConditionalNG(ConditionalNG conditionalNG) { 282 if (_conditionalNG_Entries.size() <= 0) { 283 log.error("attempt to delete ConditionalNG not in LogixNG: {}", conditionalNG.getSystemName()); // NOI18N 284 return; 285 } 286 287 boolean found = false; 288 // Remove Conditional from this logix 289 for (ConditionalNG_Entry entry : _conditionalNG_Entries) { 290 if (conditionalNG == entry._conditionalNG) { 291 _conditionalNG_Entries.remove(entry); 292 found = true; 293 break; 294 } 295 } 296 if (!found) { 297 log.error("attempt to delete ConditionalNG not in LogixNG: {}", conditionalNG.getSystemName()); // NOI18N 298 } 299 } 300 301 /** {@inheritDoc} */ 302 @Override 303 public boolean isActive() { 304 return _enabled && _isActive && _manager.isActive(); 305 } 306 307 /** {@inheritDoc} */ 308 @Override 309 public void execute() { 310 for (ConditionalNG_Entry entry : _conditionalNG_Entries) { 311 entry._conditionalNG.execute(); 312 } 313 } 314 315 /** {@inheritDoc} */ 316 @Override 317 public void execute(boolean allowRunDelayed) { 318 for (ConditionalNG_Entry entry : _conditionalNG_Entries) { 319 entry._conditionalNG.execute(allowRunDelayed); 320 } 321 } 322 323 /** {@inheritDoc} */ 324 @Override 325 public ConditionalNG getConditionalNG() { 326 throw new UnsupportedOperationException("Not supported."); 327 } 328 329 /** {@inheritDoc} */ 330 @Override 331 public LogixNG getLogixNG() { 332 return this; 333 } 334 335 /** {@inheritDoc} */ 336 @Override 337 public final Base getRoot() { 338 return this; 339 } 340 341 /** {@inheritDoc} */ 342 @Override 343 public boolean setParentForAllChildren(List<String> errors) { 344 boolean result = true; 345 for (ConditionalNG_Entry entry : _conditionalNG_Entries) { 346 if (entry._conditionalNG != null) { 347 entry._conditionalNG.setParent(this); 348 result = result && entry._conditionalNG.setParentForAllChildren(errors); 349 } 350 } 351 return result; 352 } 353 354 /** {@inheritDoc} */ 355 @Override 356 public void registerListeners() { 357 for (ConditionalNG_Entry entry : _conditionalNG_Entries) { 358 entry._conditionalNG.registerListeners(); 359 } 360 } 361 362 /** {@inheritDoc} */ 363 @Override 364 public void unregisterListeners() { 365 for (ConditionalNG_Entry entry : _conditionalNG_Entries) { 366 entry._conditionalNG.unregisterListeners(); 367 } 368 } 369 370 protected void printTreeRow( 371 PrintTreeSettings settings, 372 Locale locale, 373 PrintWriter writer, 374 String currentIndent, 375 MutableInt lineNumber) { 376 377 if (settings._printLineNumbers) { 378 writer.append(String.format(PRINT_LINE_NUMBERS_FORMAT, lineNumber.addAndGet(1))); 379 } 380 writer.append(currentIndent); 381 writer.append(getLongDescription(locale)); 382 writer.println(); 383 } 384 385 /** {@inheritDoc} */ 386 @Override 387 public void printTree( 388 PrintTreeSettings settings, 389 PrintWriter writer, 390 String indent, 391 MutableInt lineNumber) { 392 393 printTree(settings, Locale.getDefault(), writer, indent, "", lineNumber); 394 } 395 396 /** {@inheritDoc} */ 397 @Override 398 public void printTree( 399 PrintTreeSettings settings, 400 Locale locale, 401 PrintWriter writer, 402 String indent, 403 MutableInt lineNumber) { 404 405 printTree(settings, locale, writer, indent, "", lineNumber); 406 } 407 408 /** {@inheritDoc} */ 409 @Override 410 public void printTree( 411 PrintTreeSettings settings, 412 Locale locale, 413 PrintWriter writer, 414 String indent, 415 String currentIndent, 416 MutableInt lineNumber) { 417 418 printTreeRow(settings, locale, writer, currentIndent, lineNumber); 419 420 for (int i=0; i < this.getNumConditionalNGs(); i++) { 421 getConditionalNG(i).printTree(settings, locale, writer, indent, currentIndent+indent, lineNumber); 422// writer.println(); 423 } 424 } 425 426 @Override 427 public Base getDeepCopy(Map<String, String> systemNames, Map<String, String> userNames) { 428 throw new UnsupportedOperationException("Not supported yet."); 429 } 430 431 @Override 432 public Base deepCopyChildren(Base original, Map<String, String> systemNames, Map<String, String> userNames) throws JmriException { 433 throw new UnsupportedOperationException("Not supported"); 434 } 435 436 private static class ConditionalNG_Entry { 437 private String _systemName; 438 private ConditionalNG _conditionalNG; 439 440 private ConditionalNG_Entry(ConditionalNG conditionalNG, String systemName) { 441 _systemName = systemName; 442 _conditionalNG = conditionalNG; 443 } 444 445 private ConditionalNG_Entry(ConditionalNG conditionalNG) { 446 this._conditionalNG = conditionalNG; 447 } 448 449 private ConditionalNG_Entry(String systemName) { 450 this._systemName = systemName; 451 } 452 453 @Override 454 public String toString() { 455 StringBuilder sb = new StringBuilder("ConditionalNG_Entry: name ="); 456 sb.append(_systemName); 457 sb.append(", cdl = "); 458 sb.append(_conditionalNG == null ? "----" : _conditionalNG.getDisplayName()); 459 return sb.toString(); 460 } 461 } 462 463 /** {@inheritDoc} */ 464 @Override 465 public List<NamedBeanUsageReport> getUsageReport(NamedBean bean) { 466 List<NamedBeanUsageReport> report = new ArrayList<>(); 467 if (bean != null) { 468 getUsageTree(0, bean, report, null); 469 } 470 return report; 471 } 472 473 /** {@inheritDoc} */ 474 @Override 475 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value="SLF4J_SIGN_ONLY_FORMAT", 476 justification="Specific log message format") 477 public void getUsageTree(int level, NamedBean bean, List<jmri.NamedBeanUsageReport> report, NamedBean cdl) { 478 log.debug("** {} :: {}", level, this.getClass().getName()); 479 480 level++; 481 for (int i=0; i < this.getNumConditionalNGs(); i++) { 482 getConditionalNG(i).getUsageTree(level, bean, report, getConditionalNG(i)); 483 } 484 } 485 486 /** {@inheritDoc} */ 487 @Override 488 public void getUsageDetail(int level, NamedBean bean, List<jmri.NamedBeanUsageReport> report, NamedBean cdl) { 489 } 490 491 /** {@inheritDoc} */ 492 @Override 493 public void getListenerRefsIncludingChildren(List<String> list) { 494 list.addAll(getListenerRefs()); 495 for (int i=0; i < getNumConditionalNGs(); i++) { 496 getConditionalNG(i).getListenerRefsIncludingChildren(list); 497 } 498 } 499 500 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultLogixNG.class); 501}