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;
}
}
}