using System.Linq; using System.Reflection; using Artemis.Core; using Ninject; using Ninject.Parameters; /// /// Represents a kind of node inside a containing storage value of type /// and a view model of type . /// /// The type of value the node stores /// The type of view model the node uses public abstract class Node : Node, ICustomViewModelNode where TViewModel : ICustomNodeViewModel { /// protected Node() { } /// protected Node(string name, string description) : base(name, description) { } [Inject] internal IKernel Kernel { get; set; } = null!; /// /// Called when a view model is required /// /// public virtual TViewModel GetViewModel(NodeScript nodeScript) { // Limit to one constructor, there's no need to have more and it complicates things anyway ConstructorInfo[] constructors = typeof(TViewModel).GetConstructors(); if (constructors.Length != 1) throw new ArtemisCoreException("Node VMs must have exactly one constructor"); // Find the ScriptConfiguration parameter, it is required by the base constructor so its there for sure ParameterInfo? configurationParameter = constructors.First().GetParameters().FirstOrDefault(p => GetType().IsAssignableFrom(p.ParameterType)); if (configurationParameter?.Name == null) throw new ArtemisCoreException($"Couldn't find a valid constructor argument on {typeof(TViewModel).Name} with type {GetType().Name}"); return Kernel.Get(new ConstructorArgument(configurationParameter.Name, this), new ConstructorArgument("script", nodeScript)); } /// /// Gets or sets the position of the node's custom view model. /// public CustomNodeViewModelPosition ViewModelPosition { get; protected set; } = CustomNodeViewModelPosition.BetweenPinsTop; /// /// public ICustomNodeViewModel GetCustomViewModel(NodeScript nodeScript) { return GetViewModel(nodeScript); } }