001package jmri.jmrit.entryexit.configurexml;
002
003import java.awt.Color;
004import java.util.ArrayList;
005import java.util.List;
006import java.util.Comparator;
007import jmri.ConfigureManager;
008import jmri.InstanceManager;
009import jmri.NamedBean;
010import jmri.Sensor;
011import jmri.SensorManager;
012import jmri.SignalHead;
013import jmri.SignalHeadManager;
014import jmri.SignalMast;
015import jmri.SignalMastManager;
016import jmri.configurexml.AbstractXmlAdapter;
017import jmri.jmrit.display.layoutEditor.LayoutEditor;
018import jmri.jmrit.entryexit.EntryExitPairs;
019import jmri.util.ColorUtil;
020import org.jdom2.Element;
021import org.slf4j.Logger;
022import org.slf4j.LoggerFactory;
023
024/**
025 * This module handles configuration for the Entry Exit pairs used in
026 * interlocking on a Layout Editor Panel.
027 *
028 * @author Kevin Dickerson Copyright (c) 2007
029 */
030public class EntryExitPairsXml extends AbstractXmlAdapter {
031
032    public EntryExitPairsXml() {
033    }
034
035    /**
036     * Default implementation for storing the contents of a PositionablePoint.
037     *
038     * @param o Object to store, of type PositionablePoint
039     * @return Element containing the complete info
040     */
041    @Override
042    public Element store(Object o) {
043        EntryExitPairs p = (EntryExitPairs) o;
044        Element element = new Element("entryexitpairs");  // NOI18N
045        setStoreElementClass(element);
046        List<LayoutEditor> editors = p.getSourcePanelList();
047        if (editors.isEmpty()) {
048            return null;    //return element;   // <== don't store empty (unused) element
049        }
050
051        java.util.Collections.sort(editors, new Comparator<LayoutEditor>(){
052                    @Override
053                    public int compare(LayoutEditor o1, LayoutEditor o2) { return o1.toString().compareTo(o2.toString() ); }
054                });
055
056        int clearDown = p.getClearDownOption();
057        if (clearDown > 0) {
058            element.addContent(new Element("cleardown").addContent("" + clearDown));  // NOI18N
059        }
060
061        int overLap = p.getOverlapOption();
062        if (overLap > 0) {
063            element.addContent(new Element("overlap").addContent("" + overLap));  // NOI18N
064        }
065
066        int memoryClearDelay = p.getMemoryClearDelay();
067        if (memoryClearDelay > 0) {
068            element.addContent(new Element("memorycleardelay").addContent("" + memoryClearDelay));  // NOI18N
069        }
070
071        String memoryName = p.getMemoryOption();
072        if (!memoryName.isEmpty()) {
073            element.addContent(new Element("memoryname").addContent(memoryName));  // NOI18N
074        }
075
076        if (p.getDispatcherIntegration()) {
077            element.addContent(new Element("dispatcherintegration").addContent("yes"));  // NOI18N
078        }
079
080        if (p.useDifferentColorWhenSetting()) {
081            element.addContent(new Element("colourwhilesetting")
082                    .addContent(ColorUtil.colorToColorName(p.getSettingRouteColor())));  // NOI18N
083            element.addContent(new Element("settingTimer").addContent("" + p.getSettingTimer()));  // NOI18N
084        }
085
086        if (p.isAbsSignalMode()) {
087            element.addContent(new Element("abssignalmode").addContent("yes"));  // NOI18N
088        }
089
090        if (p.isQuietFail()) {
091            element.addContent(new Element("quietfail").addContent("yes"));  // NOI18N
092        }
093
094        if (p.isSkipGuiFix()) {
095            element.addContent(new Element("skipguifix").addContent("yes"));  // NOI18N
096        }
097
098        for (int k = 0; k < editors.size(); k++) {
099            LayoutEditor panel = editors.get(k);
100            List<Object> nxpair = p.getSourceList(panel);
101
102            java.util.Collections.sort(nxpair, new Comparator<Object>(){
103                    @Override
104                    public int compare(Object o1, Object o2) { return o1.toString().compareTo(o2.toString() ); }
105                });
106            Element panelElem = new Element("layoutPanel");  // NOI18N
107            panelElem.setAttribute("name", panel.getLayoutName());  // NOI18N
108            for (int j = 0; j < nxpair.size(); j++) {
109                Object key = nxpair.get(j);
110                Element source = new Element("source");  // NOI18N
111                String type = "";
112                String item = "";
113
114                if (key instanceof SignalMast) {
115                    type = "signalMast";  // NOI18N
116                    item = ((SignalMast) key).getDisplayName();
117                } else if (key instanceof Sensor) {
118                    type = "sensor";  // NOI18N
119                    item = ((Sensor) key).getDisplayName();
120                } else if (key instanceof SignalHead) {
121                    type = "signalHead";  // NOI18N
122                    item = ((SignalHead) key).getDisplayName();
123                }
124
125                source.setAttribute("type", type);  // NOI18N
126                source.setAttribute("item", item);  // NOI18N
127
128                List<Object> a = p.getDestinationList(key, panel);
129                java.util.Collections.sort(a, new Comparator<Object>(){
130                    @Override
131                    public int compare(Object o1, Object o2) { return o1.toString().compareTo(o2.toString() ); }
132                });
133
134                for (int i = 0; i < a.size(); i++) {
135                    Object keyDest = a.get(i);
136                    String typeDest = "";
137                    String itemDest = "";
138                    if (keyDest instanceof SignalMast) {
139                        typeDest = "signalMast";  // NOI18N
140                        itemDest = ((SignalMast) keyDest).getDisplayName();
141                    } else if (keyDest instanceof Sensor) {
142                        typeDest = "sensor";  // NOI18N
143                        itemDest = ((Sensor) keyDest).getDisplayName();
144                    } else if (keyDest instanceof SignalHead) {
145                        typeDest = "signalHead";  // NOI18N
146                        itemDest = ((SignalHead) keyDest).getDisplayName();
147                    }
148                    Element dest = new Element("destination");  // NOI18N
149                    dest.setAttribute("type", typeDest);  // NOI18N
150                    dest.setAttribute("item", itemDest);  // NOI18N
151                    if (!p.isUniDirection(key, panel, keyDest)) {
152                        dest.setAttribute("uniDirection", "no");  // NOI18N
153                    }
154                    if (!p.isEnabled(key, panel, keyDest)) {
155                        dest.setAttribute("enabled", "no");  // NOI18N
156                    }
157                    int nxType = p.getEntryExitType(key, panel, keyDest);
158                    switch (nxType) {
159                        case 0x01:
160                            dest.setAttribute("nxType", "signalmastlogic");  // NOI18N
161                            break;
162                        case 0x02:
163                            dest.setAttribute("nxType", "fullinterlocking");  // NOI18N
164                            break;
165                        case 0x00:
166                        default:
167                            dest.setAttribute("nxType", "turnoutsetting");  // NOI18N
168                            break;
169                    }
170                    if (p.getUniqueId(key, panel, keyDest) != null) {
171                        dest.setAttribute("uniqueid", p.getUniqueId(key, panel, keyDest));  // NOI18N
172                    }
173                    source.addContent(dest);
174                }
175                panelElem.addContent(source);
176            }
177            element.addContent(panelElem);
178        }
179        return element;
180    }
181
182    /**
183     * Define attribute for an element that is to be stored.
184     *
185     * @param messages Storage element
186     */
187    public void setStoreElementClass(Element messages) {
188        messages.setAttribute("class", "jmri.jmrit.entryexit.configurexml.EntryExitPairsXml");  // NOI18N
189    }
190
191    /**
192     * Load, starting with the layoutBlock element, then all the value-icon
193     * pairs.
194     *
195     * @param shared  Top level Element to unpack
196     * @param perNode ignored in this application
197     * @return true if loaded without errors; false otherwise
198     */
199    @Override
200    public boolean load(Element shared, Element perNode) {
201        // create the objects
202        EntryExitPairs eep = InstanceManager.getDefault(EntryExitPairs.class);
203        String nodeText;
204
205        nodeText = shared.getChildText("cleardown");
206        if (nodeText != null) eep.setClearDownOption(Integer.parseInt(nodeText));
207
208        nodeText = shared.getChildText("overlap");
209        if (nodeText != null) eep.setOverlapOption(Integer.parseInt(nodeText));
210
211        nodeText = shared.getChildText("memorycleardelay");
212        if (nodeText != null) eep.setMemoryClearDelay(Integer.parseInt(nodeText));
213
214        nodeText = shared.getChildText("memoryname");
215        if (nodeText != null) eep.setMemoryOption(nodeText);
216
217        // get attributes
218        ConfigureManager cm = InstanceManager.getNullableDefault(jmri.ConfigureManager.class);
219        List<Object> loadedPanel;
220        if (cm != null) {
221            loadedPanel = cm.getInstanceList(LayoutEditor.class);
222        } else {
223            log.error("Failed getting optional default config manager");  // NOI18N
224            loadedPanel = new ArrayList<>();
225        }
226
227        if (shared.getChild("dispatcherintegration") != null && shared.getChild("dispatcherintegration").getText().equals("yes")) {  // NOI18N
228            eep.setDispatcherIntegration(true);
229        }
230
231        if (shared.getChild("colourwhilesetting") != null) {
232            try {
233                eep.setSettingRouteColor(ColorUtil.stringToColor(shared.getChild("colourwhilesetting").getText()));  // NOI18N
234            } catch (IllegalArgumentException e) {
235                eep.setSettingRouteColor(Color.BLACK);
236                log.error("Invalid color {}; using black", shared.getChild("colourwhilesetting").getText());
237            }
238            int settingTimer = 2000;
239            try {
240                settingTimer = Integer.parseInt(shared.getChild("settingTimer").getText());  // NOI18N
241            } catch (NumberFormatException e) {
242                log.error("Error in converting timer to int {}", shared.getChild("settingTimer"));  // NOI18N
243            }
244            eep.setSettingTimer(settingTimer);
245        }
246
247        if (shared.getChild("abssignalmode") != null && shared.getChild("abssignalmode").getText().equals("yes")) {  // NOI18N
248            eep.setAbsSignalMode(true);
249        }
250
251        if (shared.getChild("quietfail") != null && shared.getChild("quietfail").getText().equals("yes")) {  // NOI18N
252            eep.setQuietFail(true);
253        }
254
255        if (shared.getChild("skipguifix") != null && shared.getChild("skipguifix").getText().equals("yes")) {  // NOI18N
256            eep.setSkipGuiFix(true);
257        }
258
259        List<Element> panelList = shared.getChildren("layoutPanel");  // NOI18N
260        for (int k = 0; k < panelList.size(); k++) {
261            String panelName = panelList.get(k).getAttribute("name").getValue();  // NOI18N
262            LayoutEditor panel = null;
263            for (int i = 0; i < loadedPanel.size(); i++) {
264                LayoutEditor tmp = (LayoutEditor) loadedPanel.get(i);
265                if (tmp.getLayoutName().equals(panelName)) {
266                    panel = tmp;
267                    break;
268                }
269            }
270            if (panel != null) {
271                List<Element> sourceList = panelList.get(k).getChildren("source");  // NOI18N
272                for (int i = 0; i < sourceList.size(); i++) {
273                    String sourceType = sourceList.get(i).getAttribute("type").getValue();  // NOI18N
274                    String sourceItem = sourceList.get(i).getAttribute("item").getValue();  // NOI18N
275                    NamedBean source = null;
276                    switch (sourceType) {
277                        case "signalMast": // NOI18N
278                            source = InstanceManager.getDefault(SignalMastManager.class).getSignalMast(sourceItem);
279                            break;
280                        case "sensor": // NOI18N
281                            source = InstanceManager.getDefault(SensorManager.class).getSensor(sourceItem);
282                            break;
283                        case "signalHead": // NOI18N
284                            source = InstanceManager.getDefault(SignalHeadManager.class).getSignalHead(sourceItem);
285                            break;
286                        default:
287                            break;
288                    }
289
290                    //These two could be subbed off.
291                    List<Element> destinationList = sourceList.get(i).getChildren("destination");  // NOI18N
292                    if (destinationList.size() > 0) {
293                        eep.addNXSourcePoint(source, panel);
294                    }
295                    for (int j = 0; j < destinationList.size(); j++) {
296                        String id = null;
297                        if (destinationList.get(j).getAttribute("uniqueid") != null) {  // NOI18N
298                            id = destinationList.get(j).getAttribute("uniqueid").getValue();  // NOI18N
299                            if (!id.startsWith("IN:")) {     // NOI18N
300                                id = "IN:" + id;    // NOI18N
301                            }
302                        }
303                        String destType = destinationList.get(j).getAttribute("type").getValue();  // NOI18N
304                        String destItem = destinationList.get(j).getAttribute("item").getValue();  // NOI18N
305                        NamedBean dest = null;
306                        switch (destType) {
307                            case "signalMast": // NOI18N
308                                dest = InstanceManager.getDefault(SignalMastManager.class).getSignalMast(destItem);
309                                break;
310                            case "sensor": // NOI18N
311                                dest = InstanceManager.getDefault(SensorManager.class).getSensor(destItem);
312                                break;
313                            case "signalHead": // NOI18N
314                                dest = InstanceManager.getDefault(SignalHeadManager.class).getSignalHead(destItem);
315                                break;
316                            default:
317                                break;
318                        }
319                        try {
320                            eep.addNXDestination(source, dest, panel, id);
321                        } catch (java.lang.NullPointerException e) {
322                            log.error("An error occurred while trying to add a point");  // NOI18N
323                        }
324                        if ((destinationList.get(j).getAttribute("uniDirection") != null) && (destinationList.get(j).getAttribute("uniDirection").getValue().equals("no"))) {  // NOI18N
325                            eep.setUniDirection(source, panel, dest, false);
326                        }
327                        if ((destinationList.get(j).getAttribute("enabled") != null) && (destinationList.get(j).getAttribute("enabled").getValue().equals("no"))) {  // NOI18N
328                            eep.setEnabled(source, panel, dest, false);
329                        }
330                        if (destinationList.get(j).getAttribute("nxType") != null) {  // NOI18N
331                            String nxType = destinationList.get(j).getAttribute("nxType").getValue();  // NOI18N
332                            switch (nxType) {
333                                case "turnoutsetting": // NOI18N
334                                    eep.setEntryExitType(source, panel, dest, 0x00);
335                                    break;
336                                case "signalmastlogic": // NOI18N
337                                    eep.setEntryExitType(source, panel, dest, 0x01);
338                                    break;
339                                case "fullinterlocking": // NOI18N
340                                    eep.setEntryExitType(source, panel, dest, 0x02);
341                                    break;
342                                default:
343                                    break;
344                            }
345
346                        }
347                    }
348                }
349            } else {
350                log.error("Panel has not been loaded");  // NOI18N
351            }
352        }
353        return true;
354    }
355
356    @Override
357    public int loadOrder() {
358        return InstanceManager.getDefault(EntryExitPairs.class).getXMLOrder();
359    }
360
361    private final static Logger log = LoggerFactory.getLogger(EntryExitPairsXml.class);
362}