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