001package jmri.jmrit.whereused;
002
003import jmri.jmrit.blockboss.BlockBossLogicProvider;
004import jmri.jmrit.display.EditorManager;
005
006import java.util.Collections;
007import java.util.Enumeration;
008
009import jmri.*;
010import jmri.jmrit.blockboss.BlockBossLogic;
011import jmri.jmrit.ctc.CtcManager;
012import jmri.jmrit.display.switchboardEditor.SwitchboardEditor;
013import jmri.jmrit.entryexit.EntryExitPairs;
014import jmri.jmrit.logix.OBlockManager;
015import jmri.jmrit.logix.WarrantManager;
016import jmri.jmrit.logixng.LogixNG_Manager;
017import jmri.jmrit.logixng.ModuleManager;
018import jmri.jmrit.display.layoutEditor.LayoutBlockManager;
019/**
020 * Find references.  Each collector method calls a corresponding getUsageReport(NamedBean)
021 * in the main implementation class for the object type.  The matches are returned in an
022 * array list of NamedBeanUsageReport objects.
023 *
024 * Collectors:
025 * <ul>
026 * <li>checkAudio</li>
027 * <li>checkTurnouts</li>
028 * <li>checkLights</li>
029 * <li>checkRoutes</li>
030 * <li>checkBlocks</li>
031 * <li>checkLayoutBlocks</li>
032 * <li>checkSignalHeadLogic</li>
033 * <li>checkSignalMastLogic</li>
034 * <li>checkSignalGroups</li>
035 * <li>checkSignalHeads</li>
036 * <li>checkSignalMasts</li>
037 * <li>checkOBlocks</li>
038 * <li>checkWarrants</li>
039 * <li>checkEntryExit</li>
040 * <li>checkLogixConditionals</li>
041 * <li>checkLogixNGConditionals</li>
042 * <li>checkSections</li>
043 * <li>checkTransits</li>
044 * <li>checkPanels</li>
045 * <li>checkCTC</li>
046 * </ul>
047 *
048 * @author Dave Sand Copyright (C) 2020
049 */
050
051public class WhereUsedCollectors {
052
053    /**
054     * Create the Audio usage string.
055     * Usage keys:
056     * <ul>
057     * <li>AudioBuffer</li>
058     * </ul>
059     * @param bean The requesting bean:  Audio.
060     * @return usage string
061     */
062    static String checkAudio(NamedBean bean) {
063        StringBuilder sb = new StringBuilder();
064        InstanceManager.getDefault(AudioManager.class).getNamedBeanSet().forEach((audio) -> audio.getUsageReport(bean).forEach((report) -> {
065            if (report.usageKey.startsWith("Audio")) {  // NOI18N
066                String name = audio.getDisplayName(NamedBean.DisplayOptions.USERNAME_SYSTEMNAME);
067                sb.append(Bundle.getMessage("ReferenceLineName", name));  // NOI18N
068            }
069        }));
070        return addHeader(sb, "ReferenceAudio");  // NOI18N
071    }
072
073    /**
074     * Create the Turnout usage string.
075     * Usage keys:
076     * <ul>
077     * <li>TurnoutFeedback1</li>
078     * <li>TurnoutFeedback2</li>
079     * </ul>
080     * @param bean The requesting bean:  Sensor.
081     * @return usage string
082     */
083    static String checkTurnouts(NamedBean bean) {
084        StringBuilder sb = new StringBuilder();
085        InstanceManager.getDefault(TurnoutManager.class).getNamedBeanSet().forEach((turnout) -> {
086            int feedback = turnout.getFeedbackMode();
087            if (feedback == Turnout.ONESENSOR || feedback == Turnout.TWOSENSOR) {
088                turnout.getUsageReport(bean).forEach((report) -> {
089                    if (report.usageKey.startsWith("TurnoutFeedback")) {  // NOI18N
090                        String name = turnout.getDisplayName(NamedBean.DisplayOptions.USERNAME_SYSTEMNAME);
091                        sb.append(Bundle.getMessage("ReferenceLineName", name));  // NOI18N
092                    }
093                });
094            }
095        });
096        return addHeader(sb, "ReferenceFeedback");  // NOI18N
097    }
098
099    /**
100     * Create the Light usage string.
101     * Usage keys:
102     * <ul>
103     * <li>LightControlSensor1</li>
104     * <li>LightControlSensor2</li>
105     * <li>LightControlSensorTimed</li>
106     * <li>LightControlTurnout</li>
107     * </ul>
108     * @param bean The requesting bean:  Sensor, Turnout.
109     * @return usage string
110     */
111    static String checkLights(NamedBean bean) {
112        StringBuilder sb = new StringBuilder();
113        InstanceManager.getDefault(LightManager.class).getNamedBeanSet().forEach((light) -> light.getUsageReport(bean).forEach((report) -> {
114            if (report.usageKey.startsWith("LightControl")) {  // NOI18N
115                String name = light.getDisplayName(NamedBean.DisplayOptions.USERNAME_SYSTEMNAME);
116                sb.append(Bundle.getMessage("ReferenceLineData", name, report.usageData));  // NOI18N
117            }
118        }));
119        return addHeader(sb, "ReferenceLightControl");  // NOI18N
120    }
121
122    /**
123     * Create the Route usage string.
124     * Usage keys:
125     * <ul>
126     * <li>RouteTurnoutOutput</li>
127     * <li>RouteSensorOutput</li>
128     * <li>RouteSensorControl</li>
129     * <li>RouteSensorAligned</li>
130     * <li>RouteTurnoutControl</li>
131     * <li>RouteTurnoutLock</li>
132     * </ul>
133     * @param bean The requesting bean:  Sensor, Turnout.
134     * @return usage string
135     */
136    static String checkRoutes(NamedBean bean) {
137        StringBuilder sb = new StringBuilder();
138        InstanceManager.getDefault(RouteManager.class).getNamedBeanSet().forEach((route) -> route.getUsageReport(bean).forEach((report) -> {
139            if (report.usageKey.startsWith("Route")) {  // NOI18N
140                String name = route.getDisplayName(NamedBean.DisplayOptions.USERNAME_SYSTEMNAME);
141                sb.append(Bundle.getMessage("ReferenceLineName", name));  // NOI18N
142            }
143        }));
144        return addHeader(sb, "ReferenceRoutes");  // NOI18N
145    }
146
147    /**
148     * Create the Block usage string.
149     * Usage keys:
150     * <ul>
151     * <li>BlockSensor</li>
152     * <li>BlockReporter</li>
153     * <li>BlockPathNeighbor</li>
154     * <li>BlockPathTurnout</li>
155     * </ul>
156     * @param bean The requesting bean:  Block (Path neighbor), Sensor, Reporter, Turnout (Path).
157     * @return usage string
158     */
159    static String checkBlocks(NamedBean bean) {
160        StringBuilder sb = new StringBuilder();
161        InstanceManager.getDefault(BlockManager.class).getNamedBeanSet().forEach((block) -> block.getUsageReport(bean).forEach((report) -> {
162            if (report.usageKey.startsWith("Block")) {  // NOI18N
163                String name = block.getDisplayName(NamedBean.DisplayOptions.USERNAME_SYSTEMNAME);
164                sb.append(Bundle.getMessage("ReferenceLineName", name));  // NOI18N
165            }
166        }));
167        return addHeader(sb, "ReferenceBlock");  // NOI18N
168    }
169
170    /**
171     * Create the LayoutBlock usage string.
172     * Usage keys:
173     * <ul>
174     * <li>LayoutBlockBlock</li>
175     * <li>LayoutBlockMemory</li>
176     * <li>LayoutBlockSensor</li>
177     * <li>LayoutBlockNeighbor</li>
178     * </ul>
179     * @param bean The requesting bean:  Block, Memory, Sensor.
180     * @return usage string
181     */
182    static String checkLayoutBlocks(NamedBean bean) {
183        StringBuilder sb = new StringBuilder();
184        InstanceManager.getDefault(LayoutBlockManager.class).getNamedBeanSet().forEach((layoutBlock) -> layoutBlock.getUsageReport(bean).forEach((report) -> {
185            if (report.usageKey.startsWith("LayoutBlock")) {  // NOI18N
186                String name = layoutBlock.getDisplayName(NamedBean.DisplayOptions.USERNAME_SYSTEMNAME);
187                sb.append(Bundle.getMessage("ReferenceLineData", name, report.usageData));  // NOI18N
188            }
189        }));
190        return addHeader(sb, "ReferenceLayoutBlock");  // NOI18N
191    }
192
193    /**
194     * Create the Signal Head Logic usage string.
195     * Usage keys:
196     * <ul>
197     * <li>SSLSignal</li>
198     * <li>SSLSensor1-5</li>
199     * <li>SSLTurnout</li>
200     * <li>SSLSignal1</li>
201     * <li>SSLSignal1Alt</li>
202     * <li>SSLSignal2</li>
203     * <li>SSLSignal2Alt</li>
204     * <li>SSLSensorWatched1</li>
205     * <li>SSLSensorWatched1Alt</li>
206     * <li>SSLSensorWatched2</li>
207     * <li>SSLSensorWatched2Alt</li>
208     * <li>SSLSensorApproach</li>
209     * </ul>
210     * @param bean The requesting bean:  Sensor, Signal Head, Turnout.
211     * @return usage string
212     */
213    static String checkSignalHeadLogic(NamedBean bean) {
214        StringBuilder sb = new StringBuilder();
215        Enumeration<BlockBossLogic> e = Collections.enumeration(InstanceManager.getDefault(BlockBossLogicProvider.class).provideAll());
216        while (e.hasMoreElements()) {
217            BlockBossLogic ssl = e.nextElement();
218            ssl.getUsageReport(bean).forEach((report) -> {
219                if (report.usageKey.startsWith("SSL")) {  // NOI18N
220                    String name = report.usageBean.getDisplayName(NamedBean.DisplayOptions.USERNAME_SYSTEMNAME);
221                    sb.append(Bundle.getMessage("ReferenceLineName", name));  // NOI18N
222                }
223            });
224        }
225        return addHeader(sb, "ReferenceHeadSSL");  // NOI18N
226    }
227
228    /**
229     * Create the Signal Mast Logic usage string.
230     * Usage keys:
231     * <ul>
232     * <li>SMLSourceMast</li>
233     * <li>SMLDestinationMast</li>
234     * <li>SMLBlockAuto</li>
235     * <li>SMLBlockUser</li>
236     * <li>SMLTurnoutAuto</li>
237     * <li>SMLTurnoutUser</li>
238     * <li>SMLSensor</li>
239     * <li>SMLMastAuto</li>
240     * <li>SMLMastUser</li>
241     * </ul>
242     * @param bean The requesting bean:  Block, Turnout, Sensor, Signal Mast.
243     * @return usage string
244     */
245    static String checkSignalMastLogic(NamedBean bean) {
246        StringBuilder sb = new StringBuilder();
247        InstanceManager.getDefault(SignalMastLogicManager.class).getNamedBeanSet().forEach((sml) -> sml.getUsageReport(bean).forEach((report) -> {
248            String name = bean.getDisplayName(NamedBean.DisplayOptions.USERNAME_SYSTEMNAME);
249            if (report.usageKey.startsWith("SMLSource")) {  // NOI18N
250                sb.append(Bundle.getMessage("ReferenceLineData", name, Bundle.getMessage("SourceMast")));  // NOI18N
251                return;
252            }
253            if (report.usageKey.startsWith("SMLDest")) {  // NOI18N
254                sb.append(Bundle.getMessage("ReferenceLineData", name, Bundle.getMessage("DestMast")));  // NOI18N
255                return;
256            }
257            if (report.usageKey.startsWith("SML")) {  // NOI18N
258                sb.append(Bundle.getMessage("ReferenceLinePair", sml.getSourceMast().getDisplayName(), report.usageBean.getDisplayName()));  // NOI18N
259            }
260        }));
261        return addHeader(sb, "ReferenceMastSML");  // NOI18N
262    }
263
264    /**
265     * Create the Signal Group usage string.
266     * Usage keys:
267     * <ul>
268     * <li>SignalGroupMast</li>
269     * <li>SignalGroupHead</li>
270     * <li>SignalGroupHeadSensor</li>
271     * <li>SignalGroupHeadTurnout</li>
272     * </ul>
273     * @param bean The requesting bean:  Sensor, Signal Head, Signal Mast, Turnout.
274     * @return usage string
275     */
276    static String checkSignalGroups(NamedBean bean) {
277        StringBuilder sb = new StringBuilder();
278        InstanceManager.getDefault(SignalGroupManager.class).getNamedBeanSet().forEach((group) -> group.getUsageReport(bean).forEach((report) -> {
279            if (report.usageKey.startsWith("SignalGroup")) {  // NOI18N
280                String name = group.getDisplayName(NamedBean.DisplayOptions.USERNAME_SYSTEMNAME);
281                sb.append(Bundle.getMessage("ReferenceLineName", name));  // NOI18N
282            }
283        }));
284        return addHeader(sb, "ReferenceSignalGroup");  // NOI18N
285    }
286
287    /**
288     * Create the Signal Head usage string.
289     * Usage keys:
290     * <ul>
291     * <li>SignalHeadTurnout</li>
292     * </ul>
293     * @param bean The requesting bean:  Turnout.
294     * @return usage string
295     */
296    static String checkSignalHeads(NamedBean bean) {
297        StringBuilder sb = new StringBuilder();
298        InstanceManager.getDefault(SignalHeadManager.class).getNamedBeanSet().forEach((head) -> head.getUsageReport(bean).forEach((report) -> {
299            if (report.usageKey.startsWith("SignalHead")) {  // NOI18N
300                String name = head.getDisplayName(NamedBean.DisplayOptions.USERNAME_SYSTEMNAME);
301                sb.append(Bundle.getMessage("ReferenceLineName", name));  // NOI18N
302            }
303        }));
304        return addHeader(sb, "ReferenceSignalHead");  // NOI18N
305    }
306
307    /**
308     * Create the Signal Mast usage string.
309     * Usage keys:
310     * <ul>
311     * <li>SignalMastTurnout</li>
312     * <li>SignalMastSignalHead</li>
313     * </ul>
314     * @param bean The requesting bean:  Signal Head, Turnout.
315     * @return usage string
316     */
317    static String checkSignalMasts(NamedBean bean) {
318        StringBuilder sb = new StringBuilder();
319        InstanceManager.getDefault(SignalMastManager.class).getNamedBeanSet().forEach((mast) -> mast.getUsageReport(bean).forEach((report) -> {
320            if (report.usageKey.startsWith("SignalMast")) {  // NOI18N
321                String name = mast.getDisplayName(NamedBean.DisplayOptions.USERNAME_SYSTEMNAME);
322                sb.append(Bundle.getMessage("ReferenceLineName", name));  // NOI18N
323            }
324        }));
325        return addHeader(sb, "ReferenceSignalMast");  // NOI18N
326    }
327
328    /**
329     * Create the OBlock usage string.
330     * Usage keys:
331     * <ul>
332     * <li>OBlockSensor</li>
333     * <li>OBlockSensorError</li>
334     * <li>OBlockPortalNeighborOBlock</li>
335     * <li>OBlockPortalSignal</li>
336     * <li>OBlockPortalPathTurnout</li>
337     * <li>OBlockWarrant</li>
338     * </ul>
339     * @param bean The requesting bean:  OBlock (Neightbor), Sensor, SignalHead, SignalMast, Turnout, Warrant.
340     * @return usage string
341     */
342    static String checkOBlocks(NamedBean bean) {
343        StringBuilder sb = new StringBuilder();
344        InstanceManager.getDefault(OBlockManager.class).getNamedBeanSet().forEach((oblock) -> oblock.getUsageReport(bean).forEach((report) -> {
345            if (report.usageKey.startsWith("OBlock")) {  // NOI18N
346                String name = oblock.getDisplayName(NamedBean.DisplayOptions.USERNAME_SYSTEMNAME);
347                sb.append(Bundle.getMessage("ReferenceLineData", name, report.usageData));  // NOI18N
348            }
349        }));
350        return addHeader(sb, "ReferenceOBlock");  // NOI18N
351    }
352
353    /**
354     * Create the Warrant usage string.
355     * Usage keys:
356     * <ul>
357     * <li>WarrantBlocking</li>
358     * <li>WarrantBlock</li>
359     * <li>WarrantSignal</li>
360     * </ul>
361     * @param bean The requesting bean:  OBlock SignalHead, SignalMast, Warrant.
362     * @return usage string
363     */
364    static String checkWarrants(NamedBean bean) {
365        StringBuilder sb = new StringBuilder();
366        InstanceManager.getDefault(WarrantManager.class).getNamedBeanSet().forEach((warrant) -> warrant.getUsageReport(bean).forEach((report) -> {
367            if (report.usageKey.startsWith("Warrant")) {  // NOI18N
368                String name = warrant.getDisplayName(NamedBean.DisplayOptions.USERNAME_SYSTEMNAME);
369                sb.append(Bundle.getMessage("ReferenceLineName", name));  // NOI18N
370            }
371        }));
372        return addHeader(sb, "ReferenceWarrant");  // NOI18N
373    }
374
375    /**
376     * Create the Entry/Exit usage string.
377     * Usage keys:
378     * <ul>
379     * <li>EntryExitSourceSensor</li>
380     * <li>EntryExitSourceSignal</li>
381     * <li>EntryExitDestinationSensor</li>
382     * <li>EntryExitDestinationSignal</li>
383     * </ul>
384     * @param bean The requesting bean:  Sensor SignalHead, SignalMast.
385     * @return usage string
386     */
387    static String checkEntryExit(NamedBean bean) {
388        StringBuilder sb = new StringBuilder();
389        InstanceManager.getDefault(EntryExitPairs.class).getNamedBeanSet().forEach((destPoint) -> destPoint.getUsageReport(bean).forEach((report) -> {
390            if (report.usageKey.startsWith("EntryExit")) {  // NOI18N
391                String name = destPoint.getDisplayName();
392                sb.append(Bundle.getMessage("ReferenceLineName", name));  // NOI18N
393            }
394        }));
395        return addHeader(sb, "ReferenceEntryExit");  // NOI18N
396    }
397
398    /**
399     * Create the Logix/Conditional usage string.
400     * Usage keys:
401     * <ul>
402     * <li>ConditionalAction</li>
403     * <li>ConditionalVariable</li>
404     * <li>ConditionalVariableData</li>
405     * </ul>
406     * @param bean The requesting bean:  Many.
407     * @return usage string
408     */
409    static String checkLogixConditionals(NamedBean bean) {
410        StringBuilder sb = new StringBuilder();
411        InstanceManager.getDefault(LogixManager.class).getNamedBeanSet().forEach((logix) -> logix.getUsageReport(bean).forEach((report) -> {
412            if (report.usageKey.startsWith("ConditionalVariable") || report.usageKey.startsWith("ConditionalAction")) {  // NOI18N
413                String name = logix.getDisplayName(NamedBean.DisplayOptions.USERNAME_SYSTEMNAME);
414                String cdlName = report.usageBean.getDisplayName();
415                sb.append(Bundle.getMessage("ReferenceLineConditional", name, cdlName, Bundle.getMessage(report.usageKey), report.usageData));  // NOI18N
416            }
417        }));
418        return addHeader(sb, "ReferenceConditionals");  // NOI18N
419    }
420
421    /**
422     * Create the LogixNG/ConditionalNG usage string.
423     * Usage keys:
424     * <ul>
425     * <li>LogixNGAction</li>
426     * <li>LogixNGExpression</li>
427     * </ul>
428     * @param bean The requesting bean:  Many.
429     * @return usage string
430     */
431    static String checkLogixNGConditionals(NamedBean bean) {
432        StringBuilder sb = new StringBuilder();
433        InstanceManager.getDefault(LogixNG_Manager.class).getNamedBeanSet().forEach((logixng) -> logixng.getUsageReport(bean).forEach((report) -> {
434            if (report.usageKey.startsWith("LogixNG")) {  // NOI18N
435                String name = logixng.getDisplayName(NamedBean.DisplayOptions.USERNAME_SYSTEMNAME);
436                String cdlName = report.usageBean != null ? report.usageBean.getDisplayName() : "";
437                sb.append(Bundle.getMessage("ReferenceLineLogixNG", name, cdlName, Bundle.getMessage(report.usageKey), report.usageData));  // NOI18N
438            }
439        }));
440        InstanceManager.getDefault(ModuleManager.class).getNamedBeanSet().forEach((module) -> module.getUsageReport(bean).forEach((report) -> {
441            if (report.usageKey.startsWith("LogixNG")) {  // NOI18N
442                String name = module.getDisplayName(NamedBean.DisplayOptions.USERNAME_SYSTEMNAME);
443                sb.append(Bundle.getMessage("ReferenceLineModule", name, Bundle.getMessage(report.usageKey), report.usageData));  // NOI18N
444            }
445        }));
446        return addHeader(sb, "ReferenceLogixNG");  // NOI18N
447    }
448
449    /**
450     * Create the Section usage string.
451     * Usage keys:
452     * <ul>
453     * <li>SectionBlock</li>
454     * <li>SectionSensorForwardBlocking</li>
455     * <li>SectionSensorForwardStopping</li>
456     * <li>SectionSensorReverseBlocking</li>
457     * <li>SectionSensorReverseStopping</li>
458     * </ul>
459     * @param bean The requesting bean:  Block, Sensor.
460     * @return usage string
461     */
462    static String checkSections(NamedBean bean) {
463        StringBuilder sb = new StringBuilder();
464        InstanceManager.getDefault(SectionManager.class).getNamedBeanSet().forEach((section) -> section.getUsageReport(bean).forEach((report) -> {
465            if (report.usageKey.startsWith("SectionSensor")) {  // NOI18N
466                String name = section.getDisplayName(NamedBean.DisplayOptions.USERNAME_SYSTEMNAME);
467                sb.append(Bundle.getMessage("ReferenceLineName", name));  // NOI18N
468            }
469        }));
470        return addHeader(sb, "ReferenceSections");  // NOI18N
471    }
472
473    /**
474     * Create the Transit usage string.
475     * Usage keys:
476     * <ul>
477     * <li>TransitSection</li>
478     * <li>TransitSensorStopAllocation</li>
479     * <li>TransitActionSensorWhen</li>
480     * <li>TransitActionSensorWhat</li>
481     * <li>TransitActionSignalHeadWhat</li>
482     * <li>TransitActionSignalMastWhat</li>
483     * </ul>
484     * @param bean The requesting bean:  Section, Sensor, Signal Head, Signal Mast.
485     * @return usage string
486     */
487    static String checkTransits(NamedBean bean) {
488        StringBuilder sb = new StringBuilder();
489        InstanceManager.getDefault(TransitManager.class).getNamedBeanSet().forEach((transit) -> transit.getUsageReport(bean).forEach((report) -> {
490            String name = transit.getDisplayName(NamedBean.DisplayOptions.USERNAME_SYSTEMNAME);
491            if (report.usageKey.startsWith("TransitSensor") || report.usageKey.startsWith("TransitSection")) {  // NOI18N
492                sb.append(Bundle.getMessage("ReferenceLineName", name));  // NOI18N
493            }
494            if (report.usageKey.startsWith("TransitAction")) {  // NOI18N
495                sb.append(Bundle.getMessage("ReferenceLineAction", name, report.usageBean.getDisplayName()));  // NOI18N
496            }
497        }));
498        return addHeader(sb, "ReferenceTransits");  // NOI18N
499    }
500
501    /**
502     * Create the Panel usage string.  The string includes the icon class name.
503     * Usage keys:
504     * <ul>
505     * <li>PositionalIcon</li>
506     * <li>LayoutEditorTurnout</li>
507     * <li>LayoutEditorTurnout2</li>
508     * <li>LayoutEditorTurnoutBlock</li>
509     * <li>LayoutEditorTurnoutSensor</li>
510     * <li>LayoutEditorTurnoutSignalHead</li>
511     * <li>LayoutEditorTurnoutSignalMast</li>
512     * <li>LayoutEditorPointSensor</li>
513     * <li>LayoutEditorPointSignalHead</li>
514     * <li>LayoutEditorPointSignalMast</li>
515     * <li>LayoutEditorSegmentBlock</li>
516     * <li>LayoutEditorXingBlock</li>
517     * <li>LayoutEditorXingOther (sensor, head, mast)</li>
518     * <li>Switchboard (sensor, turnout, light)</li>
519     * </ul>
520     * Note:  The getUsageReport is invoked at either Editor or LayoutEditor depending on the
521     * panel type.  The LayoutEditor version does a super call and then does special turnout
522     * checking since LE turnouts are not icons.
523     * @param bean The requesting bean:  Many.
524     * @return usage string
525     */
526    static String checkPanels(NamedBean bean) {
527        StringBuilder sb = new StringBuilder();
528        InstanceManager.getDefault(EditorManager.class).getAll().forEach(panel ->
529            panel.getUsageReport(bean).forEach(report -> {
530                if (panel instanceof SwitchboardEditor) {
531                    sb.append(Bundle.getMessage("ReferenceLineName", report.usageData));  // NOI18N
532                } else {
533                    sb.append(Bundle.getMessage("ReferenceLinePanel", panel.getTitle(), report.usageData));  // NOI18N
534                }
535            }));
536        return addHeader(sb, "ReferencePanels");  // NOI18N
537    }
538
539    /**
540     * Create the CTC usage string.
541     * The CTC manager is found using the ConfigureManager instead of the InstanceManager.
542     * The CTC manager uses InstanceManagerAutoDefault which can result in unnecessary
543     * XML content when CTC is not being used.
544     * Usage keys:
545     * <ul>
546     * <li>CtcWhereUsedOther</li>
547     * <li>CtcWhereUsedCBHD</li>
548     * </ul>
549     * @param bean The requesting bean:  Block, Sensor, Signal Head, Signal Mast, Turnout.
550     * @return usage string
551     */
552    static String checkCTC(NamedBean bean) {
553        StringBuilder sb = new StringBuilder();
554
555        // Get the CTC manager via the ConfigureManager to avoid auto default.
556        InstanceManager.getOptionalDefault(ConfigureManager.class).ifPresent(cm -> {
557            cm.getInstanceList(CtcManager.class).forEach(m -> {
558                mgr = (CtcManager) m;
559            });
560        });
561
562        if (mgr != null) {
563            mgr.getUsageReport(bean).forEach((report) -> {
564                sb.append(Bundle.getMessage("ReferenceLineName", report.usageData));  // NOI18N
565            });
566        }
567        return addHeader(sb, "ReferenceCTC");  // NOI18N
568    }
569    static CtcManager mgr = null;
570
571    /**
572     * Add the specified section to the beginning of the string builder if there is data.
573     * @param sb The current string builder.
574     * @param bundleKey The key for the section header.
575     * @return the resulting string.
576     */
577    static String addHeader(StringBuilder sb, String bundleKey) {
578        if (sb.length() > 0) {
579            sb.insert(0, Bundle.getMessage("ReferenceHeader", Bundle.getMessage(bundleKey)));  // NOI18N
580            sb.append("\n");
581        }
582        return sb.toString();
583    }
584
585//     private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(WhereUsedCollectors.class);
586}