/// <summary>
        /// Update changes to the current entity compared to an input <paramref name="newdata" /> and set the entity to a proper state for updating.
        /// </summary>
        /// <param name="newdata">The "new" entity acting as the source of the changes, if any.</param>
        /// <returns>
        /// </returns>
        public void UpdateChanges(MemberCallback newdata)
        {
            int cnt = 0;

            if (IsDisconnected != newdata.IsDisconnected)
            {
                IsDisconnected           = newdata.IsDisconnected;
                IsIsDisconnectedModified = true;
                cnt++;
            }
            if (LastActiveDate != newdata.LastActiveDate)
            {
                LastActiveDate           = newdata.LastActiveDate;
                IsLastActiveDateModified = true;
                cnt++;
            }
            if (ConnectionID != newdata.ConnectionID)
            {
                ConnectionID           = newdata.ConnectionID;
                IsConnectionIDModified = true;
                cnt++;
            }
            if (SupervisorMode != newdata.SupervisorMode)
            {
                SupervisorMode           = newdata.SupervisorMode;
                IsSupervisorModeModified = true;
                cnt++;
            }
            IsEntityChanged = cnt > 0;
        }
        public static async Task<MemberCallback> OnUserConnected(string hubId, string userId, string connectId, string languages)
        {
            var mbsvc = new UserAppMemberServiceProxy();
            var cntx = Cntx;
            cntx.AcceptLanguages = languages;
            var memb = await mbsvc.LoadEntityGraphRecursAsync(cntx, AppId, userId, null, null);
            if (memb != null)
            {
                memb.StartAutoUpdating = true;
                memb.LastActivityDate = DateTime.UtcNow;
                if (languages != null)
                    memb.AcceptLanguages = languages;
                List<MemberCallback> callbacks;
                if (memb.ChangedMemberCallbacks == null)
                    callbacks = new List<MemberCallback>();
                else
                    callbacks = new List<MemberCallback>(memb.ChangedMemberCallbacks);
                var cbk = (from d in callbacks where d.HubID == hubId && d.ChannelID == "System" select d).SingleOrDefault();
                if (cbk == null)
                {
                    cbk = new MemberCallback
                    {
                        ApplicationID = AppId,
                        UserID = userId,
                        HubID = hubId,
                        ChannelID = "System",
                        ConnectionID = connectId,
                        IsDisconnected = false,
                        LastActiveDate = DateTime.UtcNow
                    };
                }
                else
                {
                    // it is very important to turn this on, otherwise the property will not be marked as modified.
                    // and the service will not save the change!
                    cbk.StartAutoUpdating = true;
                    cbk.ConnectionID = connectId;
                    cbk.IsDisconnected = false;
                    cbk.LastActiveDate = DateTime.UtcNow;
                    // other more explicit way of doing so is given in the following:
                    //cbk.ConnectionID = connectId;
                    //cbk.IsConnectionIDModified = true;
                    //cbk.IsDisconnected = false;
                    //cbk.IsIsDisconnectedModified = true;
                    //cbk.LastActiveDate = DateTime.UtcNow;
                    //cbk.IsLastActiveDateModified = true;
                }
                memb.ChangedMemberCallbacks = new MemberCallback[] { cbk };
                try
                {
                    await mbsvc.AddOrUpdateEntitiesAsync(cntx, new UserAppMemberSet(), new UserAppMember[] { memb });
                }
                catch (Exception ex)
                {

                }
                return cbk;
            }
            return null;
        }
        /// <summary>
        /// Internal use
        /// </summary>
        public MemberCallback ShallowCopy(bool allData = false, bool preserveState = false)
        {
            MemberCallback e = new MemberCallback();

            e.StartAutoUpdating = false;
            e.ChannelID         = ChannelID;
            e.HubID             = HubID;
            e.ApplicationID     = ApplicationID;
            e.UserID            = UserID;
            e.IsDisconnected    = IsDisconnected;
            if (preserveState)
            {
                e.IsIsDisconnectedModified = IsIsDisconnectedModified;
            }
            else
            {
                e.IsIsDisconnectedModified = false;
            }
            e.LastActiveDate = LastActiveDate;
            if (preserveState)
            {
                e.IsLastActiveDateModified = IsLastActiveDateModified;
            }
            else
            {
                e.IsLastActiveDateModified = false;
            }
            e.ConnectionID = ConnectionID;
            if (preserveState)
            {
                e.IsConnectionIDModified = IsConnectionIDModified;
            }
            else
            {
                e.IsConnectionIDModified = false;
            }
            e.SupervisorMode = SupervisorMode;
            if (preserveState)
            {
                e.IsSupervisorModeModified = IsSupervisorModeModified;
            }
            else
            {
                e.IsSupervisorModeModified = false;
            }
            e.DistinctString = GetDistinctString(true);
            e.IsPersisted    = IsPersisted;
            if (preserveState)
            {
                e.IsEntityChanged = IsEntityChanged;
            }
            else
            {
                e.IsEntityChanged = false;
            }
            e.StartAutoUpdating = true;
            return(e);
        }
 /// <summary>
 /// Whether or not the present entity is identitical to <paramref name="other" />, in the sense that they have the same (set of) intrinsic identifiers.
 /// </summary>
 /// <param name="other">The entity to be compared to.</param>
 /// <returns>
 ///   The result of comparison.
 /// </returns>
 public bool IsEntityTheSame(MemberCallback other)
 {
     if (other == null)
     {
         return(false);
     }
     else
     {
         return(ChannelID == other.ChannelID && HubID == other.HubID && ApplicationID == other.ApplicationID && UserID == other.UserID);
     }
 }
 /// <summary>
 /// Merge changes inside entity <paramref name="from" /> to the entity <paramref name="to" />. Any changes in <paramref name="from" /> that is not changed in <paramref name="to" /> is updated inside <paramref name="to" />.
 /// </summary>
 /// <param name="from">The "old" entity acting as merging source.</param>
 /// <param name="to">The "new" entity which inherits changes made in <paramref name="from" />.</param>
 /// <returns>
 /// </returns>
 public static void MergeChanges(MemberCallback from, MemberCallback to)
 {
     if (to.IsPersisted)
     {
         if (from.IsIsDisconnectedModified && !to.IsIsDisconnectedModified)
         {
             to.IsDisconnected           = from.IsDisconnected;
             to.IsIsDisconnectedModified = true;
         }
         if (from.IsLastActiveDateModified && !to.IsLastActiveDateModified)
         {
             to.LastActiveDate           = from.LastActiveDate;
             to.IsLastActiveDateModified = true;
         }
         if (from.IsConnectionIDModified && !to.IsConnectionIDModified)
         {
             to.ConnectionID           = from.ConnectionID;
             to.IsConnectionIDModified = true;
         }
         if (from.IsSupervisorModeModified && !to.IsSupervisorModeModified)
         {
             to.SupervisorMode           = from.SupervisorMode;
             to.IsSupervisorModeModified = true;
         }
     }
     else
     {
         to.IsPersisted              = from.IsPersisted;
         to.ChannelID                = from.ChannelID;
         to.HubID                    = from.HubID;
         to.ApplicationID            = from.ApplicationID;
         to.UserID                   = from.UserID;
         to.IsDisconnected           = from.IsDisconnected;
         to.IsIsDisconnectedModified = from.IsIsDisconnectedModified;
         to.LastActiveDate           = from.LastActiveDate;
         to.IsLastActiveDateModified = from.IsLastActiveDateModified;
         to.ConnectionID             = from.ConnectionID;
         to.IsConnectionIDModified   = from.IsConnectionIDModified;
         to.SupervisorMode           = from.SupervisorMode;
         to.IsSupervisorModeModified = from.IsSupervisorModeModified;
     }
 }
 /// <summary>
 /// Whether or not the present entity is identitical to <paramref name="other" />, in the sense that they have the same (set of) primary key(s).
 /// </summary>
 /// <param name="other">The entity to be compared to.</param>
 /// <returns>
 ///   The result of comparison.
 /// </returns>
 public bool IsEntityIdentical(MemberCallback other)
 {
     if (other == null)
     {
         return(false);
     }
     if (ChannelID != other.ChannelID)
     {
         return(false);
     }
     if (HubID != other.HubID)
     {
         return(false);
     }
     if (ApplicationID != other.ApplicationID)
     {
         return(false);
     }
     if (UserID != other.UserID)
     {
         return(false);
     }
     return(true);
 }
 /// <summary>
 /// Internal use
 /// </summary>
 public MemberCallback ShallowCopy(bool allData = false, bool preserveState = false, bool checkLoadState = false)
 {
     MemberCallback e = new MemberCallback();
     e.StartAutoUpdating = false;
     e.ChannelID = ChannelID;
     e.HubID = HubID;
     e.ApplicationID = ApplicationID;
     e.UserID = UserID;
     e.IsDisconnected = IsDisconnected;
     if (preserveState)
         e.IsIsDisconnectedModified = IsIsDisconnectedModified;
     else
         e.IsIsDisconnectedModified = false;
     e.LastActiveDate = LastActiveDate;
     if (preserveState)
         e.IsLastActiveDateModified = IsLastActiveDateModified;
     else
         e.IsLastActiveDateModified = false;
     e.ConnectionID = ConnectionID;
     if (preserveState)
         e.IsConnectionIDModified = IsConnectionIDModified;
     else
         e.IsConnectionIDModified = false;
     e.SupervisorMode = SupervisorMode;
     if (preserveState)
         e.IsSupervisorModeModified = IsSupervisorModeModified;
     else
         e.IsSupervisorModeModified = false;
     e.DistinctString = GetDistinctString(true);
     e.IsPersisted = IsPersisted;
     if (preserveState)
         e.IsEntityChanged = IsEntityChanged;
     else
         e.IsEntityChanged = false;
     e.StartAutoUpdating = true;
     return e;
 }
 /// <summary>
 /// Update changes to the current entity compared to an input <paramref name="newdata" /> and set the entity to a proper state for updating.
 /// </summary>
 /// <param name="newdata">The "new" entity acting as the source of the changes, if any.</param>
 /// <returns>
 /// </returns>
 public void UpdateChanges(MemberCallback newdata)
 {
     int cnt = 0;
     if (IsDisconnected != newdata.IsDisconnected)
     {
         IsDisconnected = newdata.IsDisconnected;
         IsIsDisconnectedModified = true;
         cnt++;
     }
     if (LastActiveDate != newdata.LastActiveDate)
     {
         LastActiveDate = newdata.LastActiveDate;
         IsLastActiveDateModified = true;
         cnt++;
     }
     if (ConnectionID != newdata.ConnectionID)
     {
         ConnectionID = newdata.ConnectionID;
         IsConnectionIDModified = true;
         cnt++;
     }
     if (SupervisorMode != newdata.SupervisorMode)
     {
         SupervisorMode = newdata.SupervisorMode;
         IsSupervisorModeModified = true;
         cnt++;
     }
     IsEntityChanged = cnt > 0;
 }
 /// <summary>
 /// Merge changes inside entity <paramref name="from" /> to the entity <paramref name="to" />. Any changes in <paramref name="from" /> that is not changed in <paramref name="to" /> is updated inside <paramref name="to" />.
 /// </summary>
 /// <param name="from">The "old" entity acting as merging source.</param>
 /// <param name="to">The "new" entity which inherits changes made in <paramref name="from" />.</param>
 /// <returns>
 /// </returns>
 public static void MergeChanges(MemberCallback from, MemberCallback to)
 {
     if (to.IsPersisted)
     {
         if (from.IsIsDisconnectedModified && !to.IsIsDisconnectedModified)
         {
             to.IsDisconnected = from.IsDisconnected;
             to.IsIsDisconnectedModified = true;
         }
         if (from.IsLastActiveDateModified && !to.IsLastActiveDateModified)
         {
             to.LastActiveDate = from.LastActiveDate;
             to.IsLastActiveDateModified = true;
         }
         if (from.IsConnectionIDModified && !to.IsConnectionIDModified)
         {
             to.ConnectionID = from.ConnectionID;
             to.IsConnectionIDModified = true;
         }
         if (from.IsSupervisorModeModified && !to.IsSupervisorModeModified)
         {
             to.SupervisorMode = from.SupervisorMode;
             to.IsSupervisorModeModified = true;
         }
     }
     else
     {
         to.IsPersisted = from.IsPersisted;
         to.ChannelID = from.ChannelID;
         to.HubID = from.HubID;
         to.ApplicationID = from.ApplicationID;
         to.UserID = from.UserID;
         to.IsDisconnected = from.IsDisconnected;
         to.IsIsDisconnectedModified = from.IsIsDisconnectedModified;
         to.LastActiveDate = from.LastActiveDate;
         to.IsLastActiveDateModified = from.IsLastActiveDateModified;
         to.ConnectionID = from.ConnectionID;
         to.IsConnectionIDModified = from.IsConnectionIDModified;
         to.SupervisorMode = from.SupervisorMode;
         to.IsSupervisorModeModified = from.IsSupervisorModeModified;
     }
 }
 /// <summary>
 /// Whether or not the present entity is identitical to <paramref name="other" />, in the sense that they have the same (set of) intrinsic identifiers.
 /// </summary>
 /// <param name="other">The entity to be compared to.</param>
 /// <returns>
 ///   The result of comparison.
 /// </returns>
 public bool IsEntityTheSame(MemberCallback other)
 {
     if (other == null)
         return false;
     else
         return ChannelID == other.ChannelID &&  HubID == other.HubID &&  ApplicationID == other.ApplicationID &&  UserID == other.UserID;
 }              
 /// <summary>
 /// Whether or not the present entity is identitical to <paramref name="other" />, in the sense that they have the same (set of) primary key(s).
 /// </summary>
 /// <param name="other">The entity to be compared to.</param>
 /// <returns>
 ///   The result of comparison.
 /// </returns>
 public bool IsEntityIdentical(MemberCallback other)
 {
     if (other == null)
         return false;
     if (ChannelID != other.ChannelID)
         return false;
     if (HubID != other.HubID)
         return false;
     if (ApplicationID != other.ApplicationID)
         return false;
     if (UserID != other.UserID)
         return false;
     return true;
 }              
 public static async Task<ConnectionStatus> UserConnected(string noticeHubId, string hubId, string peerId, string userId, string connectId, string languages)
 {
     var mbsvc = new UserAppMemberServiceProxy();
     var cntx = Cntx;
     cntx.AcceptLanguages = languages;
     var memb = await mbsvc.LoadEntityGraphRecursAsync(cntx, AppId, userId, null, null);
     if (memb != null)
     {
         memb.StartAutoUpdating = true;
         memb.LastActivityDate = DateTime.UtcNow;
         memb.AcceptLanguages = languages;
         List<MemberCallback> callbacks;
         if (memb.ChangedMemberCallbacks == null)
             callbacks = new List<MemberCallback>();
         else
             callbacks = new List<MemberCallback>(memb.ChangedMemberCallbacks);
         var cbk = (from d in callbacks where d.HubID == hubId && d.ChannelID == peerId select d).SingleOrDefault();
         if (cbk == null)
         {
             cbk = new MemberCallback
             {
                 ApplicationID = AppId,
                 UserID = userId,
                 HubID = hubId,
                 ChannelID = peerId,
                 ConnectionID = connectId,
                 IsDisconnected = false,
                 LastActiveDate = DateTime.UtcNow
             };
         }
         else
         {
             // it is very important to turn this on, otherwise the property will not be marked as modified.
             // and the service will not save the change!
             cbk.StartAutoUpdating = true;
             cbk.ConnectionID = connectId;
             cbk.IsDisconnected = false;
             cbk.LastActiveDate = DateTime.UtcNow;
         }
         memb.ChangedMemberCallbacks = new MemberCallback[] { cbk };
         await mbsvc.AddOrUpdateEntitiesAsync(cntx, new UserAppMemberSet(), new UserAppMember[] { memb });
         UserServiceProxy usvc = new UserServiceProxy();
         var u = await usvc.LoadEntityByKeyAsync(cntx, userId);
         memb.UserRef = u;
         var peerMb = await mbsvc.LoadEntityByKeyAsync(cntx, AppId, peerId);
         ConnectionStatus status = new ConnectionStatus();
         status.me = cbk;
         MemberCallbackServiceProxy mbcsvc = new MemberCallbackServiceProxy();
         UserAssociationServiceProxy uasvc = new UserAssociationServiceProxy();
         var peerCb = await mbcsvc.LoadEntityByKeyAsync(cntx, userId, hubId, AppId, peerId);
         if (peerCb == null || peerCb.ConnectionID == null || peerCb.IsDisconnected)
         {
             UserAssociation utop = await uasvc.LoadEntityByKeyAsync(cntx, userId, peerId, ApplicationContext.ChatAssocTypeId);
             MemberNotificationTypeServiceProxy ntsvc = new MemberNotificationTypeServiceProxy();
             var ntype = await ntsvc.LoadEntityByKeyAsync(cntx, ApplicationContext.PrivateChatNoticeTypeId);
             var notifier = await mbcsvc.LoadEntityByKeyAsync(cntx, "System", noticeHubId, AppId, peerId);
             if (notifier != null && notifier.ConnectionID != null && !notifier.IsDisconnected)
             {
                 if (utop != null && utop.NoMessages != null && utop.NoMessages == true)
                 {
                     status.status = PeerStatus.InBlackList;
                 }
                 else if (utop != null && utop.DoNotNotify != null && utop.DoNotNotify == true)
                 {
                     status.status = PeerStatus.DoNotDisturb;
                 }
                 else if (utop != null && utop.NotifyButBlock != null && utop.NotifyButBlock == true)
                 {
                     status.peerNotifier = notifier;
                     status.status = PeerStatus.NotifyButBlock;
                 }
                 else
                 {
                     status.peerNotifier = notifier;
                     status.status = PeerStatus.Notifiable;
                 }
             }
             else
             {
                 if (utop == null || utop.NoMessages == null || utop.NoMessages == false)
                     status.status = PeerStatus.LeaveMessage;
             }
             MemberNotification n = new MemberNotification 
             {
                 ID = Guid.NewGuid().ToString(),
                 Title = string.Format(ResourceUtils.GetString("20dc5913998d0e9ed01360475e46a0f9", "{0} invites you to chat, is waiting ...", peerMb.AcceptLanguages), ""),
                 CreatedDate = DateTime.UtcNow,
                 PriorityLevel = 0,
                 ReadCount = 0,
                 ApplicationID = AppId,
                 TypeID = ApplicationContext.PrivateChatNoticeTypeId,
                 UserID = peerId
             };
             bool hasIcon = !string.IsNullOrEmpty(memb.IconMime);
             n.NoticeMsg = "{ \"peerId\": \"" + userId + "\", \"peer\": \"" + u.Username + "\", \"connectId\": \"" + connectId + "\", \"hasIcon\": " + (hasIcon ? "true" : "false") + ", \"msg\": \"" + n.Title + "\", \"isCancel\": false, ";
             if (utop != null && utop.NoMessages != null && utop.NoMessages == true)
                 n.NoticeMsg += "\"noMessages\": true, ";
             else
                 n.NoticeMsg += "\"noMessages\": false, ";
             if (utop != null && utop.DoNotNotify != null && utop.DoNotNotify == true)
                 n.NoticeMsg += "\"notDisturb\": true, ";
             else
                 n.NoticeMsg += "\"notDisturb\": false, ";
             if (utop != null && utop.NotifyButBlock != null && utop.NotifyButBlock == true)
                 n.NoticeMsg += "\"keepNotified\": true }";
             else
                 n.NoticeMsg += "\"keepNotified\": false }";
             n.IsNoticeDataLoaded = true;
             MemberNotificationServiceProxy nsvc = new MemberNotificationServiceProxy();
             var r = await nsvc.AddOrUpdateEntitiesAsync(cntx, new MemberNotificationSet(), new MemberNotification[] { n });
             status.noticeType = ntype.TypeName;
             status.noticeMsg = n.NoticeMsg;
             status.noticeRecId = r.ChangedEntities[0].UpdatedItem.ID;
         }
         else
         {
             DateTime dt = DateTime.UtcNow;
             UserAssociation utop = await uasvc.LoadEntityByKeyAsync(cntx, userId, peerId, ApplicationContext.ChatAssocTypeId);
             if (utop == null)
             {
                 utop = new UserAssociation
                 {
                     TypeID = ApplicationContext.ChatAssocTypeId,
                     FromUserID = userId,
                     ToUserID = peerId,
                     CreateDate = dt,
                     AssocCount = 1,
                     LastAssoc = dt,
                     InteractCount = 0,
                     Votes = 0
                 };
             }
             else
                 utop.AssocCount++;
             UserAssociation ptou = await uasvc.LoadEntityByKeyAsync(cntx, peerId, userId, ApplicationContext.ChatAssocTypeId);
             if (ptou == null)
             {
                 ptou = new UserAssociation
                 {
                     TypeID = ApplicationContext.ChatAssocTypeId,
                     FromUserID = peerId,
                     ToUserID = userId,
                     CreateDate = dt,
                     AssocCount = 1,
                     LastAssoc = dt,
                     InteractCount = 0,
                     Votes = 0
                 };
             }
             else
                 ptou.AssocCount++;
             await uasvc.AddOrUpdateEntitiesAsync(cntx, new UserAssociationSet(), new UserAssociation[] { utop, ptou });
             status.status = PeerStatus.Connected;
         }
         if (peerCb != null)
             peerCb.UserAppMemberRef = peerMb;
         status.peer = peerCb;
         return status;
     }
     return null;
 }
 public static string GetJsonPeer(MemberCallback peer)
 {
     bool hasIcon = false;
     if (peer.UserAppMemberRef != null)
         hasIcon = !string.IsNullOrEmpty(peer.UserAppMemberRef.IconMime);
     string json = "{ ";
     json += @"""id"": """ + peer.UserID + @""", ";
     json += @"""name"": """ + (peer.UserAppMemberRef != null ? peer.UserAppMemberRef.UserRef.Username : "") + @""", ";
     json += @"""email"": """ + (peer.UserAppMemberRef != null && peer.UserAppMemberRef.Email != null ? peer.UserAppMemberRef.Email : "") + @""", ";
     json += @"""active"": " + (peer.IsDisconnected ? "false" : "true") + @", ";
     json += @"""icon"": " + (hasIcon ? "true" : "false") + @", ";
     json += @"""lastActive"": " + getUnixJsonTime(peer.LastActiveDate) + @"";
     json += " }";
     return json;
 }