001package jmri.managers.configurexml;
002
003import java.util.ArrayList;
004import java.util.List;
005import java.util.SortedSet;
006
007import jmri.InstanceManager;
008import jmri.Section;
009import jmri.Transit;
010import jmri.TransitManager;
011import jmri.TransitSection;
012import jmri.TransitSectionAction;
013
014import org.jdom2.DataConversionException;
015import org.jdom2.Element;
016import org.slf4j.Logger;
017import org.slf4j.LoggerFactory;
018
019/**
020 * Provides the functionality for configuring a TransitManager.
021 *
022 * @author Dave Duchamp Copyright (c) 2008
023 */
024public class DefaultTransitManagerXml extends jmri.managers.configurexml.AbstractNamedBeanManagerConfigXML {
025
026    public DefaultTransitManagerXml() {
027    }
028
029    /**
030     * Default implementation for storing the contents of a TransitManager.
031     *
032     * @param o Object to store, of type TransitManager
033     * @return Element containing the complete info
034     */
035    @Override
036    public Element store(Object o) {
037        Element transits = new Element("transits");
038        setStoreElementClass(transits);
039        TransitManager tm = (TransitManager) o;
040        if (tm != null) {
041            SortedSet<Transit> tstList = tm.getNamedBeanSet();
042            // don't return an element if there are no Transits to include
043            if (tstList.isEmpty()) {
044                return null;
045            }
046
047            // store the Transit
048            for (Transit transit : tstList) {
049                String tstName = transit.getSystemName();
050                log.debug("Transit system name is {}", tstName);
051
052                Element elem = new Element("transit");
053                elem.addContent(new Element("systemName").addContent(tstName));
054
055                // As a work-around for backward compatibility, store systemName and username as attribute.
056                // Remove this in e.g. JMRI 4.11.1 and then update all the loadref comparison files
057                elem.setAttribute("systemName", tstName);
058                String uName = transit.getUserName();
059                if ((uName != null) && !uName.isEmpty()) {
060                    elem.setAttribute("userName", uName);
061                }
062
063                // store common part
064                storeCommon(transit, elem);
065
066                // save child transitsection entries
067                ArrayList<TransitSection> tsList = transit.getTransitSectionList();
068                Element tsElem;
069                for (TransitSection ts : tsList) {
070                    if ((ts != null) && !ts.isTemporary()) {
071                        tsElem = new Element("transitsection");
072                        Section tSection = ts.getSection();
073                        if (tSection != null) {
074                            tsElem.setAttribute("sectionname", tSection.getSystemName());
075                        } else {
076                            tsElem.setAttribute("sectionname", "null");
077                        }
078                        tsElem.setAttribute("sequence", Integer.toString(ts.getSequenceNumber()));
079                        tsElem.setAttribute("direction", Integer.toString(ts.getDirection()));
080                        tsElem.setAttribute("alternate", "" + (ts.isAlternate() ? "yes" : "no"));
081                        tsElem.setAttribute("safe", "" + (ts.isSafe() ? "yes" : "no"));
082                        tsElem.setAttribute("stopallocatingsensor", ts.getStopAllocatingSensor());
083
084                        // save child TransitSectionAction entries if any
085                        ArrayList<TransitSectionAction> tsaList = ts.getTransitSectionActionList();
086                        if (!tsaList.isEmpty()) {
087                            Element tsaElem;
088                            for (TransitSectionAction tsa : tsaList) {
089                                if (tsa != null) {
090                                    tsaElem = new Element("transitsectionaction");
091                                    tsaElem.setAttribute("whencode", Integer.toString(tsa.getWhenCode()));
092                                    tsaElem.setAttribute("whatcode", Integer.toString(tsa.getWhatCode()));
093                                    tsaElem.setAttribute("whendata", Integer.toString(tsa.getDataWhen()));
094                                    tsaElem.setAttribute("whenstring", tsa.getStringWhen());
095                                    tsaElem.setAttribute("whatdata1", Integer.toString(tsa.getDataWhat1()));
096                                    tsaElem.setAttribute("whatdata2", Integer.toString(tsa.getDataWhat2()));
097                                    tsaElem.setAttribute("whatstring", tsa.getStringWhat());
098                                    tsElem.addContent(tsaElem);
099                                }
100                            }
101                        }
102                        elem.addContent(tsElem);
103                    }
104                }
105                transits.addContent(elem);
106            }
107        }
108        return (transits);
109    }
110
111    /**
112     * Subclass provides implementation to create the correct top element,
113     * including the type information. Default implementation is to use the
114     * local class here.
115     *
116     * @param transits The top-level element being created
117     */
118    public void setStoreElementClass(Element transits) {
119        transits.setAttribute("class", "jmri.configurexml.TransitManagerXml");
120    }
121
122    /**
123     * Create a TransitManager object of the correct class, then register and
124     * fill it.
125     *
126     * @param sharedTransits  Top level Element to unpack.
127     * @param perNodeTransits Per-node top level Element to unpack.
128     * @return true if successful
129     */
130    @Override
131    public boolean load(Element sharedTransits, Element perNodeTransits) {
132        // load individual Transits
133        loadTransits(sharedTransits, perNodeTransits);
134        return true;
135    }
136
137    /**
138     * Utility method to load the individual Transit objects. If there's no
139     * additional info needed for a specific Transit type, invoke this with the
140     * parent of the set of Transit elements.
141     *
142     * @param sharedTransits  Element containing the Transit elements to load.
143     * @param perNodeTransits Per-node Element containing the Transit elements
144     *                        to load.
145     */
146    public void loadTransits(Element sharedTransits, Element perNodeTransits) {
147        List<Element> transitList = sharedTransits.getChildren("transit");
148        log.debug("Found {} transits", transitList.size());
149        TransitManager tm = InstanceManager.getDefault(TransitManager.class);
150        tm.setPropertyChangesSilenced("beans", true);
151
152        for (Element tst : transitList) {
153            String sysName = getSystemName(tst);
154            String userName = getUserName(tst);
155            Transit x;
156            try {
157                x = tm.createNewTransit(sysName, userName);
158            } catch (IllegalArgumentException ex) {
159                log.error("Continuing following Exception: ", ex);
160                continue; // go to next Element
161            }
162            // load common part
163            loadCommon(x, tst);
164
165            // load transitsection children
166            List<Element> transitTransitSectionList = tst.getChildren("transitsection");
167            for (Element elem : transitTransitSectionList) {
168                int seq = 0;
169                int dir = Section.UNKNOWN;
170                boolean alt = false;
171                boolean safe = false;
172                String sectionName = elem.getAttribute("sectionname").getValue();
173                if (sectionName.equals("null")) {
174                    log.warn("When loading configuration - missing Section in Transit {}", sysName);
175                }
176                try {
177                    seq = elem.getAttribute("sequence").getIntValue();
178                    dir = elem.getAttribute("direction").getIntValue();
179                } catch (DataConversionException e) {
180                    log.error("Data Conversion Exception when loading direction of entry point - ", e);
181                }
182                if (elem.getAttribute("alternate").getValue().equals("yes")) {
183                    alt = true;
184                }
185                if (elem.getAttribute("safe") != null) {
186                    if (elem.getAttribute("safe").getValue().equals("yes")) {
187                        safe = true;
188                    }
189                }
190                String stopAllocatingSensor = "";
191                if (elem.getAttribute("stopallocatingsensor") != null) {  // may not exist
192                    stopAllocatingSensor = elem.getAttribute("stopallocatingsensor").getValue();
193                    if (stopAllocatingSensor.equals("null")) {
194                        log.warn("When loading configuration - missing Section in Transit {}", sysName);
195                        stopAllocatingSensor = "";
196                    }
197                }
198
199                TransitSection ts = new TransitSection(sectionName, seq, dir, alt, safe, stopAllocatingSensor );
200                x.addTransitSection(ts);
201                // load transitsectionaction children, if any
202                List<Element> transitTransitSectionActionList = elem.
203                        getChildren("transitsectionaction");
204                for (Element elemx : transitTransitSectionActionList) {
205                    int tWhen = 1;
206                    int tWhat = 1;
207                    int tWhenData = 0;
208                    String tWhenString = elemx.getAttribute("whenstring").getValue();
209                    int tWhatData1 = 0;
210                    int tWhatData2 = 0;
211                    String tWhatString = elemx.getAttribute("whatstring").getValue();
212                    try {
213                        tWhen = elemx.getAttribute("whencode").getIntValue();
214                        tWhat = elemx.getAttribute("whatcode").getIntValue();
215                        tWhenData = elemx.getAttribute("whendata").getIntValue();
216                        tWhatData1 = elemx.getAttribute("whatdata1").getIntValue();
217                        tWhatData2 = elemx.getAttribute("whatdata2").getIntValue();
218                    } catch (DataConversionException e) {
219                        log.error("Data Conversion Exception when loading transit section action - ", e);
220                    }
221                    TransitSectionAction tsa = new TransitSectionAction(tWhen, tWhat, tWhenData,
222                            tWhatData1, tWhatData2, tWhenString, tWhatString);
223                    ts.addAction(tsa);
224                }
225            }
226        }
227        tm.setPropertyChangesSilenced("beans", false);
228    }
229
230    @Override
231    public int loadOrder() {
232        return InstanceManager.getDefault(TransitManager.class).getXMLOrder();
233    }
234
235    private final static Logger log = LoggerFactory.getLogger(DefaultTransitManagerXml.class);
236
237}