001package jmri.jmrit.ctc.configurexml;
002
003import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
004
005import java.beans.XMLDecoder;
006import java.io.BufferedInputStream;
007import java.io.BufferedReader;
008import java.io.BufferedWriter;
009import java.io.FileInputStream;
010import java.io.FileReader;
011import java.io.FileWriter;
012import java.io.IOException;
013import java.util.ArrayList;
014import jmri.*;
015import jmri.jmrit.ctc.*;
016import jmri.jmrit.ctc.editor.code.*;
017import jmri.jmrit.ctc.ctcserialdata.*;
018
019/**
020 * The external data was created using XMLEncoder.  The import process changes the
021 * class names in the xml file and then loads the temporary classes using XMLDecoder.
022 * The content from the temporary classes is then transferred and converted to the
023 * real classes.
024 *
025 * @author Dave Sand Copyright (c) 2020
026 */
027public class ImportExternalData {
028
029    static final CtcManager cm = InstanceManager.getDefault(CtcManager.class);
030    static ImportOtherData _mImportOtherData;
031    static ArrayList<ImportCodeButtonHandlerData> _mImportCodeButtonHandlerDataArrayList = new ArrayList<>();
032
033    private static final String CTC_FILE_NAME = "CTCSystem.xml";        // NOI18N
034    private static final String PROG_PROPS = "ProgramProperties.xml";   // NOI18N
035    private static final String TEMPORARY_EXTENSION = ".xmlTMP";        // NOI18N
036    private static final String SAVED_PREFIX = "V1_Save_";              // NOI18N
037
038    public static void loadExternalData() {
039        // Make an initial backup of the CTCSystem.xml file.  This only occurs on the very first run
040        // This backup can be used to run version 1 CTC.
041        String backName = SAVED_PREFIX + CTC_FILE_NAME;
042        if (!CTCFiles.fileExists(backName)) {
043            if (!CTCFiles.copyFile(CTC_FILE_NAME, backName, false)) {
044                log.warn("Unable to make version 1 copy: source = {}, backup = {}", CTC_FILE_NAME, backName);
045                return;
046            }
047        }
048        backName = SAVED_PREFIX + PROG_PROPS;
049        if (!CTCFiles.fileExists(backName)) {
050            if (!CTCFiles.copyFile(PROG_PROPS, backName, false)) {
051                log.warn("Unable to make version 1 copy: source = {}, backup = {}", PROG_PROPS, backName);
052                return;
053            }
054        }
055
056        cm.getProgramProperties().importExternalProgramProperties();    // Load ProgramProperties
057        if (loadCTCSystemContent()) {   // Load the CTCSystem.xml file into special classes
058            doDataLoading();            // Process the content
059        }
060
061        // Delete tempoary data files
062        if (!CTCFiles.deleteFile(CTC_FILE_NAME)) {
063            log.error("Delete failed for old CTCSystem.xml");
064        }
065        if (!CTCFiles.deleteFile(PROG_PROPS)) {
066            log.error("Delete failed for old ProgramProperties.xml");
067        }
068    }
069
070    @SuppressWarnings("unchecked") // See below comments:
071    public static boolean loadCTCSystemContent() {
072        String fullName = CTCFiles.getFullName(CTC_FILE_NAME);
073        ImportCodeButtonHandlerData.preprocessingUpgradeSelf(fullName);     // WHOLE FILE operations FIRST.
074        try {
075            convertClassNameReferences(CTC_FILE_NAME);   // Change the class references
076        } catch (Exception ex) {
077            log.error("Exception occurred converting the class names in CTCSystem.xml: ex = {}", ex.getMessage());
078            return false;
079        }
080
081        try {
082            try (XMLDecoder xmlDecoder = new XMLDecoder(new BufferedInputStream(new FileInputStream(fullName)))) {
083                _mImportOtherData = (ImportOtherData) xmlDecoder.readObject();
084                // triggers unchecked warning
085                _mImportCodeButtonHandlerDataArrayList = (ArrayList<ImportCodeButtonHandlerData>) xmlDecoder.readObject(); // Type safety: Unchecked cast from Object to ArrayList<>
086            }
087        } catch (IOException e) {
088            log.debug("Unable to read {}", CTC_FILE_NAME, e); // debug because missing file is not error
089        }
090        if (_mImportOtherData == null) {
091            log.error("---------  Import failed");
092            return false;
093        }
094
095        // Give each object a chance to upgrade itself BEFORE anything uses it:
096        _mImportOtherData.upgradeSelf();
097        for (ImportCodeButtonHandlerData codeButtonHandlerData : _mImportCodeButtonHandlerDataArrayList) {
098            codeButtonHandlerData.upgradeSelf();
099        }
100
101        return true;
102    }
103
104    @SuppressFBWarnings(value = "OS_OPEN_STREAM_EXCEPTION_PATH", justification = "Low risk due to rare usage")
105    static private void convertClassNameReferences(String fileName) throws Exception {
106        String temporaryFilename = fileName + TEMPORARY_EXTENSION;
107        int errors = 0;
108        if (!CTCFiles.deleteFile(temporaryFilename)) errors++;   // Just delete it for safety before we start:
109        BufferedReader bufferedReader = new BufferedReader(new FileReader(CTCFiles.getFullName(fileName)));
110        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(CTCFiles.getFullName(temporaryFilename)));
111        String aLine = null;
112        while ((aLine = bufferedReader.readLine()) != null) { // Not EOF:
113            aLine = aLine.replaceFirst("jmri.jmrit.ctc.ctcserialdata.", "jmri.jmrit.ctc.configurexml.Import");
114            writeLine(bufferedWriter, aLine);
115        }
116        bufferedReader.close();
117        bufferedWriter.close();
118        if (!CTCFiles.deleteFile(fileName)) errors++;   // Just delete it for safety before we start:
119        if (!CTCFiles.renameFile(temporaryFilename, fileName, false)) errors++;   // Just delete it for safety before we start:
120        log.debug("convertClassNameReferences: errors = {}", errors);
121     }
122
123    static private void writeLine(BufferedWriter bufferedWriter, String aLine) throws IOException {
124        bufferedWriter.write(aLine); bufferedWriter.newLine();
125    }
126
127    static void doDataLoading() {
128        loadOtherData();
129        _mImportCodeButtonHandlerDataArrayList.forEach(imp -> {
130            loadCodeButtonHandlerData(imp);
131        });
132        convertCallOnSensorNamesToNBHSensors();
133    }
134
135    static void loadCodeButtonHandlerData(ImportCodeButtonHandlerData oldCBHD) {
136    log.debug("------------- Create CBHD ------------");
137        int _mUniqueID = oldCBHD._mUniqueID;
138        int _mSwitchNumber = oldCBHD._mSwitchNumber;
139        int _mSignalEtcNumber = oldCBHD._mSignalEtcNumber;
140        int _mGUIColumnNumber = oldCBHD._mGUIColumnNumber;
141
142        // Create a new CodeButtonHandlerData via CodeButtonHandlerDataRoutines which sets default values and empty NBH... objects
143        CodeButtonHandlerData cbhd = CodeButtonHandlerDataRoutines.createNewCodeButtonHandlerData(
144                _mUniqueID, _mSwitchNumber, _mSignalEtcNumber, _mGUIColumnNumber, cm.getProgramProperties());
145        cm.getCTCSerialData().addCodeButtonHandlerData(cbhd);
146
147    log.debug("------------- Code ------------");
148
149        // Code section
150        cbhd._mCodeButtonInternalSensor = loadSensor(oldCBHD._mCodeButtonInternalSensor, true);
151        cbhd._mOSSectionOccupiedExternalSensor = loadSensor(oldCBHD._mOSSectionOccupiedExternalSensor, false);
152        cbhd._mOSSectionOccupiedExternalSensor2 = loadSensor(oldCBHD._mOSSectionOccupiedExternalSensor2, false);
153        cbhd._mOSSectionSwitchSlavedToUniqueID = oldCBHD._mOSSectionSwitchSlavedToUniqueID;
154        cbhd._mGUIGeneratedAtLeastOnceAlready = oldCBHD._mGUIGeneratedAtLeastOnceAlready;
155        cbhd._mCodeButtonDelayTime = oldCBHD._mCodeButtonDelayTime;
156
157    log.debug("------------- SIDI ------------");
158
159        // SIDI section
160        cbhd._mSIDI_Enabled = oldCBHD._mSIDI_Enabled;
161        cbhd._mSIDI_LeftInternalSensor = loadSensor(oldCBHD._mSIDI_LeftInternalSensor, true);
162        cbhd._mSIDI_NormalInternalSensor = loadSensor(oldCBHD._mSIDI_NormalInternalSensor, true);
163        cbhd._mSIDI_RightInternalSensor = loadSensor(oldCBHD._mSIDI_RightInternalSensor, true);
164        cbhd._mSIDI_CodingTimeInMilliseconds = oldCBHD._mSIDI_CodingTimeInMilliseconds;
165        cbhd._mSIDI_TimeLockingTimeInMilliseconds = oldCBHD._mSIDI_TimeLockingTimeInMilliseconds;
166        cbhd._mSIDI_LeftRightTrafficSignals = getSignalList(oldCBHD._mSIDI_LeftRightTrafficSignalsCSVList);
167        cbhd._mSIDI_RightLeftTrafficSignals = getSignalList(oldCBHD._mSIDI_RightLeftTrafficSignalsCSVList);
168
169        // Set the traffic direction based on indicator sensors.
170        String trafficDirection = "BOTH";
171        if (oldCBHD._mSIDI_LeftInternalSensor.isEmpty() && !oldCBHD._mSIDI_RightInternalSensor.isEmpty()) {
172            trafficDirection = "RIGHT";
173        } else if (!oldCBHD._mSIDI_LeftInternalSensor.isEmpty() && oldCBHD._mSIDI_RightInternalSensor.isEmpty()) {
174            trafficDirection = "LEFT";
175        }
176        cbhd._mSIDI_TrafficDirection = CodeButtonHandlerData.TRAFFIC_DIRECTION.valueOf(trafficDirection);
177
178    log.debug("------------- SIDL ------------");
179        // SIDL section
180        cbhd._mSIDL_Enabled = oldCBHD._mSIDL_Enabled;
181        cbhd._mSIDL_LeftInternalSensor = loadSensor(oldCBHD._mSIDL_LeftInternalSensor, true);
182        cbhd._mSIDL_NormalInternalSensor = loadSensor(oldCBHD._mSIDL_NormalInternalSensor, true);
183        cbhd._mSIDL_RightInternalSensor = loadSensor(oldCBHD._mSIDL_RightInternalSensor, true);
184
185    log.debug("------------- SWDI ------------");
186        // SWDI section
187        cbhd._mSWDI_Enabled = oldCBHD._mSWDI_Enabled;
188        cbhd._mSWDI_NormalInternalSensor = loadSensor(oldCBHD._mSWDI_NormalInternalSensor, true);
189        cbhd._mSWDI_ReversedInternalSensor = loadSensor(oldCBHD._mSWDI_ReversedInternalSensor, true);
190        cbhd._mSWDI_FeedbackDifferent = oldCBHD._mSWDI_FeedbackDifferent;
191        cbhd._mSWDI_ExternalTurnout = loadTurnout(oldCBHD._mSWDI_ExternalTurnout, oldCBHD._mSWDI_FeedbackDifferent);
192        cbhd._mSWDI_CodingTimeInMilliseconds = oldCBHD._mSWDI_CodingTimeInMilliseconds;
193        cbhd._mSWDI_GUITurnoutType = CodeButtonHandlerData.TURNOUT_TYPE.valueOf(oldCBHD._mSWDI_GUITurnoutType.toString());
194        cbhd._mSWDI_GUITurnoutLeftHand = oldCBHD._mSWDI_GUITurnoutLeftHand;
195        cbhd._mSWDI_GUICrossoverLeftHand = oldCBHD._mSWDI_GUICrossoverLeftHand;
196
197    log.debug("------------- SWDL ------------");
198        // SWDL section
199        cbhd._mSWDL_Enabled = oldCBHD._mSWDL_Enabled;
200        cbhd._mSWDL_InternalSensor = loadSensor(oldCBHD._mSWDL_InternalSensor, true);
201
202    log.debug("-------------  CO  ------------");
203        // CO section
204        cbhd._mCO_Enabled = oldCBHD._mCO_Enabled;
205        cbhd._mCO_CallOnToggleInternalSensor = loadSensor(oldCBHD._mCO_CallOnToggleInternalSensor, true);
206        cbhd._mCO_GroupingsList = getCallOnList(oldCBHD._mCO_GroupingsListString);
207
208    log.debug("------------- TRL  ------------");
209        // TRL section
210        cbhd._mTRL_Enabled = oldCBHD._mTRL_Enabled;
211        cbhd._mTRL_LeftTrafficLockingRules = getTrafficLocking(oldCBHD._mTRL_LeftTrafficLockingRulesSSVList);
212        cbhd._mTRL_RightTrafficLockingRules = getTrafficLocking(oldCBHD._mTRL_RightTrafficLockingRulesSSVList);
213
214    log.debug("------------- TUL  ------------");
215        // TUL section
216        cbhd._mTUL_Enabled = oldCBHD._mTUL_Enabled;
217        cbhd._mTUL_DispatcherInternalSensorLockToggle = loadSensor(oldCBHD._mTUL_DispatcherInternalSensorLockToggle, true);
218        cbhd._mTUL_ExternalTurnoutFeedbackDifferent = oldCBHD._mTUL_ExternalTurnoutFeedbackDifferent;
219        cbhd._mTUL_ExternalTurnout = loadTurnout(oldCBHD._mTUL_ExternalTurnout, oldCBHD._mTUL_ExternalTurnoutFeedbackDifferent);
220        cbhd._mTUL_DispatcherInternalSensorUnlockedIndicator = loadSensor(oldCBHD._mTUL_DispatcherInternalSensorUnlockedIndicator, true);
221        cbhd._mTUL_NoDispatcherControlOfSwitch = oldCBHD._mTUL_NoDispatcherControlOfSwitch;
222        cbhd._mTUL_ndcos_WhenLockedSwitchStateIsClosed = oldCBHD._mTUL_ndcos_WhenLockedSwitchStateIsClosed;
223
224        // Use the lock toggle to set the GUI icons boolean
225        cbhd._mTUL_GUI_IconsEnabled = cbhd._mTUL_DispatcherInternalSensorLockToggle.valid() ? true : false;
226
227        cbhd._mTUL_LockImplementation = CodeButtonHandlerData.LOCK_IMPLEMENTATION.valueOf(oldCBHD._mTUL_LockImplementation.toString());
228
229        cbhd._mTUL_AdditionalExternalTurnout1 = loadTurnout(oldCBHD._mTUL_AdditionalExternalTurnout1, oldCBHD._mTUL_AdditionalExternalTurnout1FeedbackDifferent);
230        cbhd._mTUL_AdditionalExternalTurnout2 = loadTurnout(oldCBHD._mTUL_AdditionalExternalTurnout2, oldCBHD._mTUL_AdditionalExternalTurnout2FeedbackDifferent);
231        cbhd._mTUL_AdditionalExternalTurnout3 = loadTurnout(oldCBHD._mTUL_AdditionalExternalTurnout3, oldCBHD._mTUL_AdditionalExternalTurnout3FeedbackDifferent);
232
233        cbhd._mTUL_AdditionalExternalTurnout1FeedbackDifferent = oldCBHD._mTUL_AdditionalExternalTurnout1FeedbackDifferent;
234        cbhd._mTUL_AdditionalExternalTurnout2FeedbackDifferent = oldCBHD._mTUL_AdditionalExternalTurnout2FeedbackDifferent;
235        cbhd._mTUL_AdditionalExternalTurnout3FeedbackDifferent = oldCBHD._mTUL_AdditionalExternalTurnout3FeedbackDifferent;
236
237    log.debug("-------------  IL  ------------");
238        // IL section
239        cbhd._mIL_Enabled = oldCBHD._mIL_Enabled;
240        cbhd._mIL_Signals = getSignalList(oldCBHD._mIL_ListOfCSVSignalNames);
241
242// Debugging aid -- not active due to SpotBugs
243//                 log.info("CodeButtonHandlerData, {}/{}:", _mSwitchNumber, _mSignalEtcNumber);
244//                 List<Field> fields = Arrays.asList(CodeButtonHandlerData.class.getFields());
245//                 fields.forEach(field -> {
246//                     try {
247//                         log.info("    CBHD: fld = {}, type = {}, val = {}", field.getName(), field.getType(), field.get(cbhd));
248//                     } catch (Exception ex) {
249//                         log.info("    CBHD list exception: {}", ex.getMessage());
250//                     }
251//                 });
252    }
253
254    /**
255     * Load the OtherData class.
256     */
257    static void loadOtherData() {
258        OtherData od = cm.getOtherData();
259
260//  Fleeting:
261        od._mFleetingToggleInternalSensor = loadSensor(_mImportOtherData._mFleetingToggleInternalSensor, true);
262        od._mDefaultFleetingEnabled = _mImportOtherData._mDefaultFleetingEnabled;
263
264//  Global startup:
265        od._mTUL_EnabledAtStartup = _mImportOtherData._mTUL_EnabledAtStartup;
266        od._mSignalSystemType = OtherData.SIGNAL_SYSTEM_TYPE.valueOf(_mImportOtherData._mSignalSystemType.toString());
267        od._mTUL_SecondsToLockTurnouts = _mImportOtherData._mTUL_SecondsToLockTurnouts;
268
269//  Next unique # for each created Column:
270        od._mNextUniqueNumber = _mImportOtherData._mNextUniqueNumber;
271
272//  CTC Debugging:
273        od._mCTCDebugSystemReloadInternalSensor = loadSensor(_mImportOtherData._mCTCDebugSystemReloadInternalSensor, true);
274        od._mCTCDebug_TrafficLockingRuleTriggeredDisplayInternalSensor = loadSensor(_mImportOtherData._mCTCDebug_TrafficLockingRuleTriggeredDisplayInternalSensor, true);
275
276//  GUI design:
277        od._mGUIDesign_NumberOfEmptyColumnsAtEnd = _mImportOtherData._mGUIDesign_NumberOfEmptyColumnsAtEnd  ;
278        od._mGUIDesign_CTCPanelType = OtherData.CTC_PANEL_TYPE.valueOf(_mImportOtherData._mGUIDesign_CTCPanelType.toString());
279        od._mGUIDesign_BuilderPlate = _mImportOtherData._mGUIDesign_BuilderPlate  ;
280        od._mGUIDesign_SignalsOnPanel = OtherData.SIGNALS_ON_PANEL.valueOf(_mImportOtherData._mGUIDesign_SignalsOnPanel.toString());
281        od._mGUIDesign_FleetingToggleSwitch = _mImportOtherData._mGUIDesign_FleetingToggleSwitch  ;
282        od._mGUIDesign_AnalogClockEtc = _mImportOtherData._mGUIDesign_AnalogClockEtc  ;
283        od._mGUIDesign_ReloadCTCSystemButton = _mImportOtherData._mGUIDesign_ReloadCTCSystemButton  ;
284        od._mGUIDesign_CTCDebugOnToggle = _mImportOtherData._mGUIDesign_CTCDebugOnToggle  ;
285        od._mGUIDesign_CreateTrackPieces = _mImportOtherData._mGUIDesign_CreateTrackPieces  ;
286        od._mGUIDesign_VerticalSize = OtherData.VERTICAL_SIZE.valueOf(_mImportOtherData._mGUIDesign_VerticalSize.toString());
287        od._mGUIDesign_OSSectionUnknownInconsistentRedBlink = _mImportOtherData._mGUIDesign_OSSectionUnknownInconsistentRedBlink  ;
288        od._mGUIDesign_TurnoutsOnPanel = _mImportOtherData._mGUIDesign_TurnoutsOnPanel  ;
289
290// Debugging aid -- not active due to SpotBugs
291//         log.info("OtherData:");
292//         List<Field> fields = Arrays.asList(ImportOtherData.class.getFields());
293//         fields.forEach(field -> {
294//             try {
295//                 log.info("    OtherData: fld = {}, type = {}, val = {}", field.getName(), field.getType(), field.get(_mImportOtherData));
296//             } catch (Exception ex) {
297//                 log.info("    OtherData list exception: {}", ex.getMessage());
298//             }
299//         });
300    }
301
302    // **** Load simple objects ****
303
304//     static String loadString(String value) {
305//         String newString = null;
306//         if (value != null) {
307//             newString = value;
308//         }
309//         return newString;
310//     }
311
312    static int loadInt(String value) {
313        int newInt = 0;
314        if (value != null) {
315            try {
316                newInt = Integer.parseInt(value);
317            } catch (NumberFormatException ex) {
318                log.warn("loadInt format exception: value = {}", value);
319            }
320        }
321        return newInt;
322    }
323
324//     static boolean loadBoolean(String value) {
325//         boolean newBoolean = false;
326//         if (value != null) {
327//             newBoolean = value.equals("true") ? true : false;
328//         }
329//         return newBoolean;
330//     }
331
332    static NBHSensor loadSensor(String value, boolean isInternal) {
333        NBHSensor sensor = null;
334        if (value != null && !value.isEmpty()) {
335            String sensorName = value;
336            sensor = cm.getNBHSensor(sensorName);
337            if (sensor == null) {
338                if (isInternal) {
339                    sensor = new NBHSensor("CtcManagerXml", "create internal = ", sensorName, sensorName);
340                } else {
341                    sensor = new NBHSensor("CtcManagerXml", "create standard = ", sensorName, sensorName, false);
342                }
343            }
344        } else {
345            sensor = new NBHSensor("CtcManagerXml", "", "Empty NBHSensor", "", true);
346        }
347        return sensor;
348    }
349
350    static NBHSignal loadSignal(String signalName) {
351        NBHSignal signal = null;
352        if (signalName != null && !signalName.isEmpty()) {
353            signal = cm.getNBHSignal(signalName);
354            if (signal == null) {
355                signal = new NBHSignal(signalName);
356            }
357        } else {
358            signal = new NBHSignal("");
359        }
360        return signal;
361    }
362
363    static NBHTurnout loadTurnout(String value, boolean feedback) {
364        NBHTurnout turnout = null;
365        if (value != null && !value.isEmpty()) {
366            String turnoutName = value;
367
368            turnout = cm.getNBHTurnout(turnoutName);
369            if (turnout == null) {
370                turnout = new NBHTurnout("CtcManagerXml", "", value, value, feedback);
371            }
372        } else {
373            turnout = new NBHTurnout("CtcManagerXml", "Empty NBHTurnout", "");
374        }
375        return turnout;
376    }
377
378    static NamedBeanHandle<Block> loadBlock(String value) {
379        NamedBeanHandle<Block> blockHandle = null;
380        if (value != null && !value.isEmpty()) {
381            blockHandle = cm.getBlock(value);
382            if (blockHandle == null) {
383                Block block = InstanceManager.getDefault(BlockManager.class).getBlock(value);
384                if (block != null) {
385                    blockHandle = InstanceManager.getDefault(NamedBeanHandleManager.class).getNamedBeanHandle(value, block);
386                    cm.putBlock(value, blockHandle);
387                }
388            }
389        }
390        return blockHandle;
391    }
392
393    // **** Load ArrayList objects ****
394
395    static ArrayList<NBHSignal> getSignalList(String value) {
396        ArrayList<NBHSignal> signalList = new ArrayList<>();
397        if (value != null) {
398            for (String signalName : ProjectsCommonSubs.getArrayListFromCSV(value)) {
399                NBHSignal signal = loadSignal(signalName);
400                signalList.add(signal);
401            }
402        }
403        return signalList;
404    }
405
406    static ArrayList<CallOnData> getCallOnList(String value) {
407        ArrayList<CallOnData> callOnList = new ArrayList<>();
408        for (String csvString : ProjectsCommonSubs.getArrayListFromSSV(value)) {
409            CallOnData cod = new CallOnData();
410
411            CallOnEntry entry = new CallOnEntry(csvString);
412            cod._mExternalSignal = loadSignal(entry._mExternalSignal);
413            cod._mSignalFacingDirection = entry._mSignalFacingDirection;
414            cod._mSignalAspectToDisplay = entry._mSignalAspectToDisplay;
415            cod._mCalledOnExternalSensor = loadSensor(entry._mCalledOnExternalSensor, false);
416            cod._mExternalBlock = loadBlock(entry._mExternalBlock);
417
418            cod._mSwitchIndicators = new ArrayList<>();
419            cod._mSwitchIndicatorNames = getCallOnSensorNames(entry);
420
421            callOnList.add(cod);
422        }
423        return callOnList;
424    }
425
426    static ArrayList<String> getCallOnSensorNames(CallOnEntry entry) {
427        ArrayList<String> sensorList = new ArrayList<>();
428        if (!entry._mSwitchIndicator1.isEmpty()) sensorList.add(entry._mSwitchIndicator1);
429        if (!entry._mSwitchIndicator2.isEmpty()) sensorList.add(entry._mSwitchIndicator2);
430        if (!entry._mSwitchIndicator3.isEmpty()) sensorList.add(entry._mSwitchIndicator3);
431        if (!entry._mSwitchIndicator4.isEmpty()) sensorList.add(entry._mSwitchIndicator4);
432        if (!entry._mSwitchIndicator5.isEmpty()) sensorList.add(entry._mSwitchIndicator5);
433        if (!entry._mSwitchIndicator6.isEmpty()) sensorList.add(entry._mSwitchIndicator6);
434        return sensorList;
435    }
436
437    static void convertCallOnSensorNamesToNBHSensors() {
438        for (CodeButtonHandlerData cbhd : cm.getCTCSerialData().getCodeButtonHandlerDataArrayList()) {
439            for (CallOnData cod : cbhd._mCO_GroupingsList) {
440                for (String sensorName : cod._mSwitchIndicatorNames) {
441                    NBHSensor sensor = cm.getNBHSensor(sensorName);
442                    if (sensor != null) {
443                        cod._mSwitchIndicators.add(sensor);
444                    }
445                }
446            }
447        }
448    }
449
450    static ArrayList<TrafficLockingData> getTrafficLocking(String value) {
451        ArrayList<TrafficLockingData> trlData = new ArrayList<>();
452        for (String csvString : ProjectsCommonSubs.getArrayListFromSSV(value)) {
453            TrafficLockingData trl = new TrafficLockingData();
454
455            TrafficLockingEntry entry = new TrafficLockingEntry(csvString);
456            trl._mUserRuleNumber = entry._mUserRuleNumber;
457            trl._mRuleEnabled = entry._mRuleEnabled;
458            trl._mDestinationSignalOrComment = entry._mDestinationSignalOrComment;
459
460            trl._mSwitchAlignments = getTRLSwitchList(entry);
461
462            trl._mOccupancyExternalSensors = getTRLSensorList(entry, true);
463            trl._mOptionalExternalSensors = getTRLSensorList(entry, false);
464
465            trlData.add(trl);
466        }
467        return trlData;
468    }
469
470    static ArrayList<TrafficLockingData.TRLSwitch> getTRLSwitchList(TrafficLockingEntry entry) {
471        ArrayList<TrafficLockingData.TRLSwitch> trlSwitches = new ArrayList<>();
472        if (!entry._mUserText1.isEmpty()) trlSwitches.add(createTRLSwitch(entry._mUserText1, entry._mSwitchAlignment1, entry._mUniqueID1));
473        if (!entry._mUserText2.isEmpty()) trlSwitches.add(createTRLSwitch(entry._mUserText2, entry._mSwitchAlignment2, entry._mUniqueID2));
474        if (!entry._mUserText3.isEmpty()) trlSwitches.add(createTRLSwitch(entry._mUserText3, entry._mSwitchAlignment3, entry._mUniqueID3));
475        if (!entry._mUserText4.isEmpty()) trlSwitches.add(createTRLSwitch(entry._mUserText4, entry._mSwitchAlignment4, entry._mUniqueID4));
476        if (!entry._mUserText5.isEmpty()) trlSwitches.add(createTRLSwitch(entry._mUserText5, entry._mSwitchAlignment5, entry._mUniqueID5));
477        return trlSwitches;
478    }
479
480    static TrafficLockingData.TRLSwitch createTRLSwitch(String text, String alignment, String id) {
481        return new TrafficLockingData.TRLSwitch(text, alignment, loadInt(id));
482    }
483
484    static ArrayList<NBHSensor> getTRLSensorList(TrafficLockingEntry entry, boolean occupancy) {
485        ArrayList<NBHSensor> sensorList = new ArrayList<>();
486        if (occupancy) {
487            if (!entry._mOccupancyExternalSensor1.isEmpty()) sensorList.add(loadSensor(entry._mOccupancyExternalSensor1, false));
488            if (!entry._mOccupancyExternalSensor2.isEmpty()) sensorList.add(loadSensor(entry._mOccupancyExternalSensor2, false));
489            if (!entry._mOccupancyExternalSensor3.isEmpty()) sensorList.add(loadSensor(entry._mOccupancyExternalSensor3, false));
490            if (!entry._mOccupancyExternalSensor4.isEmpty()) sensorList.add(loadSensor(entry._mOccupancyExternalSensor4, false));
491            if (!entry._mOccupancyExternalSensor5.isEmpty()) sensorList.add(loadSensor(entry._mOccupancyExternalSensor5, false));
492            if (!entry._mOccupancyExternalSensor6.isEmpty()) sensorList.add(loadSensor(entry._mOccupancyExternalSensor6, false));
493            if (!entry._mOccupancyExternalSensor7.isEmpty()) sensorList.add(loadSensor(entry._mOccupancyExternalSensor7, false));
494            if (!entry._mOccupancyExternalSensor8.isEmpty()) sensorList.add(loadSensor(entry._mOccupancyExternalSensor8, false));
495            if (!entry._mOccupancyExternalSensor9.isEmpty()) sensorList.add(loadSensor(entry._mOccupancyExternalSensor9, false));
496        } else {
497            if (!entry._mOptionalExternalSensor1.isEmpty()) sensorList.add(loadSensor(entry._mOptionalExternalSensor1, false));
498            if (!entry._mOptionalExternalSensor2.isEmpty()) sensorList.add(loadSensor(entry._mOptionalExternalSensor2, false));
499        }
500        return sensorList;
501    }
502
503    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ImportExternalData.class);
504}