/// <summary>
        /// Detach an event listener
        /// </summary>
        /// <param name="address">the address of the container</param>
        /// <param name="event">the event to remove</param>
        public void Detach(string address, OscMessageEvent @event)
        {
            if (@event == null)
            {
                throw new ArgumentNullException("event");
            }

            if (OscAddress.IsValidAddressLiteral(address) == true)
            {
                OscLiteralEvent container;

                lock (m_Lock)
                {
                    if (m_LiteralAddresses.TryGetValue(address, out container) == false)
                    {
                        // no container was found so abort
                        return;
                    }
                }
                // unregiser the event
                container.Event -= @event;

                // if the container is now empty remove it from the lookup
                if (container.IsNull == true)
                {
                    m_LiteralAddresses.Remove(container.Address);
                }
            }
            else if (OscAddress.IsValidAddressPattern(address) == true)
            {
                OscPatternEvent container;
                OscAddress      oscAddress = new OscAddress(address);

                lock (m_Lock)
                {
                    if (m_PatternAddresses.TryGetValue(oscAddress, out container) == false)
                    {
                        // no container was found so abort
                        return;
                    }
                }

                // unregiser the event
                container.Event -= @event;

                // if the container is now empty remove it from the lookup
                if (container.IsNull == true)
                {
                    m_PatternAddresses.Remove(container.Address);
                }
            }
            else
            {
                throw new ArgumentException(String.Format(Strings.Container_IsValidContainerAddress, address), "address");
            }
        }
        /// <summary>
        /// Attach an event listener on to the given address
        /// </summary>
        /// <param name="address">the address of the contianer</param>
        /// <param name="event">the event to attach</param>
        public void Attach(string address, OscMessageEvent @event)
        {
            if (@event == null)
            {
                throw new ArgumentNullException("event");
            }

            // if the address is a literal then add it to the literal lookup
            if (OscAddress.IsValidAddressLiteral(address) == true)
            {
                OscLiteralEvent container;

                lock (m_Lock)
                {
                    if (m_LiteralAddresses.TryGetValue(address, out container) == false)
                    {
                        // no container was found so create one
                        container = new OscLiteralEvent(address);

                        // add it to the lookup
                        m_LiteralAddresses.Add(address, container);
                    }
                }

                // attach the event
                container.Event += @event;
            }
            // if the address is a pattern add it to the pattern lookup
            else if (OscAddress.IsValidAddressPattern(address) == true)
            {
                OscPatternEvent container;
                OscAddress      oscAddress = new OscAddress(address);

                lock (m_Lock)
                {
                    if (m_PatternAddresses.TryGetValue(oscAddress, out container) == false)
                    {
                        // no container was found so create one
                        container = new OscPatternEvent(oscAddress);

                        // add it to the lookup
                        m_PatternAddresses.Add(oscAddress, container);
                    }
                }

                // attach the event
                container.Event += @event;
            }
            else
            {
                throw new ArgumentException(String.Format(Strings.Container_IsValidContainerAddress, address), "address");
            }
        }
        /// <summary>
        /// Invoke any event that matches the address on the message
        /// </summary>
        /// <param name="message">the message argument</param>
        /// <returns>true if there was a listener to invoke otherwise false</returns>
        public bool Invoke(OscMessage message)
        {
            bool       invoked    = false;
            OscAddress oscAddress = null;

            List <OscLiteralEvent> shouldInvoke        = new List <OscLiteralEvent>();
            List <OscPatternEvent> shouldInvoke_Filter = new List <OscPatternEvent>();

            do
            {
                lock (m_Lock)
                {
                    if (OscAddress.IsValidAddressLiteral(message.Address) == true)
                    {
                        OscLiteralEvent container;

                        if (m_LiteralAddresses.TryGetValue(message.Address, out container) == true)
                        {
                            //container.Invoke(message);
                            shouldInvoke.Add(container);
                            invoked = true;
                        }
                    }
                    else
                    {
                        oscAddress = new OscAddress(message.Address);

                        foreach (KeyValuePair <string, OscLiteralEvent> value in m_LiteralAddresses)
                        {
                            if (oscAddress.Match(value.Key) == true)
                            {
                                //value.Value.Invoke(message);
                                shouldInvoke.Add(value.Value);
                                invoked = true;
                            }
                        }
                    }

                    if (m_PatternAddresses.Count > 0)
                    {
                        if (oscAddress == null)
                        {
                            oscAddress = new OscAddress(message.Address);
                        }

                        foreach (KeyValuePair <OscAddress, OscPatternEvent> value in m_PatternAddresses)
                        {
                            if (oscAddress.Match(value.Key) == true)
                            {
                                //value.Value.Invoke(message);
                                shouldInvoke_Filter.Add(value.Value);
                                invoked = true;
                            }
                        }
                    }
                }
            }while (invoked == false && OnUnknownAddress(message.Address) == true);

            foreach (OscLiteralEvent @event in shouldInvoke)
            {
                @event.Invoke(message);
            }

            foreach (OscPatternEvent @event in shouldInvoke_Filter)
            {
                @event.Invoke(message);
            }

            return(invoked);
        }