001package jmri.jmrit.ctc; 002 003import java.util.ArrayList; 004import java.util.HashMap; 005import java.util.List; 006import jmri.Block; 007import jmri.ConfigureManager; 008import jmri.InstanceManager; 009import jmri.InstanceManagerAutoDefault; 010import jmri.Manager; 011import jmri.NamedBean; 012import jmri.NamedBeanHandle; 013import jmri.NamedBeanUsageReport; 014import jmri.jmrit.ctc.ctcserialdata.*; 015import jmri.jmrit.ctc.editor.code.*; 016 017/** 018 * Start the CtcManager and register with the instance and configuration managers. 019 * <ul> 020 * <li>Create/provide the ProgramProperties instance</li> 021 * <li>Create/provide the CTCSerialData instance</li> 022 * <li>Provide the OtherData instance</li> 023 * <li>Provide hash maps of beans used by CTC</li> 024 * <li>Veto deletes for beans used by CTC</li> 025 * </ul> 026 * 027 * @author Dave Sand Copyright (C) 2020 028 */ 029public class CtcManager implements InstanceManagerAutoDefault, java.beans.VetoableChangeListener { 030 031 ProgramProperties programProperties = null; 032 CTCSerialData ctcSerialData = null; 033 HashMap<String, NBHSensor> nbhSensors = new HashMap<>(); 034 HashMap<String, NBHSignal> nbhSignals = new HashMap<>(); 035 HashMap<String, NBHTurnout> nbhTurnouts = new HashMap<>(); 036 HashMap<String, NamedBeanHandle<Block>> blocks = new HashMap<>(); 037 038 // Search results 039 NBHSensor foundSensor; 040 NBHSignal foundSignal; 041 NBHTurnout foundTurnout; 042 Block foundBlock; 043 044 List<NamedBeanUsageReport> usageReport; 045 046 public CtcManager() { 047 InstanceManager.setDefault(CtcManager.class, this); 048 InstanceManager.getOptionalDefault(ConfigureManager.class).ifPresent(cm -> { 049 cm.registerConfig(this, getXMLOrder()); 050 }); 051 InstanceManager.getDefault(jmri.SensorManager.class).addVetoableChangeListener(this); 052 InstanceManager.getDefault(jmri.SignalHeadManager.class).addVetoableChangeListener(this); 053 InstanceManager.getDefault(jmri.SignalMastManager.class).addVetoableChangeListener(this); 054 InstanceManager.getDefault(jmri.TurnoutManager.class).addVetoableChangeListener(this); 055 InstanceManager.getDefault(jmri.BlockManager.class).addVetoableChangeListener(this); 056 log.debug("CtcManager started"); // NOI18N 057 } 058 059 public ProgramProperties getProgramProperties() { 060 if (programProperties == null) { 061 programProperties = new ProgramProperties(); 062 } 063 return programProperties; 064 } 065 066 public ProgramProperties newProgramProperties() { 067 programProperties = new ProgramProperties(); 068 return programProperties; 069 } 070 071 public CTCSerialData getCTCSerialData() { 072 if (ctcSerialData == null) { 073 ctcSerialData = new CTCSerialData(); 074 } 075 return ctcSerialData; 076 } 077 078 public CTCSerialData newCTCSerialData() { 079 ctcSerialData = new CTCSerialData(); 080 081 nbhSensors.clear(); 082 nbhSignals.clear(); 083 nbhTurnouts.clear(); 084 blocks.clear(); 085 086 return ctcSerialData; 087 } 088 089 public OtherData getOtherData() { 090 if (ctcSerialData == null) { 091 ctcSerialData = getCTCSerialData(); 092 } 093 return ctcSerialData.getOtherData(); 094 } 095 096 public NBHSensor getNBHSensor(String name) { 097 // check for new names 098 return nbhSensors.get(name); 099 } 100 101 public void putNBHSensor(String name, NBHSensor nbh) { 102 NBHSensor oldSensor = nbhSensors.put(name, nbh); 103 log.debug("sensor put = {} -- {}", name, nbh); // NOI18N 104 if (oldSensor != null) { 105 log.debug("---- duplicate sensor: {} -- {}", name, nbh); // NOI18N 106 } 107 } 108 109 public NBHSignal getNBHSignal(String name) { 110 // check for new names 111 return nbhSignals.get(name); 112 } 113 114 public void putNBHSignal(String name, NBHSignal nbh) { 115 NBHSignal oldSignal = nbhSignals.put(name, nbh); 116 log.debug("signal put = {} -- {}", name, nbh); // NOI18N 117 if (oldSignal != null) { 118 log.debug("---- duplicate signal: {} -- {}", name, nbh); // NOI18N 119 } 120 } 121 122 public NBHTurnout getNBHTurnout(String name) { 123 // check for new names 124 return nbhTurnouts.get(name); 125 } 126 127 public void putNBHTurnout(String name, NBHTurnout nbh) { 128 NBHTurnout oldTurnout = nbhTurnouts.put(name, nbh); 129 log.debug("turnout put = {} -- {}", name, nbh); // NOI18N 130 if (oldTurnout != null) { 131 log.debug("---- duplicate turnout: {} -- {}", name, nbh); // NOI18N 132 } 133 } 134 135 public NamedBeanHandle<Block> getBlock(String name) { 136 // check for new names 137 return blocks.get(name); 138 } 139 140 public void putBlock(String name, NamedBeanHandle<Block> block) { 141 NamedBeanHandle<Block> oldBlock = blocks.put(name, block); 142 log.debug("block put = {} -- {}", name, block); // NOI18N 143 if (oldBlock != null) { 144 log.debug("---- duplicate block: {} -- {}", name, block); // NOI18N 145 } 146 } 147 148 public int getXMLOrder() { 149 return Manager.CTCDATA; 150 } 151 152 @Override 153 public void vetoableChange(java.beans.PropertyChangeEvent evt) throws java.beans.PropertyVetoException { 154 jmri.NamedBean nb = (jmri.NamedBean) evt.getOldValue(); 155 if ("CanDelete".equals(evt.getPropertyName())) { // NOI18N 156 if (findNBHforBean(nb)) { 157 java.beans.PropertyChangeEvent e = new java.beans.PropertyChangeEvent(this, "DoNotDelete", null, null); // NOI18N 158 throw new java.beans.PropertyVetoException(getVetoDetails(nb), e); 159 } 160 } 161 } 162 163 String getVetoDetails(NamedBean nb) { 164 StringBuilder sb = new StringBuilder(); 165 sb.append(Bundle.getMessage("CtcManagerDeleteVetoed", nb.getBeanType())); // NOI18N 166 for (NamedBeanUsageReport report : getUsageReport(nb)) { 167 sb.append(Bundle.getMessage("VetoDetailLine", report.usageData)); // NOI18N 168 } 169 return sb.toString(); 170 } 171 172 boolean findNBHforBean(NamedBean nb) { 173 if (nb == null) return false; 174 boolean found = false; 175 foundSensor = null; 176 foundSignal = null; 177 foundTurnout = null; 178 foundBlock = null; 179 180 if (nb instanceof jmri.Sensor) { 181 for (NBHSensor sensor : nbhSensors.values()) { 182 if (nb.equals(sensor.getBean())) { 183 foundSensor = sensor; 184 found = true; 185 break; 186 } 187 } 188 } 189 190 if (nb instanceof jmri.SignalHead || nb instanceof jmri.SignalMast) { 191 for (NBHSignal signal : nbhSignals.values()) { 192 if (nb.equals(signal.getBean())) { 193 foundSignal = signal; 194 found = true; 195 break; 196 } 197 } 198 } 199 200 if (nb instanceof jmri.Turnout) { 201 for (NBHTurnout turnout : nbhTurnouts.values()) { 202 if (nb.equals(turnout.getBean())) { 203 foundTurnout = turnout; 204 found = true; 205 break; 206 } 207 } 208 } 209 210 if (nb instanceof Block) { 211 for (NamedBeanHandle<Block> block : blocks.values()) { 212 if (nb.equals(block.getBean())) { 213 foundBlock = block.getBean(); 214 found = true; 215 break; 216 } 217 } 218 } 219 return found; 220 } 221 222 public List<NamedBeanUsageReport> getUsageReport(NamedBean bean) { 223 usageReport = new ArrayList<>(); 224 if (findNBHforBean(bean)) { 225 // Other data 226 if (getOtherData()._mFleetingToggleInternalSensor.equals(foundSensor) || 227 getOtherData()._mCTCDebugSystemReloadInternalSensor.equals(foundSensor) || 228 getOtherData()._mCTCDebug_TrafficLockingRuleTriggeredDisplayInternalSensor.equals(foundSensor)) { 229 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedOther", Bundle.getMessage("WhereUsedOther"))); // NOI18N 230 } 231 232 // O.S. Sections 233 getCTCSerialData().getCodeButtonHandlerDataArrayList().forEach(cbhd -> { 234 getCodeButtonHandleDataUsage(cbhd); 235 }); 236 } 237 return usageReport; 238 } 239 240 void getCodeButtonHandleDataUsage(CodeButtonHandlerData cbhd) { 241 String osName = cbhd.myShortStringNoComma(); 242 243 // CB Sensors 244 if (cbhd._mCodeButtonInternalSensor.equals(foundSensor) || 245 cbhd._mOSSectionOccupiedExternalSensor.equals(foundSensor) || 246 cbhd._mOSSectionOccupiedExternalSensor2.equals(foundSensor)) { 247 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSensor", osName, "CB"))); // NOI18N 248 } 249 250 // SIDI Sensors 251 if (cbhd._mSIDI_LeftInternalSensor.equals(foundSensor) || 252 cbhd._mSIDI_NormalInternalSensor.equals(foundSensor) || 253 cbhd._mSIDI_RightInternalSensor.equals(foundSensor)) { 254 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSensor", osName, "SIDI"))); // NOI18N 255 } 256 257 // SIDI Signals 258 cbhd._mSIDI_LeftRightTrafficSignals.forEach(signal -> { 259 if (signal.equals(foundSignal)) { 260 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSignal", osName, "SIDI"))); // NOI18N 261 } 262 }); 263 cbhd._mSIDI_RightLeftTrafficSignals.forEach(signal -> { 264 if (signal.equals(foundSignal)) { 265 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSignal", osName, "SIDI"))); // NOI18N 266 } 267 }); 268 269 // SIDL Sensors 270 if (cbhd._mSIDL_LeftInternalSensor.equals(foundSensor) || 271 cbhd._mSIDL_NormalInternalSensor.equals(foundSensor) || 272 cbhd._mSIDL_RightInternalSensor.equals(foundSensor)) { 273 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSensor", osName, "SIDL"))); // NOI18N 274 } 275 276 // SWDI Sensors 277 if (cbhd._mSWDI_NormalInternalSensor.equals(foundSensor) || 278 cbhd._mSWDI_ReversedInternalSensor.equals(foundSensor)) { 279 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSensor", osName, "SWDI"))); // NOI18N 280 } 281 282 // SWDI Turnout 283 if (cbhd._mSWDI_ExternalTurnout.equals(foundTurnout)) { 284 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedTurnout", osName, "SWDI"))); // NOI18N 285 } 286 287 // SWDL Sensor 288 if (cbhd._mSWDL_InternalSensor.equals(foundSensor)) { 289 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSensor", osName, "SWDL"))); // NOI18N 290 } 291 292 callOnDataUsage(cbhd, osName); 293 traffficLockingDataUsage(cbhd, osName); 294 295 // TUL Sensors 296 if (cbhd._mTUL_DispatcherInternalSensorLockToggle.equals(foundSensor) || 297 cbhd._mTUL_DispatcherInternalSensorUnlockedIndicator.equals(foundSensor)) { 298 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSensor", osName, "TUL"))); // NOI18N 299 } 300 301 // TUL Turnouts 302 if (cbhd._mTUL_ExternalTurnout.equals(foundTurnout) || 303 cbhd._mTUL_AdditionalExternalTurnout1.equals(foundTurnout) || 304 cbhd._mTUL_AdditionalExternalTurnout2.equals(foundTurnout) || 305 cbhd._mTUL_AdditionalExternalTurnout3.equals(foundTurnout)) { 306 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedTurnout", osName, "TUL"))); // NOI18N 307 } 308 309 // IL Signals 310 cbhd._mIL_Signals.forEach(signal -> { 311 if (signal.equals(foundSignal)) { 312 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSignal", osName, "IL"))); // NOI18N 313 } 314 }); 315 } 316 317 void callOnDataUsage(CodeButtonHandlerData cbhd, String osName) { 318 // CO Sensor 319 if (cbhd._mCO_CallOnToggleInternalSensor.equals(foundSensor)) { 320 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSensor", osName, "CO"))); // NOI18N 321 } 322 cbhd._mCO_GroupingsList.forEach(row -> { 323 // Sensor 324 if (row._mCalledOnExternalSensor.equals(foundSensor)) { 325 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSensor", osName, "CO"))); // NOI18N 326 } 327 328 // Signal 329 if (row._mExternalSignal.equals(foundSignal)) { 330 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSignal", osName, "CO"))); // NOI18N 331 } 332 333 // Block 334 if (row._mExternalBlock != null && row._mExternalBlock.getBean().equals(foundBlock)) { 335 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedBlock", osName, "CO"))); // NOI18N 336 } 337 338 // Switch indicator sensors 339 row._mSwitchIndicators.forEach(sw -> { 340 if (sw.equals(foundSensor)) { 341 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSensor", osName, "CO"))); // NOI18N 342 } 343 }); 344 }); 345 } 346 347 void traffficLockingDataUsage(CodeButtonHandlerData cbhd, String osName) { 348 cbhd._mTRL_LeftTrafficLockingRules.forEach(rule -> { 349 traffficLockingRuleDataUsage(rule, osName); 350 }); 351 352 cbhd._mTRL_RightTrafficLockingRules.forEach(rule -> { 353 traffficLockingRuleDataUsage(rule, osName); 354 }); 355 } 356 357 void traffficLockingRuleDataUsage(TrafficLockingData rule, String osName) { 358 // Signal -- _mDestinationSignalOrComment 359 if (foundSignal != null) { 360 if (rule._mDestinationSignalOrComment.equals(foundSignal.getHandleName())) { 361 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSignal", osName, "TRL"))); // NOI18N 362 } 363 } 364 365 // Occupancy sensors 366 for (NBHSensor sensor : rule._mOccupancyExternalSensors) { 367 if (sensor.equals(foundSensor)) { 368 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSensor", osName, "TRL"))); // NOI18N 369 break; 370 } 371 } 372 373 // Optional sensors 374 for (NBHSensor sensor : rule._mOptionalExternalSensors) { 375 if (sensor.equals(foundSensor)) { 376 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSensor", osName, "TRL"))); // NOI18N 377 break; 378 } 379 } 380 } 381 382 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CtcManager.class); 383}