001package jmri.jmrix.openlcb.configurexml;
002
003import org.jdom2.Element;
004import org.slf4j.Logger;
005import org.slf4j.LoggerFactory;
006
007import java.util.Map;
008
009import jmri.jmrix.PortAdapter;
010import jmri.jmrix.can.CanSystemConnectionMemo;
011import jmri.jmrix.can.ConfigurationManager;
012
013/**
014 * This class encapsulates common code for reading and writing per-connection information from/to
015 * the XML of the connection profile. It is intended to be called by all conforming Adapter
016 * implementations that are the possible choices for an OpenLCB connection.
017 * <p>
018 * (C) Balazs Racz, 2018.
019 */
020
021public class ConnectionConfigXml {
022    /**
023     * Checks if we are loading an OpenLCB protocol adapter. If no, returns without doing
024     * anything. If yes, loads the protocol settings from the XML elements.
025     *
026     * Must be called after loadOptions is done.
027     *
028     * @param shared  The &lt;connection&gt; element in the shared profile configuration.
029     * @param perNode The &lt;connection&gt; element in the per-node profile configuration.
030     * @param adapter The adapter that's in the process of initializing this connection.
031     */
032    public static void maybeLoadOlcbProfileSettings(Element shared, Element perNode, PortAdapter
033            adapter) {
034        CanSystemConnectionMemo sc = isOpenLCBProtocol(adapter);
035        if (sc == null) return;
036        loadSettingsElement(sc, shared);
037        loadSettingsElement(sc, perNode);
038    }
039
040    private static void loadSettingsElement(CanSystemConnectionMemo sc, Element xmlNode) {
041        for (Element n : xmlNode.getChildren("node")) {
042            String protocol = n.getAttributeValue("name");
043            for (Element p : n.getChildren("parameter")) {
044                String optionName = p.getAttributeValue("name");
045                String value = p.getTextTrim();
046                sc.setProtocolOption(protocol, optionName, value);
047            }
048        }
049    }
050
051    /**
052     * Checks if we are saving an OpenLCB protocol connection. If no, does nothing. If yes, saves
053     * the protocol options from the SystemConnectionMemo into the XML element.
054     * This function needs to be called from the extendElement(Element e) override in a
055     * ConnectionConfigXml of an adaptor.
056     *
057     * @param element &lt;connection&gt; XML node
058     * @param adapter Adaptor object that we are trying to save; used to access the system
059     *                connection memo.
060     */
061    public static void maybeSaveOlcbProfileSettings(Element element, PortAdapter adapter) {
062        CanSystemConnectionMemo sc = isOpenLCBProtocol(adapter);
063        if (sc == null) return;
064
065        for (String protocol : sc.getProtocolsWithOptions()) {
066            Element n = new Element("node");
067            n.setAttribute("name", protocol);
068            element.addContent(n);
069
070            Map<String, String> params = sc.getProtocolAllOptions(protocol);
071            for (Map.Entry<String, String> entry : params.entrySet()) {
072                Element p = new Element("parameter");
073                p.setAttribute("name", entry.getKey());
074                p.addContent(entry.getValue());
075                n.addContent(p);
076            }
077        }
078    }
079
080    /**
081     * Tests whether a CAN adapter is set to openLCB protocol or not.
082     *
083     * @param adapter CAN adapter 9may be serial, loopback or network).
084     * @return null for non-OpenLCB connections; for OpenLCB the connection-associated the
085     * CanSystemConnectionMemo.
086     */
087    public static CanSystemConnectionMemo isOpenLCBProtocol(PortAdapter adapter) {
088        CanSystemConnectionMemo sc = (CanSystemConnectionMemo) adapter.getSystemConnectionMemo();
089        if (sc == null) {
090            log.error("Adapter is expected to have a CanSystemConnectionMemo to be used for " +
091                    "OpenLCB protocol.");
092            return null;
093        }
094        if (!ConfigurationManager.OPENLCB.equals(adapter.getOptionState("Protocol"))) {
095            log.debug("Skipping OpenLCB protocol properties action, because protocol is not " +
096                    "OpenLCB, but {}", adapter.getOptionState("Protocol"));
097            return null;
098        }
099        return sc;
100    }
101
102    private static final Logger log = LoggerFactory.getLogger(ConnectionConfigXml.class);
103}