Ejemplo n.º 1
0
        internal void RemoveThread(YamsterThread thread, YamsterModelEventCollector eventCollector)
        {
            int index = this.threadsInternal.BinarySearch(thread,
                                                          Comparer <YamsterThread> .Create((x, y) => Math.Sign(x.ThreadId - y.ThreadId)));
            int deletedIndex = this.deletedThreadsInternal.BinarySearch(thread,
                                                                        Comparer <YamsterThread> .Create((x, y) => Math.Sign(x.ThreadId - y.ThreadId)));

            if (index < 0 && deletedIndex < 0)
            {
                Debug.Assert(false, "RemoveThread() called on thread that doesn't belong to this group");
                return;
            }

            if (index >= 0)
            {
                this.threadsInternal.RemoveAt(index);

                if (thread.Read)
                {
                    this.NotifyThreadReadChanged(newReadValue: false, eventCollector: eventCollector);
                }
            }
            else
            {
                this.deletedThreadsInternal.RemoveAt(deletedIndex);
            }
        }
Ejemplo n.º 2
0
        internal void AddThread(YamsterThread thread, YamsterModelEventCollector eventCollector)
        {
            int index = this.threadsInternal.BinarySearch(thread,
                                                          Comparer <YamsterThread> .Create((x, y) => Math.Sign(x.ThreadId - y.ThreadId)));
            int deletedIndex = this.deletedThreadsInternal.BinarySearch(thread,
                                                                        Comparer <YamsterThread> .Create((x, y) => Math.Sign(x.ThreadId - y.ThreadId)));

            if (index >= 0 || deletedIndex >= 0)
            {
                throw new InvalidOperationException("Program Bug: The message was already added to this thread");
            }

            if (!thread.AllMessagesDeleted)
            {
                this.threadsInternal.Insert(~index, thread);

                if (thread.Read)
                {
                    this.NotifyThreadReadChanged(newReadValue: true, eventCollector: eventCollector);
                }
            }
            else
            {
                this.deletedThreadsInternal.Insert(~deletedIndex, thread);
            }
        }
Ejemplo n.º 3
0
        internal void ProcessDbMessageState(DbMessageState record)
        {
            var eventCollector = new YamsterModelEventCollector();

            ProcessDbMessageState(record, eventCollector);
            eventCollector.FireEvents();
        }
Ejemplo n.º 4
0
        internal void FixupUnresolvedObjectsForThread(YamsterThread thread, YamsterMessage latestMessage,
                                                      YamsterModelEventCollector eventCollector)
        {
            Debug.Assert(latestMessage.Thread == thread);

            DbThreadState dbThreadState;

            if (unresolvedThreadStatesById.TryGetValue(thread.ThreadId, out dbThreadState))
            {
                unresolvedThreadStatesById.Remove(thread.ThreadId);
                thread.SetDbThreadState(dbThreadState, eventCollector);
            }

            // Is this thread part of a conversation?
            long conversationId = latestMessage.DbMessage.ConversationId;

            if (conversationId != 0)
            {
                // Register the thread as the owner of this conversation
                this.threadsByConversationId[conversationId] = thread;

                // Is there an unresolved conversation object?
                DbConversation unresolvedConversation;
                if (this.unresolvedConversationsById.TryGetValue(conversationId, out unresolvedConversation))
                {
                    // Yes, so apply it now
                    this.unresolvedConversationsById.Remove(conversationId);
                    thread.UpdateConversation(unresolvedConversation, eventCollector);
                }
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        /// If the YamsterMessage with messageId already exists, this calls messageAction
        /// immediately.  Otherwise, messageAction is queued and will be called later when
        /// the message appears.  If the same listener calls ListenForMessageById() more
        /// than once, only the most recent request is kept.
        /// </summary>
        internal void ListenForMessageById(long messageId,
                                           object listener,
                                           YamsterModelEventCollector eventCollector,
                                           ListenedMessageAction messageAction)
        {
            YamsterMessage message = this.GetMessageById(messageId, nullIfMissing: true);

            if (message != null)
            {
                messageAction(message, eventCollector);
                return;
            }

            ListenedMessage listenedMessage;

            if (!listenedMessagesById.TryGetValue(messageId, out listenedMessage))
            {
                listenedMessage = new ListenedMessage()
                {
                    MessageId = messageId
                };
                listenedMessagesById.Add(messageId, listenedMessage);
            }

            listenedMessage.ActionsByListener[listener] = messageAction;
        }
Ejemplo n.º 6
0
        // TODO: This is a hack.  Need a better story for referencing objects that haven't been
        // synced yet.
        public YamsterUser GetPossiblyUnknownUserById(long userId)
        {
            var eventCollector = new YamsterModelEventCollector();
            var user           = FetchUserById(userId, eventCollector);

            eventCollector.FireEvents();
            return(user);
        }
Ejemplo n.º 7
0
        void ProcessDbGroupState(DbGroupState record)
        {
            var          eventCollector = new YamsterModelEventCollector();
            YamsterGroup group          = this.FetchGroupById(record.GroupId, eventCollector);

            group.SetDbGroupState(record, eventCollector);
            eventCollector.FireEvents();
        }
Ejemplo n.º 8
0
        void ProcessDbUser(DbUser record)
        {
            var         eventCollector = new YamsterModelEventCollector();
            YamsterUser user           = this.FetchUserById(record.UserId, eventCollector);

            user.DbUser = record;
            eventCollector.NotifyAfterUpdate(user);
            eventCollector.FireEvents();
        }
Ejemplo n.º 9
0
        void ProcessDbMessage(DbMessage record)
        {
            // Does the message exist yet?
            var message = this.GetMessageById(record.MessageId, nullIfMissing: true);

            bool messageIsNew = message == null;

            var eventCollector = new YamsterModelEventCollector();

            if (messageIsNew)
            {
                message = new YamsterMessage(record.MessageId, this);
                this.messagesById.Add(record.MessageId, message);
                eventCollector.NotifyAfterAdd(message);
                message.SetDbMessage(record, eventCollector);

                // For now we assume that messages cannot move between threads
                var           threadId = message.ThreadId;
                YamsterThread thread   = GetThreadById(threadId, nullIfMissing: true);
                if (thread == null)
                {
                    thread = new YamsterThread(threadId, message.Group, this);
                    threadsById.Add(threadId, thread);
                    eventCollector.NotifyAfterAdd(thread);
                    message.Group.AddThread(thread, eventCollector);

                    thread.AddMessage(message, eventCollector);

                    FixupUnresolvedObjectsForThread(thread, message, eventCollector);
                }
                else
                {
                    thread.AddMessage(message, eventCollector);
                }
            }
            else
            {
                message.SetDbMessage(record, eventCollector);
            }

            // Was there an unresolved message that we can process now?
            DbMessageState unresolvedMessageState;

            if (this.unresolvedMessageStatesById.TryGetValue(record.MessageId, out unresolvedMessageState))
            {
                this.unresolvedMessageStatesById.Remove(record.MessageId);
                ProcessDbMessageState(unresolvedMessageState, eventCollector);
            }

            if (messageIsNew)
            {
                CheckForListenedMessage(message, eventCollector);
            }

            eventCollector.FireEvents();
        }
Ejemplo n.º 10
0
 internal void NotifyTotalLikesChanged(int totalLikesCountDelta, YamsterModelEventCollector eventCollector)
 {
     if (totalLikesCountDelta == 0)
     {
         return;
     }
     this.totalLikesCount += totalLikesCountDelta;
     Debug.Assert(totalLikesCount == this.messagesInternal.Sum(x => x.LikesCount));
     eventCollector.NotifyAfterUpdate(this);
 }
Ejemplo n.º 11
0
        internal YamsterGroup FetchGroupById(long groupId, YamsterModelEventCollector eventCollector)
        {
            YamsterGroup group = this.GetGroupById(groupId, nullIfMissing: true);

            if (group == null)
            {
                group = new YamsterGroup(groupId, this);
                this.groupsById.Add(groupId, group);
                eventCollector.NotifyAfterAdd(group);
            }
            return(group);
        }
Ejemplo n.º 12
0
        internal YamsterUser FetchUserById(long userId, YamsterModelEventCollector eventCollector)
        {
            YamsterUser user = this.GetUserById(userId, nullIfMissing: true);

            if (user == null)
            {
                user = new YamsterUser(userId, this);
                this.usersById.Add(userId, user);
                eventCollector.NotifyAfterAdd(user);
            }
            return(user);
        }
Ejemplo n.º 13
0
 internal void NotifyMessageReadChanged(bool newReadValue, YamsterModelEventCollector eventCollector)
 {
     this.PerformActionAndCheckRead(() => {
         if (newReadValue)
         {
             ++readMessageCount;
         }
         else
         {
             --readMessageCount;
         }
     }, eventCollector);
 }
Ejemplo n.º 14
0
        internal void UpdateConversation(DbConversation conversation, YamsterModelEventCollector eventCollector)
        {
            this.ConversationId = conversation.ConversationId;

            var users = new List <YamsterUser>(conversation.ParticipantUserIds.Count);

            foreach (long userId in conversation.ParticipantUserIds)
            {
                var user = YamsterCache.FetchUserById(userId, eventCollector);
                users.Add(user);
            }
            this.participants = new YamsterUserSet(users);
            eventCollector.NotifyAfterUpdate(this);
        }
Ejemplo n.º 15
0
 internal void SetDbThreadState(DbThreadState newValue, YamsterModelEventCollector eventCollector)
 {
     if (newValue == null)
     {
         throw new ArgumentNullException("DbThreadState");
     }
     if (newValue.ThreadId != this.ThreadId)
     {
         throw new ArgumentException("Cannot change ID");
     }
     this.dbThreadState = newValue;
     UpdateLoadedStatus();
     eventCollector.NotifyAfterUpdate(this);
 }
Ejemplo n.º 16
0
        private void PerformActionAndCheckRead(Action action, YamsterModelEventCollector eventCollector)
        {
            bool oldThreadRead = this.Read;

            action();

            Debug.Assert(readMessageCount == this.messagesInternal.Where(x => x.Read).Count());

            if (this.Read != oldThreadRead && !this.AllMessagesDeleted)
            {
                this.Group.NotifyThreadReadChanged(this.Read, eventCollector);
                eventCollector.NotifyAfterUpdate(this);
            }
        }
Ejemplo n.º 17
0
        void ProcessDbMessageState(DbMessageState record, YamsterModelEventCollector eventCollector)
        {
            // Does the message exist yet?
            var message = this.GetMessageById(record.MessageId, nullIfMissing: true);

            if (message != null)
            {
                message.SetDbMessageState(record, eventCollector);
            }
            else
            {
                // Stash the message state and deal with it later
                this.unresolvedMessageStatesById[record.MessageId] = record;
            }
        }
Ejemplo n.º 18
0
        void CheckForListenedMessage(YamsterMessage message, YamsterModelEventCollector eventCollector)
        {
            ListenedMessage listenedMessage;

            if (!listenedMessagesById.TryGetValue(message.MessageId, out listenedMessage))
            {
                return;
            }
            listenedMessagesById.Remove(message.MessageId);

            foreach (var messageAction in listenedMessage.ActionsByListener.Values)
            {
                messageAction(message, eventCollector);
            }
        }
Ejemplo n.º 19
0
        internal void AddMessage(YamsterMessage message, YamsterModelEventCollector eventCollector)
        {
            // Insert sorted by MessageId
            int index = this.messagesInternal.BinarySearch(message,
                                                           Comparer <YamsterMessage> .Create((x, y) => Math.Sign(x.MessageId - y.MessageId)));
            int deletedIndex = this.deletedMessagesInternal.BinarySearch(message,
                                                                         Comparer <YamsterMessage> .Create((x, y) => Math.Sign(x.MessageId - y.MessageId)));

            if (index >= 0 || deletedIndex >= 0)
            {
                throw new InvalidOperationException("Program Bug: The message was already added to this thread");
            }

            bool oldAllMessagesDeleted = this.AllMessagesDeleted;

            if (!message.Deleted)
            {
                this.PerformActionAndCheckRead(() => {
                    this.messagesInternal.Insert(~index, message);
                }, eventCollector);

                message.NotifyAddedToThread(this);

                if (message.Read)
                {
                    // Increment the read message counter
                    this.NotifyMessageReadChanged(newReadValue: true, eventCollector: eventCollector);
                }

                NotifyTotalLikesChanged(+message.LikesCount, eventCollector);

                // Adding a message changes LastUpdate, Messages.Count, and possibly other properties
                // like TotalLikesCount
                eventCollector.NotifyAfterUpdate(this);
            }
            else
            {
                this.deletedMessagesInternal.Insert(~deletedIndex, message);
            }

            if (oldAllMessagesDeleted != this.AllMessagesDeleted)
            {
                // Remove and re-add the thread so it moves to the appropriate
                // collection (YamsterGroup.Threads or DeletedThreads)
                this.Group.RemoveThread(this, eventCollector);
                this.Group.AddThread(this, eventCollector);
            }
        }
Ejemplo n.º 20
0
        void ProcessDbThreadState(DbThreadState record)
        {
            // Does the thread exist yet?
            YamsterThread thread;

            if (threadsById.TryGetValue(record.ThreadId, out thread))
            {
                var eventCollector = new YamsterModelEventCollector();
                thread.SetDbThreadState(record, eventCollector);
                eventCollector.FireEvents();
            }
            else
            {
                // Stash the record and deal with it later
                unresolvedThreadStatesById[record.ThreadId] = record;
            }
        }
Ejemplo n.º 21
0
        void ProcessDbConversation(DbConversation record)
        {
            // Does the thread exist yet?
            YamsterThread thread;

            if (threadsByConversationId.TryGetValue(record.ConversationId, out thread))
            {
                var eventCollector = new YamsterModelEventCollector();
                thread.UpdateConversation(record, eventCollector);
                eventCollector.FireEvents();
            }
            else
            {
                // Stash the conversation and deal with it later
                unresolvedConversationsById[record.ConversationId] = record;
            }
        }
Ejemplo n.º 22
0
        internal void NotifyThreadReadChanged(bool newReadValue, YamsterModelEventCollector eventCollector)
        {
            bool oldGroupRead = this.Read;

            if (newReadValue)
            {
                ++readThreadCount;
            }
            else
            {
                --readThreadCount;
            }

            Debug.Assert(readThreadCount >= 0 && readThreadCount <= threadsInternal.Count);

            eventCollector.NotifyAfterUpdate(this);
        }
Ejemplo n.º 23
0
        internal void RemoveMessage(YamsterMessage message, YamsterModelEventCollector eventCollector)
        {
            int index = this.messagesInternal.BinarySearch(message,
                                                           Comparer <YamsterMessage> .Create((x, y) => Math.Sign(x.MessageId - y.MessageId)));
            int deletedIndex = this.deletedMessagesInternal.BinarySearch(message,
                                                                         Comparer <YamsterMessage> .Create((x, y) => Math.Sign(x.MessageId - y.MessageId)));

            if (index < 0 && deletedIndex < 0)
            {
                Debug.Assert(false, "RemoveMessage() called on message that doesn't belong to this thread");
                return;
            }

            if (index >= 0)
            {
                bool oldAllMessagesDeleted = this.AllMessagesDeleted;

                this.PerformActionAndCheckRead(() => {
                    this.messagesInternal.RemoveAt(index);
                }, eventCollector);


                if (oldAllMessagesDeleted != this.AllMessagesDeleted)
                {
                    // Remove and re-add the thread so it moves to the appropriate
                    // collection (YamsterGroup.Threads or DeletedThreads)
                    // (Note that NotifyMessageReadChanged() assumes that the thread
                    // is in the right collection.)
                    this.Group.RemoveThread(this, eventCollector);
                    this.Group.AddThread(this, eventCollector);
                }

                if (message.Read)
                {
                    // Decrement the read message counter
                    this.NotifyMessageReadChanged(newReadValue: false, eventCollector: eventCollector);
                }

                this.NotifyTotalLikesChanged(-message.LikesCount, eventCollector);
            }
            else
            {
                this.deletedMessagesInternal.RemoveAt(deletedIndex);
            }
        }
Ejemplo n.º 24
0
        internal void SetDbMessageState(DbMessageState newValue, YamsterModelEventCollector eventCollector)
        {
            if (newValue == null)
            {
                throw new ArgumentNullException("DbMessageState");
            }
            if (newValue.MessageId != messageId)
            {
                throw new ArgumentException("Cannot change ID");
            }

            bool oldRead    = this.Read;
            bool oldDeleted = this.Deleted;

            if (newValue.Deleted != oldDeleted)
            {
                // Remove and re-add the message so it moves to the appropriate
                // collection (YamsterThread.Messages or DeletedMessages).
                // (Note that NotifyMessageReadChanged() assumes that the message
                // is in the right collection.)
                this.Thread.RemoveMessage(this, eventCollector);

                this.dbMessageState = newValue;

                this.Thread.AddMessage(this, eventCollector);

                this.cachedPreviewText = null;
            }
            else
            {
                this.dbMessageState = newValue;

                if (this.Read != oldRead && !this.Deleted)
                {
                    this.Thread.NotifyMessageReadChanged(this.Read, eventCollector);
                }
            }

            UpdateLoadedStatus();

            eventCollector.NotifyAfterUpdate(this);
        }
Ejemplo n.º 25
0
        internal void SetDbMessage(DbMessage newValue, YamsterModelEventCollector eventCollector)
        {
            if (newValue == null)
            {
                throw new ArgumentNullException("DbMessage");
            }
            if (newValue.MessageId != messageId)
            {
                throw new ArgumentException("Cannot change ID");
            }

            var oldValue = this.dbMessage;

            this.dbMessage         = newValue;
            this.cachedPreviewText = null;

            this.group      = this.YamsterCache.FetchGroupById(this.dbMessage.GroupId, eventCollector);
            this.senderUser = this.YamsterCache.FetchUserById(this.dbMessage.SenderUserId, eventCollector);

            this.messageRepliedTo = null;
            if (this.dbMessage.MessageIdRepliedTo != 0
                // The Yammer UI doesn't show "in reply to" when messageRepliedTo is the threadstarter.
                // TODO: What does it do if the threadstarter's MessageId != ThreadId?
                && this.dbMessage.MessageIdRepliedTo != this.dbMessage.ThreadId)
            {
                this.YamsterCache.ListenForMessageById(
                    this.dbMessage.MessageIdRepliedTo,
                    this,
                    eventCollector,
                    delegate(YamsterMessage listenedMessage, YamsterModelEventCollector ec)
                {
                    if (listenedMessage.MessageId == this.dbMessage.MessageIdRepliedTo)
                    {
                        this.messageRepliedTo = listenedMessage;
                        ec.NotifyAfterUpdate(this);
                    }
                }
                    );
            }

            int oldlikingUsersCount = likingUsers.Count;

            likingUsers.Clear();
            foreach (long userId in this.dbMessage.LikingUserIds)
            {
                var user = this.YamsterCache.FetchUserById(userId, eventCollector);
                likingUsers.AddUser(user);
            }

            if (this.thread != null)
            {
                int totalLikesCountDelta = newValue.LikesCount - oldValue.LikesCount;
                if (totalLikesCountDelta != 0)
                {
                    this.thread.NotifyTotalLikesChanged(totalLikesCountDelta, eventCollector);
                }
            }

            notifiedUsers.Clear();
            foreach (long userId in this.dbMessage.NotifiedUserIds)
            {
                var user = this.YamsterCache.FetchUserById(userId, eventCollector);
                notifiedUsers.AddUser(user);
            }

            UpdateLoadedStatus();

            eventCollector.NotifyAfterUpdate(this);
        }