using System; using System.Collections.Generic; using System.Linq; namespace MxGateway.Worker.MxAccess; public sealed class MxAccessHandleRegistry { private readonly Dictionary serverHandles = new(); private readonly Dictionary itemHandles = new(); private readonly Dictionary adviceHandles = new(); /// Gets a read-only list of registered server handles ordered by handle value. public IReadOnlyList ServerHandles => serverHandles .Values .OrderBy(handle => handle.ServerHandle) .ToArray(); /// Gets a read-only list of registered item handles ordered by server handle then item handle. public IReadOnlyList ItemHandles => itemHandles .Values .OrderBy(handle => handle.ServerHandle) .ThenBy(handle => handle.ItemHandle) .ToArray(); /// Gets a read-only list of registered advice handles ordered by server handle, item handle, and advice kind. public IReadOnlyList AdviceHandles => adviceHandles .Values .OrderBy(handle => handle.ServerHandle) .ThenBy(handle => handle.ItemHandle) .ThenBy(handle => handle.AdviceKind) .ToArray(); /// Registers a server handle with the registry. /// Handle returned by the worker. /// Display name of the client that owns the server handle. public void RegisterServerHandle( int serverHandle, string clientName) { serverHandles[serverHandle] = new RegisteredServerHandle(serverHandle, clientName); } /// Unregisters a server handle and all associated item and advice handles from the registry. /// Handle returned by the worker. public void UnregisterServerHandle(int serverHandle) { serverHandles.Remove(serverHandle); foreach (long key in itemHandles .Where(pair => pair.Value.ServerHandle == serverHandle) .Select(pair => pair.Key) .ToArray()) { itemHandles.Remove(key); } foreach (AdviceHandleKey key in adviceHandles .Where(pair => pair.Value.ServerHandle == serverHandle) .Select(pair => pair.Key) .ToArray()) { adviceHandles.Remove(key); } } /// Checks if the registry contains the specified server handle. /// Handle returned by the worker. public bool ContainsServerHandle(int serverHandle) { return serverHandles.ContainsKey(serverHandle); } /// Registers an item handle with the registry. /// Handle returned by the worker. /// Handle returned by the worker. /// Item definition name from MXAccess. /// Item context from MXAccess, or empty string if none. /// True if the item has a context; false otherwise. public void RegisterItemHandle( int serverHandle, int itemHandle, string itemDefinition, string itemContext, bool hasItemContext) { itemHandles[CreateItemKey(serverHandle, itemHandle)] = new RegisteredItemHandle( serverHandle, itemHandle, itemDefinition, itemContext, hasItemContext); } /// Removes an item handle and all associated advice handles from the registry. /// Handle returned by the worker. /// Handle returned by the worker. public void RemoveItemHandle( int serverHandle, int itemHandle) { itemHandles.Remove(CreateItemKey(serverHandle, itemHandle)); RemoveAdviceHandles(serverHandle, itemHandle); } /// Checks if the registry contains the specified item handle. /// Handle returned by the worker. /// Handle returned by the worker. public bool ContainsItemHandle( int serverHandle, int itemHandle) { return itemHandles.ContainsKey(CreateItemKey(serverHandle, itemHandle)); } /// Registers an advice handle with the registry. /// Handle returned by the worker. /// Handle returned by the worker. /// Type of advice to register. public void RegisterAdviceHandle( int serverHandle, int itemHandle, MxAccessAdviceKind adviceKind) { AdviceHandleKey key = new(serverHandle, itemHandle, adviceKind); adviceHandles[key] = new RegisteredAdviceHandle( serverHandle, itemHandle, adviceKind); } /// Removes all advice handles for the specified server and item handles from the registry. /// Handle returned by the worker. /// Handle returned by the worker. public void RemoveAdviceHandles( int serverHandle, int itemHandle) { foreach (AdviceHandleKey key in adviceHandles .Where(pair => pair.Value.ServerHandle == serverHandle && pair.Value.ItemHandle == itemHandle) .Select(pair => pair.Key) .ToArray()) { adviceHandles.Remove(key); } } /// Checks if the registry contains the specified advice handle. /// Handle returned by the worker. /// Handle returned by the worker. /// Type of advice to check. public bool ContainsAdviceHandle( int serverHandle, int itemHandle, MxAccessAdviceKind adviceKind) { return adviceHandles.ContainsKey(new AdviceHandleKey(serverHandle, itemHandle, adviceKind)); } private static long CreateItemKey( int serverHandle, int itemHandle) { return ((long)serverHandle << 32) | (uint)itemHandle; } private readonly struct AdviceHandleKey : IEquatable { private readonly int serverHandle; private readonly int itemHandle; private readonly MxAccessAdviceKind adviceKind; /// Initializes a new instance of the struct. /// Handle returned by the worker. /// Handle returned by the worker. /// Type of advice. public AdviceHandleKey( int serverHandle, int itemHandle, MxAccessAdviceKind adviceKind) { this.serverHandle = serverHandle; this.itemHandle = itemHandle; this.adviceKind = adviceKind; } /// public bool Equals(AdviceHandleKey other) { return serverHandle == other.serverHandle && itemHandle == other.itemHandle && adviceKind == other.adviceKind; } /// public override bool Equals(object? obj) { return obj is AdviceHandleKey other && Equals(other); } /// public override int GetHashCode() { unchecked { int hashCode = serverHandle; hashCode = (hashCode * 397) ^ itemHandle; hashCode = (hashCode * 397) ^ (int)adviceKind; return hashCode; } } } }