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                        tsElem.setAttribute("fwdstoppercent", Float.toString(ts.getFwdStopPerCent()));
090                        tsElem.setAttribute("revstoppercent", Float.toString(ts.getRevStopPerCent()));
091                        // save child TransitSectionAction entries if any
092                        ArrayList<TransitSectionAction> tsaList = ts.getTransitSectionActionList();
093                        if (!tsaList.isEmpty()) {
094                            Element tsaElem;
095                            for (TransitSectionAction tsa : tsaList) {
096                                if (tsa != null) {
097                                    tsaElem = new Element("transitsectionaction");
098                                    tsaElem.setAttribute("whencode", Integer.toString(tsa.getWhenCode()));
099                                    tsaElem.setAttribute("whatcode", Integer.toString(tsa.getWhatCode()));
100                                    tsaElem.setAttribute("whendata", Integer.toString(tsa.getDataWhen()));
101                                    tsaElem.setAttribute("whenstring", tsa.getStringWhen());
102                                    tsaElem.setAttribute("whatdata1", Integer.toString(tsa.getDataWhat1()));
103                                    tsaElem.setAttribute("whatdata2", Integer.toString(tsa.getDataWhat2()));
104                                    tsaElem.setAttribute("whatstring", tsa.getStringWhat());
105                                    tsaElem.setAttribute("whatstring2", tsa.getStringWhat2());
106                                    tsElem.addContent(tsaElem);
107                                }
108                            }
109                        }
110                        elem.addContent(tsElem);
111                    }
112                }
113                transits.addContent(elem);
114            }
115        }
116        return (transits);
117    }
118
119    /**
120     * Subclass provides implementation to create the correct top element,
121     * including the type information. Default implementation is to use the
122     * local class here.
123     *
124     * @param transits The top-level element being created
125     */
126    public void setStoreElementClass(Element transits) {
127        transits.setAttribute("class", "jmri.configurexml.TransitManagerXml");
128    }
129
130    /**
131     * Create a TransitManager object of the correct class, then register and
132     * fill it.
133     *
134     * @param sharedTransits  Top level Element to unpack.
135     * @param perNodeTransits Per-node top level Element to unpack.
136     * @return true if successful
137     */
138    @Override
139    public boolean load(Element sharedTransits, Element perNodeTransits) {
140        // load individual Transits
141        loadTransits(sharedTransits, perNodeTransits);
142        return true;
143    }
144
145    /**
146     * Utility method to load the individual Transit objects. If there's no
147     * additional info needed for a specific Transit type, invoke this with the
148     * parent of the set of Transit elements.
149     *
150     * @param sharedTransits  Element containing the Transit elements to load.
151     * @param perNodeTransits Per-node Element containing the Transit elements
152     *                        to load.
153     */
154    public void loadTransits(Element sharedTransits, Element perNodeTransits) {
155        List<Element> transitList = sharedTransits.getChildren("transit");
156        log.debug("Found {} transits", transitList.size());
157        TransitManager tm = InstanceManager.getDefault(TransitManager.class);
158        tm.setPropertyChangesSilenced("beans", true);
159
160        for (Element tst : transitList) {
161            String sysName = getSystemName(tst);
162            String userName = getUserName(tst);
163            Transit x;
164            try {
165                x = tm.createNewTransit(sysName, userName);
166            } catch (IllegalArgumentException ex) {
167                log.error("Continuing following Exception: ", ex);
168                continue; // go to next Element
169            }
170            // load common part
171            loadCommon(x, tst);
172
173            // load transitsection children
174            List<Element> transitTransitSectionList = tst.getChildren("transitsection");
175            for (Element elem : transitTransitSectionList) {
176                int seq = 0;
177                int dir = Section.UNKNOWN;
178                boolean alt = false;
179                boolean safe = false;
180                String sectionName = elem.getAttribute("sectionname").getValue();
181                if (sectionName.equals("null")) {
182                    log.warn("When loading configuration - missing Section in Transit {}", sysName);
183                }
184                try {
185                    seq = elem.getAttribute("sequence").getIntValue();
186                    dir = elem.getAttribute("direction").getIntValue();
187                } catch (DataConversionException e) {
188                    log.error("Data Conversion Exception when loading direction of entry point - ", e);
189                }
190                if (elem.getAttribute("alternate").getValue().equals("yes")) {
191                    alt = true;
192                }
193                if (elem.getAttribute("safe") != null) {
194                    if (elem.getAttribute("safe").getValue().equals("yes")) {
195                        safe = true;
196                    }
197                }
198                String stopAllocatingSensor = "";
199                if (elem.getAttribute("stopallocatingsensor") != null) {  // may not exist
200                    stopAllocatingSensor = elem.getAttribute("stopallocatingsensor").getValue();
201                    if (stopAllocatingSensor.equals("null")) {
202                        log.warn("When loading configuration - missing Section in Transit {}", sysName);
203                        stopAllocatingSensor = "";
204                    }
205                }
206                float fwdStopPerCent = 1.00f;
207                if (elem.getAttribute("fwdstoppercent") != null) {
208                    fwdStopPerCent = Float.parseFloat(elem.getAttribute("fwdstoppercent").getValue());
209                }
210                float revStopPerCent = 1.00f;
211                if (elem.getAttribute("revstoppercent") != null) {
212                    revStopPerCent = Float.parseFloat(elem.getAttribute("revstoppercent").getValue());
213                }
214
215                TransitSection ts = new TransitSection(sectionName, seq, dir, alt, safe,
216                        stopAllocatingSensor, fwdStopPerCent, revStopPerCent );
217                x.addTransitSection(ts);
218                // load transitsectionaction children, if any
219                List<Element> transitTransitSectionActionList = elem.
220                        getChildren("transitsectionaction");
221                for (Element elemx : transitTransitSectionActionList) {
222                    int tWhen = 1;
223                    int tWhat = 1;
224                    int tWhenData = 0;
225                    String tWhenString = elemx.getAttribute("whenstring").getValue();
226                    int tWhatData1 = 0;
227                    int tWhatData2 = 0;
228                    String tWhatString = elemx.getAttribute("whatstring").getValue();
229                    String tWhatString2 = "";
230                    if (elemx.getAttribute("whatstring2") != null) {
231                        tWhatString2=elemx.getAttribute("whatstring2").getValue();
232                    }
233                    try {
234                        tWhen = elemx.getAttribute("whencode").getIntValue();
235                        tWhat = elemx.getAttribute("whatcode").getIntValue();
236                        tWhenData = elemx.getAttribute("whendata").getIntValue();
237                        tWhatData1 = elemx.getAttribute("whatdata1").getIntValue();
238                        tWhatData2 = elemx.getAttribute("whatdata2").getIntValue();
239                    } catch (DataConversionException e) {
240                        log.error("Data Conversion Exception when loading transit section action - ", e);
241                    }
242                    TransitSectionAction tsa = new TransitSectionAction(tWhen, tWhat, tWhenData,
243                            tWhatData1, tWhatData2, tWhenString, tWhatString, tWhatString2);
244                    ts.addAction(tsa);
245                }
246            }
247        }
248        tm.setPropertyChangesSilenced("beans", false);
249    }
250
251    @Override
252    public int loadOrder() {
253        return InstanceManager.getDefault(TransitManager.class).getXMLOrder();
254    }
255
256    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultTransitManagerXml.class);
257
258}