using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; namespace Discord.Commands { internal class CommandMapNode { private readonly ConcurrentDictionary<string, CommandMapNode> _nodes; private readonly string _name; private readonly object _lockObj = new object(); private ImmutableArray<Command> _commands; public bool IsEmpty => _commands.Length == 0 && _nodes.Count == 0; public CommandMapNode(string name) { _name = name; _nodes = new ConcurrentDictionary<string, CommandMapNode>(); _commands = ImmutableArray.Create<Command>(); } public void AddCommand(string text, int index, Command command) { int nextSpace = text.IndexOf(' ', index); string name; lock (_lockObj) { if (text == "") _commands = _commands.Add(command); else { if (nextSpace == -1) name = text.Substring(index); else name = text.Substring(index, nextSpace - index); var nextNode = _nodes.GetOrAdd(name, x => new CommandMapNode(x)); nextNode.AddCommand(nextSpace == -1 ? "" : text, nextSpace + 1, command); } } } public void RemoveCommand(string text, int index, Command command) { int nextSpace = text.IndexOf(' ', index); string name; lock (_lockObj) { if (text == "") _commands = _commands.Remove(command); else { if (nextSpace == -1) name = text.Substring(index); else name = text.Substring(index, nextSpace - index); CommandMapNode nextNode; if (_nodes.TryGetValue(name, out nextNode)) { nextNode.RemoveCommand(nextSpace == -1 ? "" : text, nextSpace + 1, command); if (nextNode.IsEmpty) _nodes.TryRemove(name, out nextNode); } } } } public IEnumerable<Command> GetCommands(string text, int index) { int nextSpace = text.IndexOf(' ', index); string name; var commands = _commands; for (int i = 0; i < commands.Length; i++) yield return _commands[i]; if (text != "") { if (nextSpace == -1) name = text.Substring(index); else name = text.Substring(index, nextSpace - index); CommandMapNode nextNode; if (_nodes.TryGetValue(name, out nextNode)) { foreach (var cmd in nextNode.GetCommands(nextSpace == -1 ? "" : text, nextSpace + 1)) yield return cmd; } } } } }