/// <summary>
        /// Splits messages into various lists of in and out message destined for different nodes.
        /// </summary>
        /// <param name="messages"></param>
        /// <returns></returns>
        internal NodeWithMessagesCollection DistributeMessages(IList <RelayMessage> messages)
        {
            NodeWithMessagesCollection distribution = new NodeWithMessagesCollection();
            RelayMessage message;
            Node         node;

            for (int i = 0; i < messages.Count; i++)
            {
                if (messages[i] != null)
                {
                    message = messages[i];

                    RelayMessage interZoneMessage = null;

                    SimpleLinkedList <Node> nodesForMessage          = GetNodesForMessage(message);
                    SimpleLinkedList <Node> nodesForInterZoneMessage = null;

                    if (nodesForMessage.Count > 0)
                    {
                        message.AddressHistory.Add(MyIpAddress);
                    }
                    message.RelayTTL--;

                    #region Identify InterZone Messages
                    if (message.IsTwoWayMessage == false)
                    {
                        message.ResultOutcome = RelayOutcome.Queued;                         //will be queued, if sync will not get overwritten

                        // Identify nodes in foreign zones
                        int nodeCount = nodesForMessage.Count;
                        for (int nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++)
                        {
                            nodesForMessage.Pop(out node);
                            if (_myNodeDefinition != null && _myNodeDefinition.Zone != node.NodeDefinition.Zone)
                            {
                                // Message needs to cross Zone bounderies
                                if (interZoneMessage == null)
                                {
                                    interZoneMessage         = RelayMessage.CreateInterZoneMessageFrom(message);
                                    nodesForInterZoneMessage = new SimpleLinkedList <Node>();
                                }
                                nodesForInterZoneMessage.Push(node);
                            }
                            else
                            {
                                nodesForMessage.Push(node);
                            }
                        }
                    }
                    #endregion

                    if (nodesForMessage.Count > 0)
                    {
                        DebugWriter.WriteDebugInfo(message, nodesForMessage);
                        distribution.Add(message, nodesForMessage);
                    }

                    if (nodesForInterZoneMessage != null && nodesForInterZoneMessage.Count > 0)
                    {
                        DebugWriter.WriteDebugInfo(interZoneMessage, nodesForInterZoneMessage);
                        distribution.Add(interZoneMessage, nodesForInterZoneMessage);
                    }
                }
            }

            return(distribution);
        }
        internal SimpleLinkedList <Node> GetNodesForMessage(RelayMessage message)
        {
            SimpleLinkedList <Node> nodes = null;

            if (message == null || message.RelayTTL < 1 || NodeGroups == null)
            {
                return(new SimpleLinkedList <Node>());
            }

            const bool useLegacySerialization = true;

            //commands that, from out of system, route to all groups
            if (message.IsGroupBroadcastMessage)
            {
                message.PrepareMessageToBeSent(useLegacySerialization);
                if (MyNodeGroup == null)                //out of system: all groups
                {
                    nodes = new SimpleLinkedList <Node>();
                    for (int groupIndex = 0; groupIndex < this.NodeGroups.Count; groupIndex++)
                    {
                        nodes.Push(NodeGroups[groupIndex].GetNodesForMessage(message));
                    }
                }
                else                //In system: my group
                {
                    nodes = MyNodeGroup.MyCluster.GetNodesForMessage(message);
                }
            }
            else
            {
                //Commands that always route to a single group
                NodeGroup group = GetNodeGroup(message.TypeId);
                if (group != null)
                {
                    message.PrepareMessageToBeSent(group.GroupDefinition.LegacySerialization);
                    nodes = group.GetNodesForMessage(message);
                }
                else
                {
                    message.PrepareMessageToBeSent(useLegacySerialization);
                    if (_log.IsErrorEnabled)
                    {
                        _log.ErrorFormat("No group found for {0}", message);
                    }
                    nodes = new SimpleLinkedList <Node>();
                }
            }

            if (nodes == null)
            {
                nodes = new SimpleLinkedList <Node>();
            }

            // If no nodes are returned, we predict that the caller
            // will drop the message.  Therefore we call the notification delegate.
            // This is admittedly a kludgy solution, but the only one
            // available without changing this method's signature.
            // A better solution should be adopted. [tchow 01/29/2008]
            if (nodes.Count == 0)
            {
                Forwarder.RaiseMessageDropped(message);
            }

            return(nodes);
        }