/**
         * Removes the given remote XBee device from the network.
         *
         * <p>Notice that this operation does not remove the remote XBee device
         * from the actual XBee network; it just tells the network object that it
         * will no longer contain that device. However, next time a discovery is
         * performed, it could be added again automatically.</p>
         *
         * <p>This method will check for a device that matches the 64-bit address
         * of the provided one, if found, that device will be removed from the
         * corresponding list. In case the 64-bit address is not defined, it will
         * use the 16-bit address for DigiMesh and ZigBee devices.</p>
         *
         * @param remoteDevice The remote device to be removed from the network.
         *
         * @throws ArgumentNullException if {@code RemoteDevice == null}.
         *
         * @see #addRemoteDevice(RemoteXBeeDevice)
         * @see #clearDeviceList()
         * @see RemoteXBeeDevice
         */
        public void removeRemoteDevice(RemoteXBeeDevice remoteDevice)
        {
            if (remoteDevice == null)
            {
                throw new ArgumentNullException("Remote device cannot be null.");
            }

            RemoteXBeeDevice devInNetwork = null;

            // Look in the 64-bit map.
            XBee64BitAddress addr64 = remoteDevice.Get64BitAddress();

            if (addr64 != null && !addr64.Equals(XBee64BitAddress.UNKNOWN_ADDRESS))
            {
                if (remotesBy64BitAddr.TryRemove(addr64, out devInNetwork))
                {
                    return;
                }
            }

            // If not found, look in the 16-bit map.
            XBee16BitAddress addr16 = Get16BitAddress(remoteDevice);

            if (addr16 != null && !addr16.Equals(XBee16BitAddress.UNKNOWN_ADDRESS))
            {
                // The preference order is:
                //    1.- Look in the 64-bit map
                //    2.- Then in the 16-bit map.
                // This should be maintained in the 'getDeviceBy16BitAddress' method.

                // Look for the 16-bit address in the 64-bit map.
                ICollection <RemoteXBeeDevice> devices = remotesBy64BitAddr.Values;
                foreach (RemoteXBeeDevice d in devices)
                {
                    XBee16BitAddress a = Get16BitAddress(d);
                    if (a != null && a.Equals(addr16))
                    {
                        RemoteXBeeDevice r;
                        remotesBy64BitAddr.TryRemove(d.Get64BitAddress(), out r);
                        return;
                    }
                }

                // If not found, look for the 16-bit address in the 16-bit map.
                // Remove the device.
                if (remotesBy16BitAddr.TryRemove(addr16, out devInNetwork))
                {
                    return;
                }
            }

            // If the device does not contain a valid address log an error.
            if ((addr64 == null || addr64.Equals(XBee64BitAddress.UNKNOWN_ADDRESS)) &&
                (addr16 == null || addr16.Equals(XBee16BitAddress.UNKNOWN_ADDRESS)))
            {
                logger.ErrorFormat("{0}Remote device '{1}' cannot be removed: 64-bit and 16-bit addresses must be specified.",
                                   localDevice.ToString(), remoteDevice.ToString());
            }
        }
        /**
         * Removes the given remote XBee device from the network.
         *
         * <p>Notice that this operation does not remove the remote XBee device
         * from the actual XBee network; it just tells the network object that it
         * will no longer contain that device. However, next time a discovery is
         * performed, it could be added again automatically.</p>
         *
         * <p>This method will check for a device that matches the 64-bit address
         * of the provided one, if found, that device will be removed from the
         * corresponding list. In case the 64-bit address is not defined, it will
         * use the 16-bit address for DigiMesh and ZigBee devices.</p>
         *
         * @param remoteDevice The remote device to be removed from the network.
         *
         * @throws ArgumentNullException if {@code RemoteDevice == null}.
         *
         * @see #addRemoteDevice(RemoteXBeeDevice)
         * @see #clearDeviceList()
         * @see RemoteXBeeDevice
         */
        public void removeRemoteDevice(RemoteXBeeDevice remoteDevice)
        {
            if (remoteDevice == null)
                throw new ArgumentNullException("Remote device cannot be null.");

            RemoteXBeeDevice devInNetwork = null;

            // Look in the 64-bit map.
            XBee64BitAddress addr64 = remoteDevice.Get64BitAddress();
            if (addr64 != null && !addr64.Equals(XBee64BitAddress.UNKNOWN_ADDRESS))
            {
                if (remotesBy64BitAddr.TryRemove(addr64, out devInNetwork))
                    return;
            }

            // If not found, look in the 16-bit map.
            XBee16BitAddress addr16 = Get16BitAddress(remoteDevice);
            if (addr16 != null && !addr16.Equals(XBee16BitAddress.UNKNOWN_ADDRESS))
            {

                // The preference order is:
                //    1.- Look in the 64-bit map
                //    2.- Then in the 16-bit map.
                // This should be maintained in the 'getDeviceBy16BitAddress' method.

                // Look for the 16-bit address in the 64-bit map.
                ICollection<RemoteXBeeDevice> devices = remotesBy64BitAddr.Values;
                foreach (RemoteXBeeDevice d in devices)
                {
                    XBee16BitAddress a = Get16BitAddress(d);
                    if (a != null && a.Equals(addr16))
                    {
                        RemoteXBeeDevice r;
                        remotesBy64BitAddr.TryRemove(d.Get64BitAddress(), out r);
                        return;
                    }
                }

                // If not found, look for the 16-bit address in the 16-bit map.
                // Remove the device.
                if (remotesBy16BitAddr.TryRemove(addr16, out devInNetwork))
                    return;
            }

            // If the device does not contain a valid address log an error.
            if ((addr64 == null || addr64.Equals(XBee64BitAddress.UNKNOWN_ADDRESS))
                    && (addr16 == null || addr16.Equals(XBee16BitAddress.UNKNOWN_ADDRESS)))
                logger.ErrorFormat("{0}Remote device '{1}' cannot be removed: 64-bit and 16-bit addresses must be specified.",
                        localDevice.ToString(), remoteDevice.ToString());
        }
        /**
         * Adds the given remote device to the network.
         *
         * <p>Notice that this operation does not join the remote XBee device to the
         * network; it just tells the network that it contains that device. However,
         * the device has only been added to the device list, and may not be
         * physically in the same network.</p>
         *
         * <p>The way of adding a device to the network is based on the 64-bit
         * address. If it is not configured:</p>
         *
         * <ul>
         * <li>For 802.15.4 and ZigBee devices, it will use the 16-bit address.</li>
         * <li>For the rest will return {@code false} as the result of the addition.</li>
         * </ul>
         *
         * @param remoteDevice The remote device to be added to the network.
         *
         * @return The remote XBee Device instance in the network, {@code null} if
         *         the device could not be successfully added.
         *
         * @throws ArgumentNullException if {@code RemoteDevice == null}.
         *
         * @see #addRemoteDevices(List)
         * @see #removeRemoteDevice(RemoteXBeeDevice)
         * @see RemoteXBeeDevice
         */
        public RemoteXBeeDevice addRemoteDevice(RemoteXBeeDevice remoteDevice)
        {
            if (remoteDevice == null)
            {
                throw new ArgumentNullException("Remote device cannot be null.");
            }

            logger.DebugFormat("{0}Adding device '{1}' to network.", localDevice.ToString(), remoteDevice.ToString());

            RemoteXBeeDevice devInNetwork = null;
            XBee64BitAddress addr64       = remoteDevice.Get64BitAddress();
            XBee16BitAddress addr16       = Get16BitAddress(remoteDevice);

            // Check if the device has 64-bit address.
            if (addr64 != null && !addr64.Equals(XBee64BitAddress.UNKNOWN_ADDRESS))
            {
                // The device has 64-bit address, so look in the 64-bit map.
                if (remotesBy64BitAddr.TryGetValue(addr64, out devInNetwork))
                {
                    // The device exists in the 64-bit map, so update the reference and return it.
                    logger.DebugFormat("{0}Existing device '{1}' in network.", localDevice.ToString(), devInNetwork.ToString());
                    devInNetwork.UpdateDeviceDataFrom(remoteDevice);
                    return(devInNetwork);
                }
                else
                {
                    // The device does not exist in the 64-bit map, so check its 16-bit address.
                    if (addr16 != null && !addr16.Equals(XBee16BitAddress.UNKNOWN_ADDRESS))
                    {
                        // The device has 16-bit address, so look in the 16-bit map.
                        if (remotesBy16BitAddr.TryGetValue(addr16, out devInNetwork))
                        {
                            // The device exists in the 16-bit map, so remove it and add it to the 64-bit map.
                            logger.DebugFormat("{0}Existing device '{1}' in network.", localDevice.ToString(), devInNetwork.ToString());
                            remotesBy16BitAddr.TryRemove(addr16, out devInNetwork);
                            devInNetwork.UpdateDeviceDataFrom(remoteDevice);
                            remotesBy64BitAddr.AddOrUpdate(addr64, devInNetwork, (k, v) => devInNetwork);
                            return(devInNetwork);
                        }
                        else
                        {
                            // The device does not exist in the 16-bit map, so add it to the 64-bit map.
                            remotesBy64BitAddr.AddOrUpdate(addr64, remoteDevice, (k, v) => remoteDevice);
                            return(remoteDevice);
                        }
                    }
                    else
                    {
                        // The device has not 16-bit address, so add it to the 64-bit map.
                        remotesBy64BitAddr.AddOrUpdate(addr64, remoteDevice, (k, v) => remoteDevice);
                        return(remoteDevice);
                    }
                }
            }

            // If the device has not 64-bit address, check if it has 16-bit address.
            if (addr16 != null && !addr16.Equals(XBee16BitAddress.UNKNOWN_ADDRESS))
            {
                // The device has 16-bit address, so look in the 64-bit map.
                ICollection <RemoteXBeeDevice> devices = remotesBy64BitAddr.Values;
                foreach (RemoteXBeeDevice d in devices)
                {
                    XBee16BitAddress a = Get16BitAddress(d);
                    if (a != null && a.Equals(addr16))
                    {
                        devInNetwork = d;
                        break;
                    }
                }
                // Check if the device exists in the 64-bit map.
                if (devInNetwork != null)
                {
                    // The device exists in the 64-bit map, so update the reference and return it.
                    logger.DebugFormat("{0}Existing device '{1}' in network.", localDevice.ToString(), devInNetwork.ToString());
                    devInNetwork.UpdateDeviceDataFrom(remoteDevice);
                    return(devInNetwork);
                }
                else
                {
                    // The device does not exist in the 64-bit map, so look in the 16-bit map.
                    devInNetwork = remotesBy16BitAddr[addr16];
                    if (devInNetwork != null)
                    {
                        // The device exists in the 16-bit map, so update the reference and return it.
                        logger.DebugFormat("{0}Existing device '{1}' in network.", localDevice.ToString(), devInNetwork.ToString());
                        devInNetwork.UpdateDeviceDataFrom(remoteDevice);
                        return(devInNetwork);
                    }
                    else
                    {
                        // The device does not exist in the 16-bit map, so add it.
                        remotesBy16BitAddr.AddOrUpdate(addr16, remoteDevice, (k, v) => remoteDevice);
                        return(remoteDevice);
                    }
                }
            }

            // If the device does not contain a valid address, return null.
            logger.ErrorFormat("{0}Remote device '{1}' cannot be added: 64-bit and 16-bit addresses must be specified.",
                               localDevice.ToString(), remoteDevice.ToString());
            return(null);
        }
        /**
         * Adds the given remote device to the network.
         *
         * <p>Notice that this operation does not join the remote XBee device to the
         * network; it just tells the network that it contains that device. However,
         * the device has only been added to the device list, and may not be
         * physically in the same network.</p>
         *
         * <p>The way of adding a device to the network is based on the 64-bit
         * address. If it is not configured:</p>
         *
         * <ul>
         * <li>For 802.15.4 and ZigBee devices, it will use the 16-bit address.</li>
         * <li>For the rest will return {@code false} as the result of the addition.</li>
         * </ul>
         *
         * @param remoteDevice The remote device to be added to the network.
         *
         * @return The remote XBee Device instance in the network, {@code null} if
         *         the device could not be successfully added.
         *
         * @throws ArgumentNullException if {@code RemoteDevice == null}.
         *
         * @see #addRemoteDevices(List)
         * @see #removeRemoteDevice(RemoteXBeeDevice)
         * @see RemoteXBeeDevice
         */
        public RemoteXBeeDevice addRemoteDevice(RemoteXBeeDevice remoteDevice)
        {
            if (remoteDevice == null)
                throw new ArgumentNullException("Remote device cannot be null.");

            logger.DebugFormat("{0}Adding device '{1}' to network.", localDevice.ToString(), remoteDevice.ToString());

            RemoteXBeeDevice devInNetwork = null;
            XBee64BitAddress addr64 = remoteDevice.Get64BitAddress();
            XBee16BitAddress addr16 = Get16BitAddress(remoteDevice);

            // Check if the device has 64-bit address.
            if (addr64 != null && !addr64.Equals(XBee64BitAddress.UNKNOWN_ADDRESS))
            {
                // The device has 64-bit address, so look in the 64-bit map.
                if (remotesBy64BitAddr.TryGetValue(addr64, out devInNetwork))
                {
                    // The device exists in the 64-bit map, so update the reference and return it.
                    logger.DebugFormat("{0}Existing device '{1}' in network.", localDevice.ToString(), devInNetwork.ToString());
                    devInNetwork.UpdateDeviceDataFrom(remoteDevice);
                    return devInNetwork;
                }
                else
                {
                    // The device does not exist in the 64-bit map, so check its 16-bit address.
                    if (addr16 != null && !addr16.Equals(XBee16BitAddress.UNKNOWN_ADDRESS))
                    {
                        // The device has 16-bit address, so look in the 16-bit map.
                        if (remotesBy16BitAddr.TryGetValue(addr16, out devInNetwork))
                        {
                            // The device exists in the 16-bit map, so remove it and add it to the 64-bit map.
                            logger.DebugFormat("{0}Existing device '{1}' in network.", localDevice.ToString(), devInNetwork.ToString());
                            remotesBy16BitAddr.TryRemove(addr16, out devInNetwork);
                            devInNetwork.UpdateDeviceDataFrom(remoteDevice);
                            remotesBy64BitAddr.AddOrUpdate(addr64, devInNetwork, (k, v) => devInNetwork);
                            return devInNetwork;
                        }
                        else
                        {
                            // The device does not exist in the 16-bit map, so add it to the 64-bit map.
                            remotesBy64BitAddr.AddOrUpdate(addr64, remoteDevice, (k, v) => remoteDevice);
                            return remoteDevice;
                        }
                    }
                    else
                    {
                        // The device has not 16-bit address, so add it to the 64-bit map.
                        remotesBy64BitAddr.AddOrUpdate(addr64, remoteDevice, (k, v) => remoteDevice);
                        return remoteDevice;
                    }
                }
            }

            // If the device has not 64-bit address, check if it has 16-bit address.
            if (addr16 != null && !addr16.Equals(XBee16BitAddress.UNKNOWN_ADDRESS))
            {
                // The device has 16-bit address, so look in the 64-bit map.
                ICollection<RemoteXBeeDevice> devices = remotesBy64BitAddr.Values;
                foreach (RemoteXBeeDevice d in devices)
                {
                    XBee16BitAddress a = Get16BitAddress(d);
                    if (a != null && a.Equals(addr16))
                    {
                        devInNetwork = d;
                        break;
                    }
                }
                // Check if the device exists in the 64-bit map.
                if (devInNetwork != null)
                {
                    // The device exists in the 64-bit map, so update the reference and return it.
                    logger.DebugFormat("{0}Existing device '{1}' in network.", localDevice.ToString(), devInNetwork.ToString());
                    devInNetwork.UpdateDeviceDataFrom(remoteDevice);
                    return devInNetwork;
                }
                else
                {
                    // The device does not exist in the 64-bit map, so look in the 16-bit map.
                    devInNetwork = remotesBy16BitAddr[addr16];
                    if (devInNetwork != null)
                    {
                        // The device exists in the 16-bit map, so update the reference and return it.
                        logger.DebugFormat("{0}Existing device '{1}' in network.", localDevice.ToString(), devInNetwork.ToString());
                        devInNetwork.UpdateDeviceDataFrom(remoteDevice);
                        return devInNetwork;
                    }
                    else
                    {
                        // The device does not exist in the 16-bit map, so add it.
                        remotesBy16BitAddr.AddOrUpdate(addr16, remoteDevice, (k, v) => remoteDevice);
                        return remoteDevice;
                    }
                }
            }

            // If the device does not contain a valid address, return null.
            logger.ErrorFormat("{0}Remote device '{1}' cannot be added: 64-bit and 16-bit addresses must be specified.",
                    localDevice.ToString(), remoteDevice.ToString());
            return null;
        }