// Copyright © Gamesmiths Guild.
#if TOOLS
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Gamesmiths.Forge.Godot.Editor.Statescript;
///
/// Registry of available implementations. Resolver editors are discovered
/// automatically via reflection. Any concrete subclass of in the executing assembly is
/// registered and becomes available in node input property dropdowns.
///
internal static class StatescriptResolverRegistry
{
private static readonly List> _factories = [];
static StatescriptResolverRegistry()
{
Type[] allTypes = Assembly.GetExecutingAssembly().GetTypes();
foreach (Type type in allTypes.Where(
x => x.IsSubclassOf(typeof(NodeEditorProperty)) && !x.IsAbstract))
{
Type captured = type;
_factories.Add(() => (NodeEditorProperty)Activator.CreateInstance(captured)!);
}
}
///
/// Gets factory functions for all resolver editors compatible with the given expected type.
///
/// The type expected by the node input property.
/// A list of compatible resolver editor factories.
public static List> GetCompatibleFactories(Type expectedType)
{
return [.. _factories.Where(factory => IsCompatibleFactory(factory, expectedType))];
}
public static int GetDefaultFactoryIndex(List> factories, bool isArray)
{
for (int i = 0; i < factories.Count; i++)
{
if (isArray)
{
if (GetResolverTypeId(factories[i]) == "ArrayVariable")
{
return i;
}
}
else if (GetResolverTypeId(factories[i]) == "Variant")
{
return i;
}
}
return 0;
}
public static string GetDisplayName(Func factory)
{
return UseTemporaryEditor(factory, static editor => editor.DisplayName);
}
public static string GetResolverTypeId(Func factory)
{
return UseTemporaryEditor(factory, static editor => editor.ResolverTypeId);
}
public static bool IsCompatibleFactory(Func factory, Type expectedType)
{
return UseTemporaryEditor(factory, editor => editor.IsCompatibleWith(expectedType));
}
private static TResult UseTemporaryEditor(
Func factory,
Func selector)
{
NodeEditorProperty editor = factory();
try
{
return selector(editor);
}
finally
{
if (global::Godot.GodotObject.IsInstanceValid(editor))
{
editor.Free();
}
}
}
}
#endif