001package jmri.managers.configurexml;
002
003import java.awt.GraphicsEnvironment;
004
005import java.util.List;
006import java.util.SortedSet;
007
008import jmri.ConfigureManager;
009import jmri.InstanceManager;
010import jmri.Logix;
011import jmri.LogixManager;
012import jmri.managers.DefaultLogixManager;
013import jmri.util.swing.JmriJOptionPane;
014
015import org.jdom2.Element;
016
017/**
018 * Provides the functionality for configuring LogixManagers.
019 *
020 * @author Dave Duchamp Copyright (c) 2007
021 */
022public class DefaultLogixManagerXml extends jmri.managers.configurexml.AbstractNamedBeanManagerConfigXML {
023
024    public DefaultLogixManagerXml() {
025    }
026
027    /**
028     * Default implementation for storing the contents of a LogixManager.
029     *
030     * @param o Object to store, of type LogixManager
031     * @return Element containing the complete info
032     */
033    @Override
034    public Element store(Object o) {
035        Element logixs = new Element("logixs");
036        setStoreElementClass(logixs);
037        LogixManager lxm = (LogixManager) o;
038        if (lxm != null) {
039            SortedSet<Logix> logixList = lxm.getNamedBeanSet();
040            // don't return an element if there are no Logix to include
041            if (logixList.isEmpty()) {
042                return null;
043            }
044            // store the Logix
045            for (Logix x : logixList) {
046                String xName = x.getSystemName();
047                log.debug("Logix system name is {}", xName);  // NOI18N
048                boolean enabled = x.getEnabled();
049
050                Element elem = new Element("logix");  // NOI18N
051                elem.addContent(new Element("systemName").addContent(xName));  // NOI18N
052
053                // As a work-around for backward compatibility, store systemName and username as attribute.
054                // TODO Remove this in e.g. JMRI 4.11.1 and then update all the loadref comparison files
055                String uName = x.getUserName();
056                if ((uName != null) && !uName.isEmpty()) {
057                    elem.setAttribute("userName", uName);  // NOI18N
058                }
059
060                // store common part
061                storeCommon(x, elem);
062
063                if (enabled) {
064                    elem.setAttribute("enabled", "yes");  // NOI18N
065                } else {
066                    elem.setAttribute("enabled", "no");  // NOI18N
067                }
068                // save child Conditionals
069                int numConditionals = x.getNumConditionals();
070                if (numConditionals > 0) {
071                    String cSysName = "";
072                    Element cElem = null;
073                    for (int k = 0; k < numConditionals; k++) {
074                        cSysName = x.getConditionalByNumberOrder(k);
075                        cElem = new Element("logixConditional");  // NOI18N
076                        cElem.setAttribute("systemName", cSysName);  // NOI18N
077                        cElem.setAttribute("order", Integer.toString(k));  // NOI18N
078                        elem.addContent(cElem);
079                    }
080                }
081                logixs.addContent(elem);
082            }
083        }
084        return (logixs);
085    }
086
087    /**
088     * Subclass provides implementation to create the correct top element,
089     * including the type information. Default implementation is to use the
090     * local class here.
091     *
092     * @param logixs The top-level element being created
093     */
094    public void setStoreElementClass(Element logixs) {
095        logixs.setAttribute("class", this.getClass().getName());  // NOI18N
096    }
097
098    @Override
099    public void load(Element element, Object o) {
100        log.error("Invalid method called");  // NOI18N
101    }
102
103    /**
104     * Create a LogixManager object of the correct class, then register and fill
105     * it.
106     *
107     * @param sharedLogix  Shared top level Element to unpack.
108     * @param perNodeLogix Per-node top level Element to unpack.
109     * @return true if successful
110     */
111    @Override
112    public boolean load(Element sharedLogix, Element perNodeLogix) {
113        // create the master object
114        replaceLogixManager();
115        // load individual sharedLogix
116        loadLogixs(sharedLogix);
117        return true;
118    }
119
120    /**
121     * Utility method to load the individual Logix objects. If there's no
122     * additional info needed for a specific logix type, invoke this with the
123     * parent of the set of Logix elements.
124     *
125     * @param logixs Element containing the Logix elements to load.
126     */
127    public void loadLogixs(Element logixs) {
128        List<Element> logixList = logixs.getChildren("logix");  // NOI18N
129        log.debug("Found {} Logixs", logixList.size());  // NOI18N
130        LogixManager lxm = InstanceManager.getDefault(jmri.LogixManager.class);
131
132        String systemNamePrefix = lxm.getSystemNamePrefix();
133        int namesChanged = 0;
134
135        for (Element elem : logixList) {
136            String sysName = getSystemName(elem);
137            if (sysName == null) {
138                log.warn("unexpected null in systemName {}", elem);  // NOI18N
139                break;
140            }
141
142            if (!sysName.startsWith(systemNamePrefix)) {
143                String old = sysName;
144                sysName = systemNamePrefix + ":" + sysName;
145                log.warn("Converting Logix system name from {} to {}", old, sysName);
146                namesChanged++;
147            }
148
149            String userName = getUserName(elem);
150            log.debug("create logix: ({})({})", sysName,  // NOI18N
151                    (userName == null ? "<null>" : userName));  // NOI18N
152
153            String yesno = "";
154            if (elem.getAttribute("enabled") != null) {  // NOI18N
155                yesno = elem.getAttribute("enabled").getValue();  // NOI18N
156            }
157
158            Logix x = lxm.createNewLogix(sysName, userName);
159            if (x != null) {
160                // load common part
161                loadCommon(x, elem);
162
163                // set enabled/disabled if attribute was present
164                if ((yesno != null) && (!yesno.equals(""))) {
165                    if (yesno.equals("yes")) {  // NOI18N
166                        x.setEnabled(true);
167                    } else if (yesno.equals("no")) {  // NOI18N
168                        x.setEnabled(false);
169                    }
170                }
171                // load conditionals, if there are any
172                List<Element> logixConditionalList = elem.getChildren("logixConditional");  // NOI18N
173                // add conditionals
174                for (Element lxcond : logixConditionalList) {
175                    String cSysName = getAttributeString(lxcond, "systemName");
176                    if (cSysName == null) {
177                        log.warn("unexpected null in systemName {} {}", // NOI18N
178                                lxcond, lxcond.getAttributes());
179                        break;
180                    }
181
182                    // Fix conditional name if necessary
183                    if (!cSysName.startsWith(systemNamePrefix)) {
184                        cSysName = systemNamePrefix + ":" + cSysName;
185                    }
186
187                    int cOrder = Integer.parseInt(lxcond
188                            .getAttribute("order").getValue()); // NOI18N
189                    // add the conditional to logix
190                    x.addConditional(cSysName, cOrder);
191                }
192            }
193        }
194
195        if (namesChanged > 0) {
196            // TODO: replace the System property check with an in-application mechanism
197            // for notifying users of multiple changes that can be silenced as part of
198            // normal operations
199            if (!GraphicsEnvironment.isHeadless() && !Boolean.getBoolean("jmri.test.no-dialogs")) {
200                JmriJOptionPane.showMessageDialog(null,
201                        Bundle.getMessage(namesChanged > 1 ? "LogixManager.SystemNamesChanged.Message" : "LogixManager.SystemNameChanged.Message", namesChanged),
202                        Bundle.getMessage("Manager.SystemNamesChanged.Title", namesChanged, lxm.getBeanTypeHandled(namesChanged > 1)),
203                        JmriJOptionPane.WARNING_MESSAGE);
204            }
205        log.warn("System names for {} Logixs changed; this may have operational impacts.", namesChanged);
206        }
207    }
208
209    /**
210     * Replace the current LogixManager, if there is one, with one newly created
211     * during a load operation. This is skipped if they are of the same absolute
212     * type.
213     */
214    protected void replaceLogixManager() {
215        if (InstanceManager.getDefault(jmri.LogixManager.class).getClass().getName()
216                .equals(DefaultLogixManager.class.getName())) {
217            return;
218        }
219        // if old manager exists, remove it from configuration process
220        if (InstanceManager.getNullableDefault(jmri.LogixManager.class) != null) {
221            ConfigureManager cmOD = InstanceManager.getNullableDefault(jmri.ConfigureManager.class);
222            if (cmOD != null) {
223                cmOD.deregister(InstanceManager.getDefault(jmri.LogixManager.class));
224            }
225        }
226
227        // register new one with InstanceManager
228        DefaultLogixManager pManager = InstanceManager.getDefault(DefaultLogixManager.class);
229        InstanceManager.store(pManager, LogixManager.class);
230        // register new one for configuration
231        ConfigureManager cmOD = InstanceManager.getNullableDefault(jmri.ConfigureManager.class);
232        if (cmOD != null) {
233            cmOD.registerConfig(pManager, jmri.Manager.LOGIXS);
234        }
235    }
236
237    @Override
238    public int loadOrder() {
239        return InstanceManager.getDefault(jmri.LogixManager.class).getXMLOrder();
240    }
241
242    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultLogixManagerXml.class);
243
244}