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