Code/UI/PanelAttribute.cs
namespace Nodebox.UI;

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class PanelAttribute : Attribute {
    public Type Type { get; set; }
    public PanelAttribute(Type type) {
        Assert.True(type.IsAssignableTo(typeof(NodePanel)), $"{type} doesn't inherit {nameof(NodePanel)}");
        Type = type;
    }

    public static NodePanel CreatePanelFor(Node node) => CreatePanelFor(node.GetType());
    public static NodePanel CreatePanelFor(Type nodeType) {
        Assert.NotNull(nodeType);

        var typeDescription = TypeLibrary.GetType(FindPanelFor(nodeType));
        if (!typeDescription.IsGenericType) {
            return typeDescription.Create<NodePanel>();
        }

        var typeArgs = new Type[typeDescription.GenericArguments.Length];
        Array.Fill(typeArgs, typeof(object));
        Type[] nodeTypeArgs = [];
        if (TypeLibrary.GetType(nodeType).IsGenericType) {
            nodeTypeArgs = TypeLibrary.GetGenericArguments(nodeType);
        }
        foreach (var (index, arg) in nodeTypeArgs.Enumerate()) {
            if (index >= typeArgs.Length) { break; }
            typeArgs[index] = arg;
        }

        return typeDescription.CreateGeneric<NodePanel>(typeArgs, []);
    }
    public static Type FindPanelFor(Node node) => FindPanelFor(node?.GetType());
    public static Type FindPanelFor(Type nodeType) {
        Assert.NotNull(nodeType);

        // Assert.True(nodeType.IsAssignableTo(typeof(Node)), $"{nodeType} doesn't inherit {nameof(Node)}");
        var genericDefNodeType = TypeLibrary.GetType(nodeType).TargetType;
        var panelAttribute = TypeLibrary.GetAttributes<PanelAttribute>(genericDefNodeType)?.FirstOrDefault();
        if (panelAttribute == null) {
            // Log.Info($"{nodeType} --Panel-> {typeof(Basic)}");
            return typeof(Basic);
        }

        // Log.Info($"{nodeType} --Panel-> {panelAttribute.Type}");
        return panelAttribute.Type;
    }
    public static Type FindPanelFor<T>() => FindPanelFor(typeof(T));
}

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class PanelAttribute<T>() : PanelAttribute(typeof(T)) { }