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        for (int k = 0; k < editors.size(); k++) {
091            LayoutEditor panel = editors.get(k);
092            List<Object> nxpair = p.getSourceList(panel);
093
094            java.util.Collections.sort(nxpair, new Comparator<Object>(){
095                    @Override
096                    public int compare(Object o1, Object o2) { return o1.toString().compareTo(o2.toString() ); }
097                });
098            Element panelElem = new Element("layoutPanel");  // NOI18N
099            panelElem.setAttribute("name", panel.getLayoutName());  // NOI18N
100            for (int j = 0; j < nxpair.size(); j++) {
101                Object key = nxpair.get(j);
102                Element source = new Element("source");  // NOI18N
103                String type = "";
104                String item = "";
105
106                if (key instanceof SignalMast) {
107                    type = "signalMast";  // NOI18N
108                    item = ((SignalMast) key).getDisplayName();
109                } else if (key instanceof Sensor) {
110                    type = "sensor";  // NOI18N
111                    item = ((Sensor) key).getDisplayName();
112                } else if (key instanceof SignalHead) {
113                    type = "signalHead";  // NOI18N
114                    item = ((SignalHead) key).getDisplayName();
115                }
116
117                source.setAttribute("type", type);  // NOI18N
118                source.setAttribute("item", item);  // NOI18N
119
120                List<Object> a = p.getDestinationList(key, panel);
121                java.util.Collections.sort(a, new Comparator<Object>(){
122                    @Override
123                    public int compare(Object o1, Object o2) { return o1.toString().compareTo(o2.toString() ); }
124                });
125
126                for (int i = 0; i < a.size(); i++) {
127                    Object keyDest = a.get(i);
128                    String typeDest = "";
129                    String itemDest = "";
130                    if (keyDest instanceof SignalMast) {
131                        typeDest = "signalMast";  // NOI18N
132                        itemDest = ((SignalMast) keyDest).getDisplayName();
133                    } else if (keyDest instanceof Sensor) {
134                        typeDest = "sensor";  // NOI18N
135                        itemDest = ((Sensor) keyDest).getDisplayName();
136                    } else if (keyDest instanceof SignalHead) {
137                        typeDest = "signalHead";  // NOI18N
138                        itemDest = ((SignalHead) keyDest).getDisplayName();
139                    }
140                    Element dest = new Element("destination");  // NOI18N
141                    dest.setAttribute("type", typeDest);  // NOI18N
142                    dest.setAttribute("item", itemDest);  // NOI18N
143                    if (!p.isUniDirection(key, panel, keyDest)) {
144                        dest.setAttribute("uniDirection", "no");  // NOI18N
145                    }
146                    if (!p.isEnabled(key, panel, keyDest)) {
147                        dest.setAttribute("enabled", "no");  // NOI18N
148                    }
149                    int nxType = p.getEntryExitType(key, panel, keyDest);
150                    switch (nxType) {
151                        case 0x01:
152                            dest.setAttribute("nxType", "signalmastlogic");  // NOI18N
153                            break;
154                        case 0x02:
155                            dest.setAttribute("nxType", "fullinterlocking");  // NOI18N
156                            break;
157                        case 0x00:
158                        default:
159                            dest.setAttribute("nxType", "turnoutsetting");  // NOI18N
160                            break;
161                    }
162                    if (p.getUniqueId(key, panel, keyDest) != null) {
163                        dest.setAttribute("uniqueid", p.getUniqueId(key, panel, keyDest));  // NOI18N
164                    }
165                    source.addContent(dest);
166                }
167                panelElem.addContent(source);
168            }
169            element.addContent(panelElem);
170        }
171        return element;
172    }
173
174    /**
175     * Define attribute for an element that is to be stored.
176     *
177     * @param messages Storage element
178     */
179    public void setStoreElementClass(Element messages) {
180        messages.setAttribute("class", "jmri.jmrit.entryexit.configurexml.EntryExitPairsXml");  // NOI18N
181    }
182
183    /**
184     * Load, starting with the layoutBlock element, then all the value-icon
185     * pairs.
186     *
187     * @param shared  Top level Element to unpack
188     * @param perNode ignored in this application
189     * @return true if loaded without errors; false otherwise
190     */
191    @Override
192    public boolean load(Element shared, Element perNode) {
193        // create the objects
194        EntryExitPairs eep = InstanceManager.getDefault(EntryExitPairs.class);
195        String nodeText;
196
197        nodeText = shared.getChildText("cleardown");
198        if (nodeText != null) eep.setClearDownOption(Integer.parseInt(nodeText));
199
200        nodeText = shared.getChildText("overlap");
201        if (nodeText != null) eep.setOverlapOption(Integer.parseInt(nodeText));
202
203        nodeText = shared.getChildText("memorycleardelay");
204        if (nodeText != null) eep.setMemoryClearDelay(Integer.parseInt(nodeText));
205
206        nodeText = shared.getChildText("memoryname");
207        if (nodeText != null) eep.setMemoryOption(nodeText);
208
209        // get attributes
210        ConfigureManager cm = InstanceManager.getNullableDefault(jmri.ConfigureManager.class);
211        List<Object> loadedPanel;
212        if (cm != null) {
213            loadedPanel = cm.getInstanceList(LayoutEditor.class);
214        } else {
215            log.error("Failed getting optional default config manager");  // NOI18N
216            loadedPanel = new ArrayList<>();
217        }
218
219        if (shared.getChild("dispatcherintegration") != null && shared.getChild("dispatcherintegration").getText().equals("yes")) {  // NOI18N
220            eep.setDispatcherIntegration(true);
221        }
222
223        if (shared.getChild("colourwhilesetting") != null) {
224            try {
225                eep.setSettingRouteColor(ColorUtil.stringToColor(shared.getChild("colourwhilesetting").getText()));  // NOI18N
226            } catch (IllegalArgumentException e) {
227                eep.setSettingRouteColor(Color.BLACK);
228                log.error("Invalid color {}; using black", shared.getChild("colourwhilesetting").getText());
229            }
230            int settingTimer = 2000;
231            try {
232                settingTimer = Integer.parseInt(shared.getChild("settingTimer").getText());  // NOI18N
233            } catch (NumberFormatException e) {
234                log.error("Error in converting timer to int {}", shared.getChild("settingTimer"));  // NOI18N
235            }
236            eep.setSettingTimer(settingTimer);
237        }
238
239        if (shared.getChild("abssignalmode") != null && shared.getChild("abssignalmode").getText().equals("yes")) {  // NOI18N
240            eep.setAbsSignalMode(true);
241        }
242
243        List<Element> panelList = shared.getChildren("layoutPanel");  // NOI18N
244        for (int k = 0; k < panelList.size(); k++) {
245            String panelName = panelList.get(k).getAttribute("name").getValue();  // NOI18N
246            LayoutEditor panel = null;
247            for (int i = 0; i < loadedPanel.size(); i++) {
248                LayoutEditor tmp = (LayoutEditor) loadedPanel.get(i);
249                if (tmp.getLayoutName().equals(panelName)) {
250                    panel = tmp;
251                    break;
252                }
253            }
254            if (panel != null) {
255                List<Element> sourceList = panelList.get(k).getChildren("source");  // NOI18N
256                for (int i = 0; i < sourceList.size(); i++) {
257                    String sourceType = sourceList.get(i).getAttribute("type").getValue();  // NOI18N
258                    String sourceItem = sourceList.get(i).getAttribute("item").getValue();  // NOI18N
259                    NamedBean source = null;
260                    switch (sourceType) {
261                        case "signalMast": // NOI18N
262                            source = InstanceManager.getDefault(SignalMastManager.class).getSignalMast(sourceItem);
263                            break;
264                        case "sensor": // NOI18N
265                            source = InstanceManager.getDefault(SensorManager.class).getSensor(sourceItem);
266                            break;
267                        case "signalHead": // NOI18N
268                            source = InstanceManager.getDefault(SignalHeadManager.class).getSignalHead(sourceItem);
269                            break;
270                        default:
271                            break;
272                    }
273
274                    //These two could be subbed off.
275                    List<Element> destinationList = sourceList.get(i).getChildren("destination");  // NOI18N
276                    if (destinationList.size() > 0) {
277                        eep.addNXSourcePoint(source, panel);
278                    }
279                    for (int j = 0; j < destinationList.size(); j++) {
280                        String id = null;
281                        if (destinationList.get(j).getAttribute("uniqueid") != null) {  // NOI18N
282                            id = destinationList.get(j).getAttribute("uniqueid").getValue();  // NOI18N
283                            if (!id.startsWith("IN:")) {     // NOI18N
284                                id = "IN:" + id;    // NOI18N
285                            }
286                        }
287                        String destType = destinationList.get(j).getAttribute("type").getValue();  // NOI18N
288                        String destItem = destinationList.get(j).getAttribute("item").getValue();  // NOI18N
289                        NamedBean dest = null;
290                        switch (destType) {
291                            case "signalMast": // NOI18N
292                                dest = InstanceManager.getDefault(SignalMastManager.class).getSignalMast(destItem);
293                                break;
294                            case "sensor": // NOI18N
295                                dest = InstanceManager.getDefault(SensorManager.class).getSensor(destItem);
296                                break;
297                            case "signalHead": // NOI18N
298                                dest = InstanceManager.getDefault(SignalHeadManager.class).getSignalHead(destItem);
299                                break;
300                            default:
301                                break;
302                        }
303                        try {
304                            eep.addNXDestination(source, dest, panel, id);
305                        } catch (java.lang.NullPointerException e) {
306                            log.error("An error occurred while trying to add a point");  // NOI18N
307                        }
308                        if ((destinationList.get(j).getAttribute("uniDirection") != null) && (destinationList.get(j).getAttribute("uniDirection").getValue().equals("no"))) {  // NOI18N
309                            eep.setUniDirection(source, panel, dest, false);
310                        }
311                        if ((destinationList.get(j).getAttribute("enabled") != null) && (destinationList.get(j).getAttribute("enabled").getValue().equals("no"))) {  // NOI18N
312                            eep.setEnabled(source, panel, dest, false);
313                        }
314                        if (destinationList.get(j).getAttribute("nxType") != null) {  // NOI18N
315                            String nxType = destinationList.get(j).getAttribute("nxType").getValue();  // NOI18N
316                            switch (nxType) {
317                                case "turnoutsetting": // NOI18N
318                                    eep.setEntryExitType(source, panel, dest, 0x00);
319                                    break;
320                                case "signalmastlogic": // NOI18N
321                                    eep.setEntryExitType(source, panel, dest, 0x01);
322                                    break;
323                                case "fullinterlocking": // NOI18N
324                                    eep.setEntryExitType(source, panel, dest, 0x02);
325                                    break;
326                                default:
327                                    break;
328                            }
329
330                        }
331                    }
332                }
333            } else {
334                log.error("Panel has not been loaded");  // NOI18N
335            }
336        }
337        return true;
338    }
339
340    @Override
341    public int loadOrder() {
342        return InstanceManager.getDefault(EntryExitPairs.class).getXMLOrder();
343    }
344
345    private final static Logger log = LoggerFactory.getLogger(EntryExitPairsXml.class);
346}