001package jmri.jmrit.ctc.configurexml;
002
003import java.util.*;
004
005import jmri.*;
006import jmri.jmrit.ctc.*;
007import jmri.jmrit.ctc.editor.code.*;
008import jmri.jmrit.ctc.ctcserialdata.*;
009
010import org.jdom2.Element;
011import org.slf4j.Logger;
012import org.slf4j.LoggerFactory;
013
014/**
015 * Provides the functionality for persistence of the CTC tool data.  The data is stored
016 * in the PanelPro data xml file using the standard Load/Store process.
017 *
018 * @author Dave Sand Copyright (c) 2020
019 */
020public class CtcManagerXml extends jmri.managers.configurexml.AbstractNamedBeanManagerConfigXML {
021    CtcManager cm = InstanceManager.getDefault(CtcManager.class);
022
023    public CtcManagerXml() {
024    }
025
026    /**
027     * Implementation for storing the contents of the CTC configuration.
028     *
029     * @param o Object to store, of type CtcManager
030     * @return Element containing the complete info
031     */
032    @Override
033    public Element store(Object o) {
034        Element ctcdata = new Element("ctcdata");
035        setStoreElementClass(ctcdata);
036
037        ctcdata.addContent(storeProperties(cm));
038        ctcdata.addContent(storeOtherData(cm));
039        for (CodeButtonHandlerData cbhd : cm.getCTCSerialData().getCodeButtonHandlerDataArrayList()) {
040            Element cbhdElement = new Element("ctcCodeButtonData");
041
042            cbhdElement.addContent(storeInt("UniqueID", cbhd._mUniqueID));
043            cbhdElement.addContent(storeInt("SwitchNumber", cbhd._mSwitchNumber));
044            cbhdElement.addContent(storeInt("SignalEtcNumber", cbhd._mSignalEtcNumber));
045            cbhdElement.addContent(storeInt("GUIColumnNumber", cbhd._mGUIColumnNumber));
046
047            // Code section
048            cbhdElement.addContent(storeSensor("CodeButtonInternalSensor", cbhd._mCodeButtonInternalSensor));
049            cbhdElement.addContent(storeSensor("OSSectionOccupiedExternalSensor", cbhd._mOSSectionOccupiedExternalSensor));
050            cbhdElement.addContent(storeSensor("OSSectionOccupiedExternalSensor2", cbhd._mOSSectionOccupiedExternalSensor2));
051            cbhdElement.addContent(storeInt("OSSectionSwitchSlavedToUniqueID", cbhd._mOSSectionSwitchSlavedToUniqueID));
052            cbhdElement.addContent(storeBoolean("GUIGeneratedAtLeastOnceAlready", cbhd._mGUIGeneratedAtLeastOnceAlready));
053            cbhdElement.addContent(storeInt("CodeButtonDelayTime", cbhd._mCodeButtonDelayTime));
054
055            // SIDI section
056            cbhdElement.addContent(storeBoolean("SIDI_Enabled", cbhd._mSIDI_Enabled));
057            cbhdElement.addContent(storeSensor("SIDI_LeftInternalSensor", cbhd._mSIDI_LeftInternalSensor));
058            cbhdElement.addContent(storeSensor("SIDI_NormalInternalSensor", cbhd._mSIDI_NormalInternalSensor));
059            cbhdElement.addContent(storeSensor("SIDI_RightInternalSensor", cbhd._mSIDI_RightInternalSensor));
060            cbhdElement.addContent(storeInt("SIDI_CodingTimeInMilliseconds", cbhd._mSIDI_CodingTimeInMilliseconds));
061            cbhdElement.addContent(storeInt("SIDI_TimeLockingTimeInMilliseconds", cbhd._mSIDI_TimeLockingTimeInMilliseconds));
062            cbhdElement.addContent(storeString("SIDI_TrafficDirection", cbhd._mSIDI_TrafficDirection.toString()));
063            cbhdElement.addContent(storeSignalList("SIDI_LeftRightTrafficSignals", cbhd._mSIDI_LeftRightTrafficSignals));
064            cbhdElement.addContent(storeSignalList("SIDI_RightLeftTrafficSignals", cbhd._mSIDI_RightLeftTrafficSignals));
065
066            // SIDL section
067            cbhdElement.addContent(storeBoolean("SIDL_Enabled", cbhd._mSIDL_Enabled));
068            cbhdElement.addContent(storeSensor("SIDL_LeftInternalSensor", cbhd._mSIDL_LeftInternalSensor));
069            cbhdElement.addContent(storeSensor("SIDL_NormalInternalSensor", cbhd._mSIDL_NormalInternalSensor));
070            cbhdElement.addContent(storeSensor("SIDL_RightInternalSensor", cbhd._mSIDL_RightInternalSensor));
071
072            // SWDI section
073            cbhdElement.addContent(storeBoolean("SWDI_Enabled", cbhd._mSWDI_Enabled));
074            cbhdElement.addContent(storeSensor("SWDI_NormalInternalSensor", cbhd._mSWDI_NormalInternalSensor));
075            cbhdElement.addContent(storeSensor("SWDI_ReversedInternalSensor", cbhd._mSWDI_ReversedInternalSensor));
076            cbhdElement.addContent(storeTurnout("SWDI_ExternalTurnout", cbhd._mSWDI_ExternalTurnout));
077            cbhdElement.addContent(storeInt("SWDI_CodingTimeInMilliseconds", cbhd._mSWDI_CodingTimeInMilliseconds));
078            cbhdElement.addContent(storeBoolean("SWDI_FeedbackDifferent", cbhd._mSWDI_FeedbackDifferent));
079            cbhdElement.addContent(storeInt("SWDI_GUITurnoutType", cbhd._mSWDI_GUITurnoutType.getInt()));
080            cbhdElement.addContent(storeBoolean("SWDI_GUITurnoutLeftHand", cbhd._mSWDI_GUITurnoutLeftHand));
081            cbhdElement.addContent(storeBoolean("SWDI_GUICrossoverLeftHand", cbhd._mSWDI_GUICrossoverLeftHand));
082
083            // SWDL section
084            cbhdElement.addContent(storeBoolean("SWDL_Enabled", cbhd._mSWDL_Enabled));
085            cbhdElement.addContent(storeSensor("SWDL_InternalSensor", cbhd._mSWDL_InternalSensor));
086
087            // CO section
088            cbhdElement.addContent(storeBoolean("CO_Enabled", cbhd._mCO_Enabled));
089            cbhdElement.addContent(storeSensor("CO_CallOnToggleInternalSensor", cbhd._mCO_CallOnToggleInternalSensor));
090            cbhdElement.addContent(storeCallOnList("CO_GroupingsList", cbhd._mCO_GroupingsList));
091
092            // TRL section
093            cbhdElement.addContent(storeBoolean("TRL_Enabled", cbhd._mTRL_Enabled));
094            cbhdElement.addContent(storeTRLRules("TRL_LeftRules", cbhd._mTRL_LeftTrafficLockingRules));
095            cbhdElement.addContent(storeTRLRules("TRL_RightRules", cbhd._mTRL_RightTrafficLockingRules));
096
097            // TUL section
098            cbhdElement.addContent(storeBoolean("TUL_Enabled", cbhd._mTUL_Enabled));
099            cbhdElement.addContent(storeSensor("TUL_DispatcherInternalSensorLockToggle", cbhd._mTUL_DispatcherInternalSensorLockToggle));
100            cbhdElement.addContent(storeTurnout("TUL_ExternalTurnout", cbhd._mTUL_ExternalTurnout));
101            cbhdElement.addContent(storeBoolean("TUL_ExternalTurnoutFeedbackDifferent", cbhd._mTUL_ExternalTurnoutFeedbackDifferent));
102            cbhdElement.addContent(storeSensor("TUL_DispatcherInternalSensorUnlockedIndicator", cbhd._mTUL_DispatcherInternalSensorUnlockedIndicator));
103            cbhdElement.addContent(storeBoolean("TUL_NoDispatcherControlOfSwitch", cbhd._mTUL_NoDispatcherControlOfSwitch));
104            cbhdElement.addContent(storeBoolean("TUL_ndcos_WhenLockedSwitchStateIsClosed", cbhd._mTUL_ndcos_WhenLockedSwitchStateIsClosed));
105            cbhdElement.addContent(storeBoolean("TUL_GUI_IconsEnabled", cbhd._mTUL_GUI_IconsEnabled));
106            cbhdElement.addContent(storeInt("TUL_LockImplementation", cbhd._mTUL_LockImplementation.getInt()));
107            cbhdElement.addContent(storeTULAdditionalTurnouts("TUL_AdditionalExternalTurnouts", cbhd));
108
109            // IL section
110            cbhdElement.addContent(storeBoolean("IL_Enabled", cbhd._mIL_Enabled));
111            cbhdElement.addContent(storeSignalList("IL_Signals", cbhd._mIL_Signals));
112
113            ctcdata.addContent(cbhdElement);
114        }
115
116        return (ctcdata);
117    }
118
119    /**
120     * Subclass provides implementation to create the correct top element,
121     * including the type information. Default implementation is to use the
122     * local class here.
123     *
124     * @param ctcdata The top-level element being created
125     */
126    public void setStoreElementClass(Element ctcdata) {
127        ctcdata.setAttribute("class", "jmri.jmrit.ctc.configurexml.CtcManagerXml");
128    }
129
130    Element storeProperties(CtcManager cm) {
131        ProgramProperties pp = cm.getProgramProperties();
132
133        Element properties = new Element("ctcProperties");
134        properties.addContent(storeString("CodeButtonInternalSensorPattern", pp._mCodeButtonInternalSensorPattern));
135        properties.addContent(storeInt("SIDI_CodingTimeInMilliseconds", pp._mSIDI_CodingTimeInMilliseconds));
136        properties.addContent(storeString("SIDI_LeftInternalSensorPattern", pp._mSIDI_LeftInternalSensorPattern));
137        properties.addContent(storeString("SIDI_NormalInternalSensorPattern", pp._mSIDI_NormalInternalSensorPattern));
138        properties.addContent(storeString("SIDI_RightInternalSensorPattern", pp._mSIDI_RightInternalSensorPattern));
139        properties.addContent(storeInt("SIDI_TimeLockingTimeInMilliseconds", pp._mSIDI_TimeLockingTimeInMilliseconds));
140        properties.addContent(storeString("SIDL_LeftInternalSensorPattern", pp._mSIDL_LeftInternalSensorPattern));
141        properties.addContent(storeString("SIDL_NormalInternalSensorPattern", pp._mSIDL_NormalInternalSensorPattern));
142        properties.addContent(storeString("SIDL_RightInternalSensorPattern", pp._mSIDL_RightInternalSensorPattern));
143        properties.addContent(storeInt("SWDI_CodingTimeInMilliseconds", pp._mSWDI_CodingTimeInMilliseconds));
144        properties.addContent(storeString("SWDI_NormalInternalSensorPattern", pp._mSWDI_NormalInternalSensorPattern));
145        properties.addContent(storeString("SWDI_ReversedInternalSensorPattern", pp._mSWDI_ReversedInternalSensorPattern));
146        properties.addContent(storeString("SWDL_InternalSensorPattern", pp._mSWDL_InternalSensorPattern));
147        properties.addContent(storeString("CO_CallOnToggleInternalSensorPattern", pp._mCO_CallOnToggleInternalSensorPattern));
148        properties.addContent(storeString("TUL_DispatcherInternalSensorLockTogglePattern", pp._mTUL_DispatcherInternalSensorLockTogglePattern));
149        properties.addContent(storeString("TUL_DispatcherInternalSensorUnlockedIndicatorPattern", pp._mTUL_DispatcherInternalSensorUnlockedIndicatorPattern));
150        properties.addContent(storeInt("CodeButtonDelayTime", pp._mCodeButtonDelayTime));
151
152        return properties;
153    }
154
155    Element storeOtherData(CtcManager cm) {
156        OtherData od = cm.getOtherData();
157
158        Element otherData = new Element("ctcOtherData");
159
160        otherData.addContent(storeString("CtcVersion", OtherData.CTC_VERSION));
161
162//  Fleeting:
163        otherData.addContent(storeSensor("FleetingToggleInternalSensor", od._mFleetingToggleInternalSensor));
164        otherData.addContent(storeBoolean("DefaultFleetingEnabled", od._mDefaultFleetingEnabled));
165
166//  Global startup:
167        otherData.addContent(storeBoolean("TUL_EnabledAtStartup", od._mTUL_EnabledAtStartup));
168        otherData.addContent(storeInt("SignalSystemType", od._mSignalSystemType.getInt()));
169        otherData.addContent(storeInt("TUL_SecondsToLockTurnouts", od._mTUL_SecondsToLockTurnouts));
170
171//  Next unique # for each created Column:
172        otherData.addContent(storeInt("NextUniqueNumber", od._mNextUniqueNumber));
173
174//  CTC Debugging:
175        otherData.addContent(storeSensor("CTCDebugSystemReloadInternalSensor", od._mCTCDebugSystemReloadInternalSensor));
176        otherData.addContent(storeSensor("CTCDebug_TrafficLockingRuleTriggeredDisplayInternalSensor", od._mCTCDebug_TrafficLockingRuleTriggeredDisplayInternalSensor));
177
178//  GUI design:
179        otherData.addContent(storeInt("GUIDesign_NumberOfEmptyColumnsAtEnd", od._mGUIDesign_NumberOfEmptyColumnsAtEnd));
180        otherData.addContent(storeInt("GUIDesign_CTCPanelType", od._mGUIDesign_CTCPanelType.getRadioGroupValue()));
181        otherData.addContent(storeBoolean("GUIDesign_BuilderPlate", od._mGUIDesign_BuilderPlate));
182        otherData.addContent(storeInt("GUIDesign_SignalsOnPanel", od._mGUIDesign_SignalsOnPanel.getRadioGroupValue()));
183        otherData.addContent(storeBoolean("GUIDesign_FleetingToggleSwitch", od._mGUIDesign_FleetingToggleSwitch));
184        otherData.addContent(storeBoolean("GUIDesign_AnalogClockEtc", od._mGUIDesign_AnalogClockEtc));
185        otherData.addContent(storeBoolean("GUIDesign_ReloadCTCSystemButton", od._mGUIDesign_ReloadCTCSystemButton));
186        otherData.addContent(storeBoolean("GUIDesign_CTCDebugOnToggle", od._mGUIDesign_CTCDebugOnToggle));
187        otherData.addContent(storeBoolean("GUIDesign_CreateTrackPieces", od._mGUIDesign_CreateTrackPieces));
188        otherData.addContent(storeInt("GUIDesign_VerticalSize", od._mGUIDesign_VerticalSize.getRadioGroupValue()));
189        otherData.addContent(storeBoolean("GUIDesign_OSSectionUnknownInconsistentRedBlink", od._mGUIDesign_OSSectionUnknownInconsistentRedBlink));
190        otherData.addContent(storeBoolean("GUIDesign_TurnoutsOnPanel", od._mGUIDesign_TurnoutsOnPanel));
191
192        return otherData;
193    }
194
195    // **** Create elements for simple objects ****
196
197    Element storeString(String elementName, String elementValue) {
198        Element element = new Element(elementName);
199        element.setText(elementValue);
200        return element;
201    }
202
203    Element storeInt(String elementName, int elementValue) {
204        Element element = new Element(elementName);
205        element.setText(String.valueOf(elementValue));
206        return element;
207    }
208
209    Element storeBoolean(String elementName, boolean elementValue) {
210        Element element = new Element(elementName);
211        element.setText(elementValue == true ? "true" : "false");
212        return element;
213    }
214
215    Element storeSensor(String elementName, NBHSensor sensor) {
216        Element element = new Element(elementName);
217        if (sensor != null) {
218            element.setText(sensor.getHandleName());
219        }
220        return element;
221    }
222
223    Element storeSignal(String elementName, NBHSignal signal) {
224        Element element = new Element(elementName);
225        if (signal != null) {
226            element.setText(signal.getHandleName());
227        }
228        return element;
229    }
230
231    Element storeTurnout(String elementName, NBHTurnout turnout) {
232        Element element = new Element(elementName);
233        if (turnout != null) {
234            element.setText(turnout.getHandleName());
235        }
236        return element;
237    }
238
239    Element storeBlock(String elementName, NamedBeanHandle<Block> block) {
240        Element element = new Element(elementName);
241        if (block != null) {
242            element.setText(block.getName());
243        }
244        return element;
245    }
246
247    // **** Create elements for ArrayList objects ****
248
249    Element storeSensorList(String elementName, List<NBHSensor> sensors) {
250        Element element = new Element(elementName);
251        sensors.forEach(sensor -> {
252            element.addContent(storeSensor("sensor", sensor));
253        });
254        return element;
255    }
256
257    Element storeSignalList(String elementName, List<NBHSignal> signals) {
258        Element element = new Element(elementName);
259        signals.forEach(signal -> {
260            element.addContent(storeSignal("signal", signal));
261        });
262        return element;
263    }
264
265    Element storeCallOnList(String elementName, List<CallOnData> callOnList) {
266        Element element = new Element(elementName);
267        callOnList.forEach(row -> {
268            Element groupEntry = new Element("CO_GroupEntry");
269            groupEntry.addContent(storeSignal("ExternalSignal", row._mExternalSignal));
270            groupEntry.addContent(storeString("SignalFacingDirection", row._mSignalFacingDirection));
271            groupEntry.addContent(storeString("SignalAspectToDisplay", row._mSignalAspectToDisplay));
272            groupEntry.addContent(storeSensor("CalledOnExternalSensor", row._mCalledOnExternalSensor));
273            groupEntry.addContent(storeBlock("ExternalBlock", row._mExternalBlock));
274            groupEntry.addContent(storeSensorList("SwitchIndicators", row._mSwitchIndicators));
275            element.addContent(groupEntry);
276        });
277        return element;
278    }
279
280    Element storeTRLRules(String elementName, List<TrafficLockingData> trlList) {
281        Element element = new Element(elementName);
282        trlList.forEach(row -> {
283            Element ruleEntry = new Element("TRL_TrafficLockingRule");
284            ruleEntry.addContent(storeString("UserRuleNumber", row._mUserRuleNumber));
285            ruleEntry.addContent(storeString("RuleEnabled", row._mRuleEnabled));
286            ruleEntry.addContent(storeString("DestinationSignalOrComment", row._mDestinationSignalOrComment));
287
288            ruleEntry.addContent(storeTRLSwitches("switches", row._mSwitchAlignments));
289
290            ruleEntry.addContent(storeSensorList("OccupancyExternalSensors", row._mOccupancyExternalSensors));
291            ruleEntry.addContent(storeSensorList("OptionalExternalSensors", row._mOptionalExternalSensors));
292            element.addContent(ruleEntry);
293        });
294        return element;
295    }
296
297    Element storeTRLSwitches(String elementName, List<TrafficLockingData.TRLSwitch> trlSwitches) {
298        Element element = new Element(elementName);
299        trlSwitches.forEach(trlSwitch -> {
300            Element elSwitch = new Element("switch");
301            elSwitch.addContent(storeString("UserText", trlSwitch._mUserText));
302            elSwitch.addContent(storeString("SwitchAlignment", trlSwitch._mSwitchAlignment));
303            elSwitch.addContent(storeInt("UniqueID", trlSwitch._mUniqueID));
304            element.addContent(elSwitch);
305        });
306        return element;
307    }
308
309    Element storeTULAdditionalTurnouts(String elementName, CodeButtonHandlerData cbhd) {
310        Element element = new Element(elementName);
311
312        Element elementRow = createAdditionalTurnoutEntry(cbhd._mTUL_AdditionalExternalTurnout1, cbhd._mTUL_AdditionalExternalTurnout1FeedbackDifferent);
313        if (elementRow != null) element.addContent(elementRow);
314        elementRow = createAdditionalTurnoutEntry(cbhd._mTUL_AdditionalExternalTurnout2, cbhd._mTUL_AdditionalExternalTurnout2FeedbackDifferent);
315        if (elementRow != null) element.addContent(elementRow);
316        elementRow = createAdditionalTurnoutEntry(cbhd._mTUL_AdditionalExternalTurnout3, cbhd._mTUL_AdditionalExternalTurnout3FeedbackDifferent);
317        if (elementRow != null) element.addContent(elementRow);
318
319        return element;
320    }
321
322    Element createAdditionalTurnoutEntry(NBHTurnout turnout, boolean turnoutFeedback) {
323        Element element = null;
324        if (turnout.valid()) {
325            element = new Element("TUL_AdditionalExternalTurnoutEntry");
326            element.addContent(storeTurnout("TUL_AdditionalExternalTurnout", turnout));
327            element.addContent(storeBoolean("TUL_AdditionalExternalTurnoutFeedbackDifferent", turnoutFeedback));
328        }
329        return element;
330    }
331
332    @Override
333    public void load(Element element, Object o) {
334        log.error("Invalid method called");
335    }
336
337    /**
338     * Implementation for loading the contents of the CTC configuration.
339     *
340     * @param sharedCtcData Element to loaded.
341     * @param perNodeCtcData Element to loaded (same as sharedCtcData).
342     * @return true for successful load.
343     */
344    @Override
345    public boolean load(Element sharedCtcData, Element perNodeCtcData) {
346        List<Element> ctcList = sharedCtcData.getChildren();
347
348        for (Element lvl1 : ctcList) {
349            if (lvl1.getName().equals("ctcProperties")) {
350                loadProperties(cm, lvl1);
351                continue;
352            }
353            if (lvl1.getName().equals("ctcOtherData")) {
354                loadOtherData(cm, lvl1);
355                continue;
356            }
357            if (lvl1.getName().equals("ctcCodeButtonData")) {
358                // Create basic CodeButtonHandlerData
359    log.debug("------------- CBHD ------------");
360                int _mUniqueID = loadInt(lvl1.getChild("UniqueID"));
361                int _mSwitchNumber = loadInt(lvl1.getChild("SwitchNumber"));
362                int _mSignalEtcNumber = loadInt(lvl1.getChild("SignalEtcNumber"));
363                int _mGUIColumnNumber = loadInt(lvl1.getChild("GUIColumnNumber"));
364
365                // Create a new CodeButtonHandlerData via CodeButtonHandlerDataRoutines which sets default values and empty NBH... objects
366                CodeButtonHandlerData cbhd = CodeButtonHandlerDataRoutines.createNewCodeButtonHandlerData(
367                        _mUniqueID, _mSwitchNumber, _mSignalEtcNumber, _mGUIColumnNumber, cm.getProgramProperties());
368                cm.getCTCSerialData().addCodeButtonHandlerData(cbhd);
369
370    log.debug("------------- Code ------------");
371
372                // Code section
373                cbhd._mCodeButtonInternalSensor = loadSensor(lvl1.getChild("CodeButtonInternalSensor"), true);
374                cbhd._mOSSectionOccupiedExternalSensor = loadSensor(lvl1.getChild("OSSectionOccupiedExternalSensor"), false);
375                cbhd._mOSSectionOccupiedExternalSensor2 = loadSensor(lvl1.getChild("OSSectionOccupiedExternalSensor2"), false);
376                cbhd._mOSSectionSwitchSlavedToUniqueID = loadInt(lvl1.getChild("OSSectionSwitchSlavedToUniqueID"));
377                cbhd._mGUIGeneratedAtLeastOnceAlready = loadBoolean(lvl1.getChild("GUIGeneratedAtLeastOnceAlready"));
378                cbhd._mCodeButtonDelayTime = loadInt(lvl1.getChild("CodeButtonDelayTime"));
379    log.debug("------------- SIDI ------------");
380
381                // SIDI section
382                cbhd._mSIDI_Enabled = loadBoolean(lvl1.getChild("SIDI_Enabled"));
383                cbhd._mSIDI_LeftInternalSensor = loadSensor(lvl1.getChild("SIDI_LeftInternalSensor"), true);
384                cbhd._mSIDI_NormalInternalSensor = loadSensor(lvl1.getChild("SIDI_NormalInternalSensor"), true);
385                cbhd._mSIDI_RightInternalSensor = loadSensor(lvl1.getChild("SIDI_RightInternalSensor"), true);
386                cbhd._mSIDI_CodingTimeInMilliseconds = loadInt(lvl1.getChild("SIDI_CodingTimeInMilliseconds"));
387                cbhd._mSIDI_TimeLockingTimeInMilliseconds = loadInt(lvl1.getChild("SIDI_TimeLockingTimeInMilliseconds"));
388                cbhd._mSIDI_TrafficDirection = CodeButtonHandlerData.TRAFFIC_DIRECTION.valueOf(loadString(lvl1.getChild("SIDI_TrafficDirection")));
389                cbhd._mSIDI_LeftRightTrafficSignals = getSignalList(lvl1.getChild("SIDI_LeftRightTrafficSignals"));
390                cbhd._mSIDI_RightLeftTrafficSignals = getSignalList(lvl1.getChild("SIDI_RightLeftTrafficSignals"));
391
392    log.debug("------------- SIDL ------------");
393                // SIDL section
394                cbhd._mSIDL_Enabled = loadBoolean(lvl1.getChild("SIDL_Enabled"));
395                cbhd._mSIDL_LeftInternalSensor = loadSensor(lvl1.getChild("SIDL_LeftInternalSensor"), true);
396                cbhd._mSIDL_NormalInternalSensor = loadSensor(lvl1.getChild("SIDL_NormalInternalSensor"), true);
397                cbhd._mSIDL_RightInternalSensor = loadSensor(lvl1.getChild("SIDL_RightInternalSensor"), true);
398
399    log.debug("------------- SWDI ------------");
400                // SWDI section
401                cbhd._mSWDI_Enabled = loadBoolean(lvl1.getChild("SWDI_Enabled"));
402                cbhd._mSWDI_NormalInternalSensor = loadSensor(lvl1.getChild("SWDI_NormalInternalSensor"), true);
403                cbhd._mSWDI_ReversedInternalSensor = loadSensor(lvl1.getChild("SWDI_ReversedInternalSensor"), true);
404                cbhd._mSWDI_ExternalTurnout = loadTurnout(lvl1.getChild("SWDI_ExternalTurnout"), lvl1.getChild("SWDI_FeedbackDifferent"));
405                cbhd._mSWDI_CodingTimeInMilliseconds = loadInt(lvl1.getChild("SWDI_CodingTimeInMilliseconds"));
406                cbhd._mSWDI_FeedbackDifferent = loadBoolean(lvl1.getChild("SWDI_FeedbackDifferent"));
407                cbhd._mSWDI_GUITurnoutType = CodeButtonHandlerData.TURNOUT_TYPE.getTurnoutType(loadInt(lvl1.getChild("SWDI_GUITurnoutType")));
408                cbhd._mSWDI_GUITurnoutLeftHand = loadBoolean(lvl1.getChild("SWDI_GUITurnoutLeftHand"));
409                cbhd._mSWDI_GUICrossoverLeftHand = loadBoolean(lvl1.getChild("SWDI_GUICrossoverLeftHand"));
410
411    log.debug("------------- SWDL ------------");
412                // SWDL section
413                cbhd._mSWDL_Enabled = loadBoolean(lvl1.getChild("SWDL_Enabled"));
414                cbhd._mSWDL_InternalSensor = loadSensor(lvl1.getChild("SWDL_InternalSensor"), true);
415
416    log.debug("-------------  CO  ------------");
417                // CO section
418                cbhd._mCO_Enabled = loadBoolean(lvl1.getChild("CO_Enabled"));
419                cbhd._mCO_CallOnToggleInternalSensor = loadSensor(lvl1.getChild("CO_CallOnToggleInternalSensor"), true);
420                cbhd._mCO_GroupingsList = getCallOnList(lvl1.getChild("CO_GroupingsList"));
421
422    log.debug("------------- TRL  ------------");
423                // TRL section
424                cbhd._mTRL_Enabled = loadBoolean(lvl1.getChild("TRL_Enabled"));
425                cbhd._mTRL_LeftTrafficLockingRules = getTrafficLocking(lvl1.getChild("TRL_LeftRules"));
426                cbhd._mTRL_RightTrafficLockingRules = getTrafficLocking(lvl1.getChild("TRL_RightRules"));
427
428    log.debug("------------- TUL  ------------");
429                // TUL section
430                cbhd._mTUL_Enabled = loadBoolean(lvl1.getChild("TUL_Enabled"));
431                cbhd._mTUL_DispatcherInternalSensorLockToggle = loadSensor(lvl1.getChild("TUL_DispatcherInternalSensorLockToggle"), true);
432                cbhd._mTUL_ExternalTurnout = loadTurnout(lvl1.getChild("TUL_ExternalTurnout"), lvl1.getChild("TUL_ExternalTurnoutFeedbackDifferent"));
433                cbhd._mTUL_ExternalTurnoutFeedbackDifferent = loadBoolean(lvl1.getChild("TUL_ExternalTurnoutFeedbackDifferent"));
434                cbhd._mTUL_DispatcherInternalSensorUnlockedIndicator = loadSensor(lvl1.getChild("TUL_DispatcherInternalSensorUnlockedIndicator"), true);
435                cbhd._mTUL_NoDispatcherControlOfSwitch = loadBoolean(lvl1.getChild("TUL_NoDispatcherControlOfSwitch"));
436                cbhd._mTUL_ndcos_WhenLockedSwitchStateIsClosed = loadBoolean(lvl1.getChild("TUL_ndcos_WhenLockedSwitchStateIsClosed"));
437                cbhd._mTUL_GUI_IconsEnabled = loadBoolean(lvl1.getChild("TUL_GUI_IconsEnabled"));
438                cbhd._mTUL_LockImplementation = CodeButtonHandlerData.LOCK_IMPLEMENTATION.getLockImplementation(loadInt(lvl1.getChild("TUL_LockImplementation")));
439                loadAdditionalTurnouts(lvl1.getChild("TUL_AdditionalExternalTurnouts"), cbhd);
440
441    log.debug("-------------  IL  ------------");
442                // IL section
443                cbhd._mIL_Enabled = loadBoolean(lvl1.getChild("IL_Enabled"));
444                cbhd._mIL_Signals = getSignalList(lvl1.getChild("IL_Signals"));
445
446// Debugging aid -- not active due to SpotBugs
447//                 log.info("CodeButtonHandlerData, {}/{}:", _mSwitchNumber, _mSignalEtcNumber);
448//                 List<Field> fields = Arrays.asList(CodeButtonHandlerData.class.getFields());
449//                 fields.forEach(field -> {
450//                     try {
451//                         log.info("    CBHD: fld = {}, type = {}, val = {}", field.getName(), field.getType(), field.get(cbhd));
452//                     } catch (Exception ex) {
453//                         log.info("    CBHD list exception: {}", ex.getMessage());
454//                     }
455//                 });
456            }
457        }
458        convertCallOnSensorNamesToNBHSensors(cm);
459        return true;
460    }
461
462    /**
463     * Load the ProgramProperties class.
464     * @param cm The CTC manager.
465     * @param el The "ctcProperties" element.
466     */
467    void loadProperties(CtcManager cm, Element el) {
468        ProgramProperties pp = cm.getProgramProperties();
469
470        pp._mCodeButtonInternalSensorPattern = loadString(el.getChild("CodeButtonInternalSensorPattern"));
471        pp._mSIDI_CodingTimeInMilliseconds = loadInt(el.getChild("SIDI_CodingTimeInMilliseconds"));
472        pp._mSIDI_LeftInternalSensorPattern = loadString(el.getChild("SIDI_LeftInternalSensorPattern"));
473        pp._mSIDI_NormalInternalSensorPattern = loadString(el.getChild("SIDI_NormalInternalSensorPattern"));
474        pp._mSIDI_RightInternalSensorPattern = loadString(el.getChild("SIDI_RightInternalSensorPattern"));
475        pp._mSIDI_TimeLockingTimeInMilliseconds = loadInt(el.getChild("SIDI_TimeLockingTimeInMilliseconds"));
476        pp._mSIDL_LeftInternalSensorPattern = loadString(el.getChild("SIDL_LeftInternalSensorPattern"));
477        pp._mSIDL_NormalInternalSensorPattern = loadString(el.getChild("SIDL_NormalInternalSensorPattern"));
478        pp._mSIDL_RightInternalSensorPattern = loadString(el.getChild("SIDL_RightInternalSensorPattern"));
479        pp._mSWDI_CodingTimeInMilliseconds = loadInt(el.getChild("SWDI_CodingTimeInMilliseconds"));
480        pp._mSWDI_NormalInternalSensorPattern = loadString(el.getChild("SWDI_NormalInternalSensorPattern"));
481        pp._mSWDI_ReversedInternalSensorPattern = loadString(el.getChild("SWDI_ReversedInternalSensorPattern"));
482        pp._mSWDL_InternalSensorPattern = loadString(el.getChild("SWDL_InternalSensorPattern"));
483        pp._mCO_CallOnToggleInternalSensorPattern = loadString(el.getChild("CO_CallOnToggleInternalSensorPattern"));
484        pp._mTUL_DispatcherInternalSensorLockTogglePattern = loadString(el.getChild("TUL_DispatcherInternalSensorLockTogglePattern"));
485        pp._mTUL_DispatcherInternalSensorUnlockedIndicatorPattern = loadString(el.getChild("TUL_DispatcherInternalSensorUnlockedIndicatorPattern"));
486        pp._mCodeButtonDelayTime = loadInt(el.getChild("CodeButtonDelayTime"));
487
488// Debugging aid -- not active due to SpotBugs
489//             log.debug("ProgramProperties:");
490//             List<Field> fields = Arrays.asList(ProgramProperties.class.getFields());
491//             fields.forEach(field -> {
492//                 try {
493//                     log.info("    ProgramProperties: fld = {}, val = {}", field.getName(), field.get(pp));
494//                 } catch (Exception ex) {
495//                     log.info("    ProgramProperties list exception: {}", ex.getMessage());
496//                 }
497//             });
498    }
499
500    /**
501     * Load the OtherData class.
502     * @param cm The CTC manager.
503     * @param el The "ctcOtherData" element.
504     */
505    void loadOtherData(CtcManager cm, Element el) {
506        OtherData od = cm.getOtherData();
507
508        String xmlVersion = loadString(el.getChild("CtcVersion"));
509        xmlVersion = xmlVersion == null ? "v2.0" : xmlVersion;   // v2.0 is the initial version
510        if (!xmlVersion.equals(OtherData.CTC_VERSION)) {
511            log.warn("Update from version {} to version {} required", xmlVersion, OtherData.CTC_VERSION);
512        }
513
514//  Fleeting:
515        od._mFleetingToggleInternalSensor = loadSensor(el.getChild("FleetingToggleInternalSensor"), true);
516        od._mDefaultFleetingEnabled = loadBoolean(el.getChild("DefaultFleetingEnabled"));
517
518//  Global startup:
519        od._mTUL_EnabledAtStartup = loadBoolean(el.getChild("TUL_EnabledAtStartup"));
520        od._mSignalSystemType = OtherData.SIGNAL_SYSTEM_TYPE.getSignalSystemType(loadInt(el.getChild("SignalSystemType")));
521        od._mTUL_SecondsToLockTurnouts = loadInt(el.getChild("TUL_SecondsToLockTurnouts"));
522
523//  Next unique # for each created Column:
524        od._mNextUniqueNumber = loadInt(el.getChild("NextUniqueNumber"));
525
526//  CTC Debugging:
527        od._mCTCDebugSystemReloadInternalSensor = loadSensor(el.getChild("CTCDebugSystemReloadInternalSensor"), true);
528        od._mCTCDebug_TrafficLockingRuleTriggeredDisplayInternalSensor = loadSensor(el.getChild("CTCDebug_TrafficLockingRuleTriggeredDisplayInternalSensor"), true);
529
530//  GUI design:
531        od._mGUIDesign_NumberOfEmptyColumnsAtEnd = loadInt(el.getChild("GUIDesign_NumberOfEmptyColumnsAtEnd"));
532        od._mGUIDesign_CTCPanelType = OtherData.CTC_PANEL_TYPE.getRadioGroupValue(loadInt(el.getChild("GUIDesign_CTCPanelType")));
533        od._mGUIDesign_BuilderPlate = loadBoolean(el.getChild("GUIDesign_BuilderPlate"));
534        od._mGUIDesign_SignalsOnPanel = OtherData.SIGNALS_ON_PANEL.getRadioGroupValue(loadInt(el.getChild("GUIDesign_SignalsOnPanel")));
535        od._mGUIDesign_FleetingToggleSwitch = loadBoolean(el.getChild("GUIDesign_FleetingToggleSwitch"));
536        od._mGUIDesign_AnalogClockEtc = loadBoolean(el.getChild("GUIDesign_AnalogClockEtc"));
537        od._mGUIDesign_ReloadCTCSystemButton = loadBoolean(el.getChild("GUIDesign_ReloadCTCSystemButton"));
538        od._mGUIDesign_CTCDebugOnToggle = loadBoolean(el.getChild("GUIDesign_CTCDebugOnToggle"));
539        od._mGUIDesign_CreateTrackPieces = loadBoolean(el.getChild("GUIDesign_CreateTrackPieces"));
540        od._mGUIDesign_VerticalSize = OtherData.VERTICAL_SIZE.getRadioGroupValue(loadInt(el.getChild("GUIDesign_VerticalSize")));
541        od._mGUIDesign_OSSectionUnknownInconsistentRedBlink = loadBoolean(el.getChild("GUIDesign_OSSectionUnknownInconsistentRedBlink"));
542        od._mGUIDesign_TurnoutsOnPanel = loadBoolean(el.getChild("GUIDesign_TurnoutsOnPanel"));
543
544// Debugging aid -- not active due to SpotBugs
545//         log.info("OtherData:");
546//         List<Field> fields = Arrays.asList(OtherData.class.getFields());
547//         fields.forEach(field -> {
548//             try {
549//                 log.info("    OtherData: fld = {}, type = {}, val = {}", field.getName(), field.getType(), field.get(od));
550//             } catch (Exception ex) {
551//                 log.info("    OtherData list exception: {}", ex.getMessage());
552//             }
553//         });
554    }
555
556    // **** Load simple objects ****
557
558    String loadString(Element element) {
559        String newString = null;
560        if (element != null) {
561            newString = element.getValue();
562        }
563        return newString;
564    }
565
566    int loadInt(Element element) {
567        int newInt = 0;
568        if (element != null) {
569            try {
570                newInt = Integer.parseInt(element.getValue());
571            } catch (NumberFormatException ex) {
572                log.warn("loadInt format exception: element = {}, value = {}", element.getName(), element.getValue());
573            }
574        }
575        return newInt;
576    }
577
578    boolean loadBoolean(Element element) {
579        boolean newBoolean = false;
580        if (element != null) {
581            newBoolean = element.getValue().equals("true") ? true : false;
582        }
583        return newBoolean;
584    }
585
586    NBHSensor loadSensor(Element element, boolean isInternal) {
587        NBHSensor sensor = null;
588        if (element != null && element.getValue() != null && !element.getValue().isEmpty()) {
589            String sensorName = element.getValue();
590            sensor = cm.getNBHSensor(sensorName);
591            if (sensor == null) {
592                if (isInternal) {
593                    sensor = new NBHSensor("CtcManagerXml", "create internal = ", sensorName, sensorName);
594                } else {
595                    sensor = new NBHSensor("CtcManagerXml", "create standard = ", sensorName, sensorName, false);
596                }
597            }
598        } else {
599            sensor = new NBHSensor("CtcManagerXml", "", "Empty NBHSensor", "", true);
600        }
601        return sensor;
602    }
603
604    NBHSignal loadSignal(Element element) {
605        NBHSignal signal = null;
606        if (element != null && element.getValue() != null && !element.getValue().isEmpty()) {
607            String signalName  = element.getValue();
608            signal = cm.getNBHSignal(signalName);
609            if (signal == null) {
610                signal = new NBHSignal(element.getValue());
611            }
612        } else {
613            signal = new NBHSignal("");
614        }
615        return signal;
616    }
617
618    NBHTurnout loadTurnout(Element element, Element feedback) {
619        NBHTurnout turnout = null;
620        boolean feedBack = loadBoolean(feedback);
621        if (element != null && element.getValue() != null && !element.getValue().isEmpty()) {
622            String turnoutName = element.getValue();
623
624            turnout = cm.getNBHTurnout(turnoutName);
625            if (turnout == null) {
626                turnout = new NBHTurnout("CtcManagerXml", "", element.getValue(), element.getValue(), feedBack);
627            }
628        } else {
629            turnout = new NBHTurnout("CtcManagerXml", "Empty NBHTurnout", "");
630        }
631        return turnout;
632    }
633
634    NamedBeanHandle<Block> loadBlock(Element element) {
635        NamedBeanHandle<Block> blockHandle = null;
636        if (element != null && element.getValue() != null && !element.getValue().isEmpty()) {
637            blockHandle = cm.getBlock(element.getValue());
638            if (blockHandle == null) {
639                Block block = InstanceManager.getDefault(BlockManager.class).getBlock(element.getValue());
640                if (block != null) {
641                    blockHandle = InstanceManager.getDefault(NamedBeanHandleManager.class).getNamedBeanHandle(element.getValue(), block);
642                    cm.putBlock(element.getValue(), blockHandle);
643                }
644            }
645        }
646        return blockHandle;
647    }
648
649    // **** Load ArrayList objects ****
650
651    ArrayList<NBHSensor> getSensorList(Element element) {
652        ArrayList<NBHSensor> sensorList = new ArrayList<>();
653        if (element != null) {
654            for (Element el : element.getChildren()) {
655                NBHSensor sensor = loadSensor(el, false);
656                sensorList.add(sensor);
657            }
658        }
659        return sensorList;
660    }
661
662    ArrayList<NBHSignal> getSignalList(Element element) {
663        ArrayList<NBHSignal> signalList = new ArrayList<>();
664        if (element != null) {
665            for (Element el : element.getChildren()) {
666                NBHSignal signal = loadSignal(el);
667                signalList.add(signal);
668            }
669        }
670        return signalList;
671    }
672
673    ArrayList<CallOnData> getCallOnList(Element element) {
674        ArrayList<CallOnData> callOnList = new ArrayList<>();
675        if (element != null) {
676            for (Element elCallOn : element.getChildren()) {
677                CallOnData cod = new CallOnData();
678                cod._mExternalSignal = loadSignal(elCallOn.getChild("ExternalSignal"));
679                cod._mSignalFacingDirection = loadString(elCallOn.getChild("SignalFacingDirection"));
680                cod._mSignalAspectToDisplay = loadString(elCallOn.getChild("SignalAspectToDisplay"));
681                cod._mCalledOnExternalSensor = loadSensor(elCallOn.getChild("CalledOnExternalSensor"), false);
682                cod._mExternalBlock = loadBlock(elCallOn.getChild("ExternalBlock"));
683                cod._mSwitchIndicators = new ArrayList<>();
684                cod._mSwitchIndicatorNames = getCallOnSensorNames(elCallOn.getChild("SwitchIndicators"));
685                callOnList.add(cod);
686            }
687        }
688        return callOnList;
689    }
690
691    ArrayList<String> getCallOnSensorNames(Element element) {
692        ArrayList<String> sensorList = new ArrayList<>();
693        if (element != null) {
694            for (Element el : element.getChildren()) {
695                sensorList.add(el.getValue());
696            }
697        }
698        return sensorList;
699    }
700
701    void convertCallOnSensorNamesToNBHSensors(CtcManager cm) {
702        for (CodeButtonHandlerData cbhd : cm.getCTCSerialData().getCodeButtonHandlerDataArrayList()) {
703            for (CallOnData cod : cbhd._mCO_GroupingsList) {
704                for (String sensorName : cod._mSwitchIndicatorNames) {
705                    NBHSensor sensor = cm.getNBHSensor(sensorName);
706                    if (sensor != null) {
707                        cod._mSwitchIndicators.add(sensor);
708                    }
709                }
710            }
711        }
712    }
713
714    ArrayList<TrafficLockingData> getTrafficLocking(Element element) {
715        ArrayList<TrafficLockingData> trlData = new ArrayList<>();
716        if (element != null) {
717            for (Element elRule : element.getChildren()) {
718                TrafficLockingData trl = new TrafficLockingData();
719                trl._mUserRuleNumber = loadString(elRule.getChild("UserRuleNumber"));
720                trl._mRuleEnabled = loadString(elRule.getChild("RuleEnabled"));
721                trl._mDestinationSignalOrComment = loadString(elRule.getChild("DestinationSignalOrComment"));
722
723                trl._mSwitchAlignments = getTRLSwitchList(elRule.getChild("switches"));
724
725                trl._mOccupancyExternalSensors = getSensorList(elRule.getChild("OccupancyExternalSensors"));
726                trl._mOptionalExternalSensors = getSensorList(elRule.getChild("OptionalExternalSensors"));
727                trlData.add(trl);
728            }
729        }
730        return trlData;
731    }
732
733    ArrayList<TrafficLockingData.TRLSwitch> getTRLSwitchList(Element element) {
734        ArrayList<TrafficLockingData.TRLSwitch> trlSwitches = new ArrayList<>();
735        if (element != null) {
736            for (Element elSwitch : element.getChildren()) {
737                String userText = loadString(elSwitch.getChild("UserText"));
738                if (userText != null && !userText.isEmpty()) {
739                    TrafficLockingData.TRLSwitch newSwitch = new TrafficLockingData.TRLSwitch(
740                            userText,
741                            loadString(elSwitch.getChild("SwitchAlignment")),
742                            loadInt(elSwitch.getChild("UniqueID")));
743                    trlSwitches.add(newSwitch);
744                }
745            }
746        }
747        return trlSwitches;
748    }
749
750    void loadAdditionalTurnouts(Element element, CodeButtonHandlerData cbhd) {      // TUL_AdditionalExternalTurnouts
751        if (element != null) {
752            int rowNumber = 0;
753            for (Element elTurnout : element.getChildren()) {       // TUL_AdditionalExternalTurnoutEntry
754                rowNumber++;
755                NBHTurnout turnout = loadTurnout(elTurnout.getChild("TUL_AdditionalExternalTurnout"), elTurnout.getChild("TUL_AdditionalExternalTurnoutFeedbackDifferent"));
756                boolean feedback = loadBoolean(elTurnout.getChild("TUL_AdditionalExternalTurnoutFeedbackDifferent"));
757
758                if (rowNumber == 1) {
759                    cbhd._mTUL_AdditionalExternalTurnout1 = turnout;
760                    cbhd._mTUL_AdditionalExternalTurnout1FeedbackDifferent = feedback;
761                }
762                if (rowNumber == 2) {
763                    cbhd._mTUL_AdditionalExternalTurnout2 = turnout;
764                    cbhd._mTUL_AdditionalExternalTurnout2FeedbackDifferent = feedback;
765                }
766                if (rowNumber == 3) {
767                    cbhd._mTUL_AdditionalExternalTurnout3 = turnout;
768                    cbhd._mTUL_AdditionalExternalTurnout3FeedbackDifferent = feedback;
769                }
770            }
771        }
772    }
773
774    @Override
775    public int loadOrder() {
776        return InstanceManager.getDefault(jmri.jmrit.ctc.CtcManager.class).getXMLOrder();
777    }
778
779    private final static Logger log = LoggerFactory.getLogger(CtcManagerXml.class);
780}