using System; using System.Collections.Generic; using System.Linq; namespace Cryville.Crtr.Browsing.Actions { public class ActionManager { readonly Dictionary> _actions = new(); readonly Dictionary _refCounts = new(); public event Action Changed; class ActionPriorityComparer : IComparer { public static readonly ActionPriorityComparer Instance = new(); public int Compare(IResourceAction x, IResourceAction y) { return x.Priority.CompareTo(y.Priority); } } void Register(Type type, IResourceAction action) { if (!_actions.TryGetValue(type, out List actions)) { _actions.Add(type, actions = new List()); } int index = actions.BinarySearch(action, ActionPriorityComparer.Instance); if (index < 0) index = ~index; actions.Insert(index, action); if (_refCounts.ContainsKey(action)) _refCounts[action]++; else _refCounts[action] = 1; Changed?.Invoke(); } public void Register(IResourceAction action) { Register(typeof(object), action); } public void Register(IResourceAction action) where T : IResourceMeta { Register(typeof(T), action); } public void Unregister(Type type, IResourceAction action) { if (!_actions.TryGetValue(type, out List actions)) return; if (--_refCounts[action] > 0) return; actions.Remove(action); Changed?.Invoke(); } public void Unregister(IResourceAction action) { Unregister(typeof(object), action); } public void Unregister(IResourceAction action) where T : IResourceMeta { Unregister(typeof(T), action); } public IEnumerable GetActions(Uri uri, IResourceMeta res) { return GetActions(uri, res, res.GetType()); } IEnumerable GetActions(Uri uri, IResourceMeta res, Type type) { if (type == null) return Enumerable.Empty(); IEnumerable result; if (_actions.TryGetValue(type, out List actions)) result = actions.Where(i => i.CanInvoke(uri, res)); else result = Enumerable.Empty(); if (type != typeof(object)) result = result .Concat(GetActions(uri, res, type.BaseType)) .Concat(type.GetInterfaces().SelectMany(i => GetActions(uri, res, i))); return result; } } }