using System.Collections.Frozen;
namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.Management;
///
/// Bidirectional name registry for management command records. The registry contains
/// exactly the non-abstract *Command types declared in the
/// ZB.MOM.WW.ScadaBridge.Commons.Messages.Management namespace; these are the commands that
/// travel over the HTTP / ClusterClient management boundary.
///
///
/// and are symmetric:
/// Resolve(GetCommandName(t)) returns t for every type
/// accepts. rejects any type
/// the registry does not contain rather than computing an unresolvable name.
///
public static class ManagementCommandRegistry
{
private static readonly FrozenDictionary Commands = BuildRegistry();
///
/// Names keyed by command type, for the reverse lookup. Keeps
/// in lock-step with the forward registry.
///
private static readonly FrozenDictionary NamesByType =
Commands.ToFrozenDictionary(kv => kv.Value, kv => kv.Key);
///
/// Resolves a management command wire name to its CLR type, or null if not registered.
///
/// The wire name of the management command (without the "Command" suffix).
public static Type? Resolve(string commandName)
{
return Commands.GetValueOrDefault(commandName);
}
///
/// Returns the registered wire name for a management command type.
///
/// The CLR type of the management command to look up.
///
/// Thrown when is not a registered management
/// command — i.e. not a non-abstract *Command type in the
/// ZB.MOM.WW.ScadaBridge.Commons.Messages.Management namespace. This keeps the method
/// symmetric with : it never yields a name that
/// cannot turn back into the same type.
///
public static string GetCommandName(Type commandType)
{
ArgumentNullException.ThrowIfNull(commandType);
if (NamesByType.TryGetValue(commandType, out var name))
return name;
throw new ArgumentException(
$"'{commandType.FullName}' is not a registered management command. " +
$"Management commands must be non-abstract '*Command' records declared in " +
$"the '{typeof(ManagementEnvelope).Namespace}' namespace.",
nameof(commandType));
}
private static FrozenDictionary BuildRegistry()
{
var ns = typeof(ManagementEnvelope).Namespace!;
var assembly = typeof(ManagementEnvelope).Assembly;
return assembly.GetTypes()
.Where(t => t.Namespace == ns
&& t.Name.EndsWith("Command", StringComparison.Ordinal)
&& !t.IsAbstract)
.ToFrozenDictionary(
t => t.Name[..^"Command".Length],
t => t,
StringComparer.OrdinalIgnoreCase);
}
}