using System; using System.Collections.Generic; using System.Linq; namespace SharpChat { public class ChannelsUsersContext { private readonly Dictionary> ChannelUsers = new(); private readonly Dictionary> UserChannels = new(); private readonly Dictionary UserLastChannel = new(); public string GetUserLastChannel(long userId) { return UserLastChannel.ContainsKey(userId) ? UserLastChannel[userId] : string.Empty; } public string GetUserLastChannel(UserInfo userInfo) { return GetUserLastChannel(userInfo.UserId); } public void SetUserLastChannel(long userId, string channelName) { channelName = channelName.ToLowerInvariant(); if(UserLastChannel.ContainsKey(userId)) UserLastChannel[userId] = channelName; else UserLastChannel.Add(userId, channelName); } public void SetUserLastChannel(UserInfo userInfo, ChannelInfo channelInfo) { SetUserLastChannel(userInfo.UserId, channelInfo.Name); } public void DeleteUserLastChannel(long userId) { if(UserLastChannel.ContainsKey(userId)) UserLastChannel.Remove(userId); } public void DeleteUserLastChannel(UserInfo userInfo) { DeleteUserLastChannel(userInfo.UserId); } public bool IsUserLastChannel(long userId, string channelName) { return !string.IsNullOrWhiteSpace(channelName) && GetUserLastChannel(userId).Equals(channelName, StringComparison.InvariantCultureIgnoreCase); } public bool IsUserLastChannel(UserInfo userInfo, ChannelInfo channelInfo) { return IsUserLastChannel(userInfo.UserId, channelInfo.Name); } public string[] GetUserChannelNames(long userId) { if(!UserChannels.ContainsKey(userId)) return Array.Empty(); return UserChannels[userId].ToArray(); } public string[] GetUserChannelNames(UserInfo userInfo) { return GetUserChannelNames(userInfo.UserId); } public long[] GetChannelUserIds(string channelName) { channelName = channelName.ToLowerInvariant(); if(!ChannelUsers.ContainsKey(channelName)) return Array.Empty(); return ChannelUsers[channelName].ToArray(); } public long[] GetChannelUserIds(string channelName, Func sanitise) { foreach(KeyValuePair> kvp in ChannelUsers) if(sanitise(kvp.Key).Equals(channelName, StringComparison.InvariantCultureIgnoreCase)) return kvp.Value.ToArray(); return Array.Empty(); } public long[] GetChannelUserIds(ChannelInfo channelInfo) { return GetChannelUserIds(channelInfo.Name); } public void Join(string channelName, long userId) { channelName = channelName.ToLowerInvariant(); if(ChannelUsers.ContainsKey(channelName)) ChannelUsers[channelName].Add(userId); else ChannelUsers.Add(channelName, new HashSet { userId }); if(UserChannels.ContainsKey(userId)) UserChannels[userId].Add(channelName); else UserChannels.Add(userId, new HashSet { channelName }); SetUserLastChannel(userId, channelName); } public void Join(ChannelInfo channelInfo, UserInfo userInfo) { Join(channelInfo.Name, userInfo.UserId); } public void Leave(string channelName, long userId) { channelName = channelName.ToLowerInvariant(); if(ChannelUsers.ContainsKey(channelName)) { if(ChannelUsers[channelName].Count < 2) ChannelUsers.Remove(channelName); else ChannelUsers[channelName].Remove(userId); } if(UserChannels.ContainsKey(userId)) { if(UserChannels[userId].Count < 2) UserChannels.Remove(userId); else UserChannels[userId].Remove(channelName); } if(IsUserLastChannel(userId, channelName)) DeleteUserLastChannel(userId); } public void Leave(ChannelInfo channelInfo, UserInfo userInfo) { Leave(channelInfo.Name, userInfo.UserId); } public bool Has(string channelName, long userId) { channelName = channelName.ToLowerInvariant(); return ChannelUsers.ContainsKey(channelName) && ChannelUsers[channelName].Contains(userId); } public bool Has(ChannelInfo channelInfo, UserInfo userInfo) { return Has(channelInfo.Name, userInfo.UserId); } public long[] FilterUsers(string channelName, long[] userIds) { if(userIds.Length < 1) return userIds; channelName = channelName.ToLowerInvariant(); if(!ChannelUsers.ContainsKey(channelName)) return Array.Empty(); List filtered = new(); HashSet channelUserIds = ChannelUsers[channelName]; foreach(long userId in userIds) if(channelUserIds.Contains(userId)) filtered.Add(userId); return filtered.ToArray(); } public UserInfo[] FilterUsers(ChannelInfo channelInfo, UserInfo[] userInfos) { if(userInfos.Length < 1) return userInfos; long[] filteredIds = FilterUsers(channelInfo.Name, userInfos.Select(u => u.UserId).ToArray()); if(filteredIds.Length < 1) return Array.Empty(); return userInfos.Where(u => filteredIds.Contains(u.UserId)).ToArray(); } public bool HasUsers(string channelName, long[] userIds) { return FilterUsers(channelName, userIds).SequenceEqual(userIds); } public bool HasUsers(ChannelInfo channelInfo, UserInfo[] userInfos) { return HasUsers(channelInfo.Name, userInfos.Select(u => u.UserId).ToArray()); } public string[] FilterChannels(long userId, string[] channelNames) { if(channelNames.Length < 1) return channelNames; if(!UserChannels.ContainsKey(userId)) return Array.Empty(); List filtered = new(); HashSet userChannelNames = UserChannels[userId]; foreach(string channelName in userChannelNames) if(userChannelNames.Contains(channelName)) filtered.Add(channelName); return filtered.ToArray(); } public ChannelInfo[] FilterChannels(UserInfo userInfo, ChannelInfo[] channelInfos) { if(channelInfos.Length < 1) return channelInfos; string[] filteredNames = FilterChannels(userInfo.UserId, channelInfos.Select(c => c.Name).ToArray()); if(filteredNames.Length < 1) return Array.Empty(); return channelInfos.Where(c => filteredNames.Contains(c.Name.ToLowerInvariant())).ToArray(); } public bool HasChannels(long userId, string[] channelNames) { if(!UserChannels.ContainsKey(userId)) return false; HashSet userChannelNames = UserChannels[userId]; foreach(string channelName in channelNames) if(!userChannelNames.Contains(channelName.ToLowerInvariant())) return false; return true; } public bool HasChannels(UserInfo userInfo, ChannelInfo[] channelInfos) { return HasChannels(userInfo.UserId, channelInfos.Select(c => c.Name).ToArray()); } public void DeleteUser(long userId) { if(!UserChannels.ContainsKey(userId)) return; HashSet channelNames = UserChannels[userId]; UserChannels.Remove(userId); DeleteUserLastChannel(userId); foreach(string channelName in channelNames) { if(!ChannelUsers.ContainsKey(channelName)) continue; ChannelUsers[channelName].Remove(userId); } } public void DeleteUser(UserInfo userInfo) { DeleteUser(userInfo.UserId); } public void DeleteChannel(string channelName) { channelName = channelName.ToLowerInvariant(); if(!ChannelUsers.ContainsKey(channelName)) return; HashSet userIds = ChannelUsers[channelName]; ChannelUsers.Remove(channelName); foreach(long userId in userIds) { if(!UserChannels.ContainsKey(userId)) continue; UserChannels[userId].Remove(channelName); if(IsUserLastChannel(userId, channelName)) DeleteUserLastChannel(userId); } } public void DeleteChannel(ChannelInfo channelInfo) { DeleteChannel(channelInfo.Name); } } }