using System;
using System.Collections.Generic;
using System.Linq;
namespace StardewModdingAPI.Framework
{
/// Manages console commands.
internal class CommandManager
{
/*********
** Properties
*********/
/// The commands registered with SMAPI.
private readonly IDictionary Commands = new Dictionary(StringComparer.InvariantCultureIgnoreCase);
/*********
** Public methods
*********/
/// Add a console command.
/// The friendly mod name for this instance.
/// The command name, which the user must type to trigger it.
/// The human-readable documentation shown when the player runs the built-in 'help' command.
/// The method to invoke when the command is triggered. This method is passed the command name and arguments submitted by the user.
/// Whether to allow a null argument; this should only used for backwards compatibility.
/// The or is null or empty.
/// The is not a valid format.
/// There's already a command with that name.
public void Add(string modName, string name, string documentation, Action callback, bool allowNullCallback = false)
{
name = this.GetNormalisedName(name);
// validate format
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentNullException(nameof(name), "Can't register a command with no name.");
if (name.Any(char.IsWhiteSpace))
throw new FormatException($"Can't register the '{name}' command because the name can't contain whitespace.");
if (callback == null && !allowNullCallback)
throw new ArgumentNullException(nameof(callback), $"Can't register the '{name}' command because without a callback.");
// ensure uniqueness
if (this.Commands.ContainsKey(name))
throw new ArgumentException(nameof(callback), $"Can't register the '{name}' command because there's already a command with that name.");
// add command
this.Commands.Add(name, new Command(modName, name, documentation, callback));
}
/// Get a command by its unique name.
/// The command name.
/// Returns the matching command, or null if not found.
public Command Get(string name)
{
name = this.GetNormalisedName(name);
this.Commands.TryGetValue(name, out Command command);
return command;
}
/// Get all registered commands.
public IEnumerable GetAll()
{
return this.Commands
.Values
.OrderBy(p => p.Name);
}
/// Trigger a command.
/// The raw command input.
/// Returns whether a matching command was triggered.
public bool Trigger(string input)
{
if (string.IsNullOrWhiteSpace(input))
return false;
string[] args = input.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
string name = args[0];
args = args.Skip(1).ToArray();
return this.Trigger(name, args);
}
/// Trigger a command.
/// The command name.
/// The command arguments.
/// Returns whether a matching command was triggered.
public bool Trigger(string name, string[] arguments)
{
// get normalised name
name = this.GetNormalisedName(name);
if (name == null)
return false;
// get command
if (this.Commands.TryGetValue(name, out Command command))
{
command.Callback.Invoke(name, arguments);
return true;
}
return false;
}
/*********
** Private methods
*********/
/// Get a normalised command name.
/// The command name.
private string GetNormalisedName(string name)
{
name = name?.Trim().ToLower();
return !string.IsNullOrWhiteSpace(name)
? name
: null;
}
}
}