001package jmri.jmrix.ieee802154.xbee;
002
003import java.util.Locale;
004import javax.annotation.Nonnull;
005import jmri.Light;
006import jmri.NamedBean;
007import jmri.managers.AbstractLightManager;
008import org.slf4j.Logger;
009import org.slf4j.LoggerFactory;
010
011/**
012 * Implement LightManager for XBee connections.
013 *
014 * @author Paul Bender Copyright (C) 2014
015 */
016public class XBeeLightManager extends AbstractLightManager {
017
018    protected XBeeTrafficController tc = null;
019
020    public XBeeLightManager(XBeeConnectionMemo memo) {
021        super(memo);
022        tc = (XBeeTrafficController) memo.getTrafficController();
023    }
024
025    /**
026     * {@inheritDoc}
027     */
028    @Override
029    @Nonnull
030    public XBeeConnectionMemo getMemo() {
031        return (XBeeConnectionMemo) memo;
032    }
033
034    // Multiple additions currently works partially, but not for all possible cases;
035    // for now, return 'false'.
036    @Override
037    public boolean allowMultipleAdditions(@Nonnull String systemName) {
038        return false;
039    }
040
041    @Override
042    @Nonnull
043    protected Light createNewLight(@Nonnull String systemName, String userName) throws IllegalArgumentException {
044        XBeeNode curNode;
045        String name = addressFromSystemName(systemName);
046        if ((curNode = (XBeeNode) tc.getNodeFromName(name)) == null) {
047            if ((curNode = (XBeeNode) tc.getNodeFromAddress(name)) == null) {
048                try {
049                    curNode = (XBeeNode) tc.getNodeFromAddress(Integer.parseInt(name));
050                } catch (java.lang.NumberFormatException nfe) {
051                    // if there was a number format exception, we couldn't
052                    // find the node.
053                    throw new IllegalArgumentException("failed to find node to create Light: " + systemName);
054                }
055            }
056        }
057        int pin = pinFromSystemName(systemName);
058        if (!curNode.getPinAssigned(pin)) {
059            log.debug("Adding sensor to pin {}", pin);
060            curNode.setPinBean(pin, new XBeeLight(systemName, userName, tc));
061            return (XBeeLight) curNode.getPinBean(pin);
062        } else {
063            throw new IllegalArgumentException("failed to create Light: " + systemName);
064        }
065    }
066
067    /**
068     * {@inheritDoc}
069     */
070    @Override
071    @Nonnull
072    public String validateSystemNameFormat(@Nonnull String name, @Nonnull Locale locale) {
073        super.validateSystemNameFormat(name, locale);
074        int pin = pinFromSystemName(name);
075        if (pin < 0 || pin > 7) {
076            throw new NamedBean.BadSystemNameException(
077                    Bundle.getMessage(Locale.ENGLISH, "SystemNameInvalidPin", name),
078                    Bundle.getMessage(locale, "SystemNameInvalidPin", name));
079        }
080        return name;
081    }
082    
083    /**
084     * {@inheritDoc}
085     */
086    @Override
087    public NameValidity validSystemNameFormat(@Nonnull String systemName) {
088        if (tc.getNodeFromName(addressFromSystemName(systemName)) == null
089                && tc.getNodeFromAddress(addressFromSystemName(systemName)) == null) {
090            try {
091                if (tc.getNodeFromAddress(Integer.parseInt(addressFromSystemName(systemName))) == null) {
092                    return NameValidity.INVALID;
093                } else {
094                    return (pinFromSystemName(systemName) >= 0
095                            && pinFromSystemName(systemName) <= 7) ? NameValidity.VALID : NameValidity.INVALID;
096                }
097            } catch (java.lang.NumberFormatException nfe) {
098                // if there was a number format exception, we couldn't find the node.
099                log.error("Unable to convert {} into the Xbee node and pin format of nn:xx", systemName);
100                return NameValidity.INVALID;
101            }
102
103        } else {
104            return (pinFromSystemName(systemName) >= 0
105                    && pinFromSystemName(systemName) <= 7) ? NameValidity.VALID : NameValidity.INVALID;
106        }
107    }
108
109    private String addressFromSystemName(@Nonnull String systemName) {
110        String encoderAddress;
111
112        if (systemName.contains(":")) {
113            //Address format passed is in the form of encoderAddress:input or S:light address
114            int seperator = systemName.indexOf(":");
115            encoderAddress = systemName.substring(getSystemPrefix().length() + 1, seperator);
116        } else {
117            if(systemName.length()>(getSystemPrefix().length()+1)) {
118               encoderAddress = systemName.substring(getSystemPrefix().length() + 1, systemName.length() - 1);
119            } else {
120               encoderAddress = systemName.substring(getSystemPrefix().length() + 1);
121            }
122        }
123        log.debug("Converted {} to hardware address {}", systemName, encoderAddress);
124        return encoderAddress;
125    }
126
127    private int pinFromSystemName(@Nonnull String systemName) {
128        int input = 0;
129        int iName = 0;
130
131        if (systemName.contains(":")) {
132            //Address format passed is in the form of encoderAddress:input or L:light address
133            int seperator = systemName.indexOf(":");
134            try {
135                input = Integer.parseInt(systemName.substring(seperator + 1));
136            } catch (NumberFormatException ex) {
137                log.debug("Unable to convert {} into the XBee node and pin format of nn:xx", systemName);
138                return -1;
139            }
140        } else {
141            try {
142                iName = Integer.parseInt(systemName.substring(getSystemPrefix().length() + 1));
143                input = iName % 10;
144            } catch (NumberFormatException ex) {
145                log.debug("Unable to convert {} system name to a number", systemName);
146                return -1;
147            }
148        }
149        log.debug("Converted {} to pin number {}", systemName, input);
150        return input;
151    }
152
153    /**
154     * Public method to validate system name for configuration.
155     *
156     * @return 'true' if system name has a valid meaning in current configuration, else returns
157     * 'false'. For now, this method always returns 'true'; it is needed for the
158     * Abstract Light class
159     */
160    @Override
161    public boolean validSystemNameConfig(@Nonnull String systemName) {
162        return (true);
163    }
164
165    @Override
166    public void deregister(@Nonnull jmri.Light l) {
167        super.deregister(l);
168        // remove the specified sensor from the associated XBee pin.
169        String systemName = l.getSystemName();
170        String name = addressFromSystemName(systemName);
171        int pin = pinFromSystemName(systemName);
172        XBeeNode curNode;
173        if ((curNode = (XBeeNode) tc.getNodeFromName(name)) == null) {
174            if ((curNode = (XBeeNode) tc.getNodeFromAddress(name)) == null) {
175                try {
176                    curNode = (XBeeNode) tc.getNodeFromAddress(Integer.parseInt(name));
177                } catch (java.lang.NumberFormatException nfe) {
178                    // if there was a number format exception, we couldn't
179                    // find the node.
180                    curNode = null;
181                }
182            }
183        }
184        if (curNode != null) {
185            if (curNode.removePinBean(pin, l)) {
186                log.debug("Removing sensor from pin {}", pin);
187            } else {
188                log.debug("Failed to removing sensor from pin {}", pin);
189            }
190        }
191
192    }
193
194    /**
195     * {@inheritDoc}
196     */
197    @Override
198    public String getEntryToolTip() {
199        return Bundle.getMessage("AddEntryToolTip");
200    }
201
202    private final static Logger log = LoggerFactory.getLogger(XBeeLightManager.class);
203
204}