/// <summary>
        /// Process the message queue to publish
        /// </summary>
        public void PublishThread()
        {
            int            count;
            byte           qosLevel;
            MqttMsgPublish publish;

            // create event to signal that current thread is ended
            this.publishEventEnd = new AutoResetEvent(false);

            while (this.isRunning)
            {
                // wait on message queueud to publish
                this.publishQueueWaitHandle.WaitOne();

                // first check new subscribers to send retained messages ...
                lock (this.subscribersForRetained)
                {
                    count = this.subscribersForRetained.Count;

                    // publish retained messages to subscribers (new or reconnected)
                    while (count > 0)
                    {
                        count--;
                        MqttSubscription subscription = this.subscribersForRetained.Dequeue();

                        var query = from p in this.retainedMessages
                                    where (new Regex(subscription.Topic)).IsMatch(p.Key)     // check for topics based also on wildcard with regex
                                    select p.Value;

                        if (query.Count() > 0)
                        {
                            // reverse loop to allow for changes in "this.retainedMessages"
                            for (int i = query.Count() - 1; i >= 0; i--)
                            {
                                MqttMsgPublish retained = query.ElementAt(i);

                                qosLevel = (subscription.QosLevel < retained.QosLevel) ? subscription.QosLevel : retained.QosLevel;

                                // send PUBLISH message to the current subscriber
                                subscription.Client.Publish(retained.Topic, retained.Message, qosLevel, retained.Retain);
                            }
                        }
                    }
                }

                // ... then check clients to send outgoing session messages
                lock (this.clientsForSession)
                {
                    count = this.clientsForSession.Count;

                    // publish outgoing session messages to clients (reconnected)
                    while (count > 0)
                    {
                        count--;
                        string clientId = this.clientsForSession.Dequeue();

                        MqttBrokerSession session = this.sessionManager.GetSession(clientId);

                        while (session.OutgoingMessages.Count > 0)
                        {
                            MqttMsgPublish outgoingMsg = session.OutgoingMessages.Dequeue();

                            var query = from s in session.Subscriptions
                                        where (new Regex(s.Topic)).IsMatch(outgoingMsg.Topic) // check for topics based also on wildcard with regex
                                        select s;

                            MqttSubscription subscription = query.First();

                            if (subscription != null)
                            {
                                qosLevel = (subscription.QosLevel < outgoingMsg.QosLevel) ? subscription.QosLevel : outgoingMsg.QosLevel;

                                session.Client.Publish(outgoingMsg.Topic, outgoingMsg.Message, qosLevel, outgoingMsg.Retain);
                            }
                        }
                    }
                }

                // ... then pass to process publish queue
                lock (this.publishQueue)
                {
                    publish = null;

                    count = this.publishQueue.Count;
                    // publish all queued messages
                    while (count > 0)
                    {
                        count--;
                        publish = (MqttMsgPublish)this.publishQueue.Dequeue();

                        if (publish != null)
                        {
                            // get all subscriptions for a topic
                            List <MqttSubscription> subscriptions = this.subscriberManager.GetSubscriptionsByTopic(publish.Topic);

                            if ((subscriptions != null) && (subscriptions.Count > 0))
                            {
                                foreach (MqttSubscription subscription in subscriptions)
                                {
                                    qosLevel = (subscription.QosLevel < publish.QosLevel) ? subscription.QosLevel : publish.QosLevel;

                                    // send PUBLISH message to the current subscriber
                                    subscription.Client.Publish(publish.Topic, publish.Message, qosLevel, publish.Retain);
                                }
                            }

                            // get all sessions
                            List <MqttBrokerSession> sessions = this.sessionManager.GetSessions();

                            if ((sessions != null) && (sessions.Count > 0))
                            {
                                foreach (MqttBrokerSession session in sessions)
                                {
                                    var query = from s in session.Subscriptions
                                                where (new Regex(s.Topic)).IsMatch(publish.Topic)
                                                select s;

                                    MqttSubscriptionComparer comparer = new MqttSubscriptionComparer(MqttSubscriptionComparer.MqttSubscriptionComparerType.OnClientId);

                                    // consider only session active for client disconnected (not online)
                                    if (session.Client == null)
                                    {
                                        foreach (MqttSubscription subscription in query.Distinct(comparer))
                                        {
                                            qosLevel = (subscription.QosLevel < publish.QosLevel) ? subscription.QosLevel : publish.QosLevel;

                                            // save PUBLISH message for client disconnected (not online)
                                            session.OutgoingMessages.Enqueue(publish);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            // signal thread end
            this.publishEventEnd.Set();
        }
 /// <summary>
 /// Constructor
 /// </summary>
 public MqttSubscriberManager()
 {
     this.subscribers = new Dictionary <string, List <MqttSubscription> >();
     this.comparer    = new MqttSubscriptionComparer(MqttSubscriptionComparer.MqttSubscriptionComparerType.OnClientId);
 }