using System; using System.Security.Permissions; namespace ReClassNET.Nodes { public abstract class BaseWrapperNode : BaseNode { /// Gets or sets the inner node. public BaseNode InnerNode { get; protected set; } /// Gets signaled if the inner node was changed. public event NodeEventHandler InnerNodeChanged; /// True to perform class cycle checks when changing the inner node. protected abstract bool PerformCycleCheck { get; } /// /// Should be called before to test if the node can handle the inner node type. /// /// The new inner node type. /// True if the class can handle the inner node type or false otherwise. public abstract bool CanChangeInnerNodeTo(BaseNode node); /// Changes the inner node. /// The new node. public void ChangeInnerNode(BaseNode node) { if (!CanChangeInnerNodeTo(node)) { throw new InvalidOperationException($"Can't change inner node to '{node?.GetType().ToString() ?? "null"}'"); } if (InnerNode != node) { InnerNode = node; if (node != null) { node.ParentNode = this; } InnerNodeChanged?.Invoke(this); GetParentContainer()?.ChildHasChanged(this); } } /// /// Resolve the most inner node of a chain. /// /// The most inner node or null. public BaseNode ResolveMostInnerNode() { if (InnerNode == null) { return null; } if (InnerNode is BaseWrapperNode baseWrapperNode) { return baseWrapperNode.ResolveMostInnerNode(); } return InnerNode; } /// /// Tests if the cycle check is really needed in a chain. /// /// public bool ShouldPerformCycleCheckForInnerNode() { // TODO Should there be a "is ClassNode" for the last inner node? if (!PerformCycleCheck) { return false; } var wrapperNode = this; while (wrapperNode.InnerNode is BaseWrapperNode wrappedNode) { if (!wrappedNode.PerformCycleCheck) { return false; } wrapperNode = wrappedNode; } return true; } /// /// Tests if the given node type is present in the chain of wrapped nodes. /// /// The node type to check. /// True if the given node type is present in the chain of wrapped nodes, false otherwise. public bool IsNodePresentInChain() where TNode : BaseNode { BaseNode node = this; while (node is BaseWrapperNode wrapperNode) { if (node is TNode) { return true; } node = wrapperNode.InnerNode; } return false; } } }