public virtual void InsertRight(IExpressionTreeNode rightNode)
        {
            if (rightNode == null)
                throw new ArgumentNullException("rightNode");

            if (Right != null)
                throw new InvalidOperationException("This node already contains right child node.");

            Right = rightNode;
            Right.AssignParent(this);

            RaiseTreeChanged();
        }
        public virtual void InsertLeft(IExpressionTreeNode leftNode)
        {
            if (leftNode == null)
                throw new ArgumentNullException("leftNode");

            if (Left != null)
                throw new InvalidOperationException("This node already contains left child node.");

            Left = leftNode;
            Left.AssignParent(this);

            RaiseTreeChanged();
        }
        public virtual void ReplaceChildNode(IExpressionTreeNode oldNode, IExpressionTreeNode newNode)
        {
            if (Left == oldNode)
            {
                Left = newNode;
            }
            else if (Right == oldNode)
            {
                Right = newNode;
            }
            else
            {
                throw new InvalidOperationException("old node is not a child of this element");
            }

            if (newNode != null)
            {
                newNode.AssignParent(this);
            }
        }
        /// <summary>
        /// Cleans up the tree structure to ensure that all Connective Nodes have both children assigned.
        /// If a Connective has no children assigned, it will be removed.
        /// If a Connective has one child assigned, it will be removed and child moved in its place.
        /// </summary>
        void CleanUpTreeStructure()
        {
            if (Root == null)
                return;

            //# find te root

            var root_candidate = Root;

            foreach (var node in Root.TraverseTreePostOrder())
            {
                if (node is PredicateNode)
                    continue;

                var connectiveNode = node as PredicateConnectiveNode;

                //# Connective Node with both children => do nothing
                if (connectiveNode.Left != null && connectiveNode.Right != null)
                    continue;

                //# Connective Node without any children => REMOVE
                if (connectiveNode.Left == null && connectiveNode.Right == null)
                {
                    if (connectiveNode.Parent == null)
                    {
                        // this is the root, replace it with null
                        Root = null;
                        break;
                    }
                    else
                    {
                        connectiveNode.Parent.ReplaceChildNode(connectiveNode, null);
                        continue;
                    }
                }

                //# Connective Node with only one child => replace connective node with the child
                if (connectiveNode.Left == null)
                {
                    if (connectiveNode.Parent == null)
                    {
                        // this is the root, replace it with Right Child
                        Root = connectiveNode.Right;
                        Root.AssignParent(newParent: null);

                    }
                    else
                    {
                        connectiveNode.Parent.ReplaceChildNode(connectiveNode, connectiveNode.Right);
                        continue;
                    }
                }

                if (connectiveNode.Right == null)
                {
                    if (connectiveNode.Parent == null)
                    {
                        // this is the root, replace it with Left Child
                        Root = connectiveNode.Left;
                        Root.AssignParent(newParent: null);
                    }
                    else
                    {
                        connectiveNode.Parent.ReplaceChildNode(connectiveNode, connectiveNode.Left);
                        continue;
                    }
                }
            }

            RaiseTreeChanged();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="source">Node to be injected</param>
        /// <param name="target">Target Node which will be replaced by Source, and joined with source's new sub-tree</param>
        static IExpressionTreeNode InjectInto(IExpressionTreeNode source, IExpressionTreeNode target, Func<IPredicateConnectiveNode> createConnectiveNode)
        {
            var sourceParent = source.Parent;

            var sourceParentAsConnective = sourceParent as PredicateConnectiveNode;

            var sourceSibling = (IExpressionTreeNode)null;

            if (sourceParentAsConnective != null)
            {
                var sourcePosition = sourceParentAsConnective.GetChildPosition(source);

                if (sourcePosition == ChildNodePosition.Left)
                    sourceSibling = sourceParentAsConnective.Right;
                else
                    sourceSibling = sourceParentAsConnective.Left;
            }
            var sourceSiblingAsConnective = sourceSibling as PredicateConnectiveNode;
            
            var targetParent = target.Parent;

            var targetParentAsConnective = targetParent as PredicateConnectiveNode;

            var targetSibling = (IExpressionTreeNode)null;

            var targetPosition = ChildNodePosition.Right; // default should be right, if target has no parent

            if(targetParent != null)
            {
                targetPosition = targetParent.GetChildPosition(target);
            }

            if (targetParentAsConnective != null)
            {
                if (targetPosition == ChildNodePosition.Left)
                    targetSibling = targetParentAsConnective.Right;
                else
                    targetSibling = targetParentAsConnective.Left;
            }

            var targetSiblingAsConnective = targetSibling as PredicateConnectiveNode;

            var newConnective = createConnectiveNode();

            if (targetParent != null)
            {
                //# remove target from its parent
                target.AssignParent(newParent: null);
                targetParent.ClearChildAssignment(target);

                //# assign new Connective in place of target
                targetParent.AssignChild(newConnective, targetPosition);
                newConnective.AssignParent(targetParent);
            }
            else
            {

            }

            //# assign old target as left child node of new connective
            if (targetPosition == ChildNodePosition.Left)
                newConnective.AssignChild(target, ChildNodePosition.Right);
            else
                newConnective.AssignChild(target, ChildNodePosition.Left);

            //# copy connective mode from target parent (if exists)
            if (targetParentAsConnective != null)
                newConnective.CopyFrom(targetParentAsConnective);
            else if (targetSiblingAsConnective != null)
                newConnective.CopyFrom(targetSiblingAsConnective);

            target.AssignParent(newConnective);

            //# assign source node as right child node of new connective
            newConnective.AssignChild(source, targetPosition);
            source.AssignParent(newConnective);

            //# fix original parent tree
            //  parent is an empty connective or connective with one child now
            //  replace parent connective with its child (removing the connective completely from the tree)
            if (sourceParent != null)
            {
                //# remove source from its parent
                var sourcePosition = default(ChildNodePosition);
                sourceParent.ClearChildAssignment(source, out sourcePosition);

                //# get other source parent child
                var oldSibling = (IExpressionTreeNode)null;
                if (sourcePosition == ChildNodePosition.Left)
                    oldSibling = sourceParent.Right;
                else
                    oldSibling = sourceParent.Left;

                //# in grand parent, replace source parent with its other sibling
                var grandParent = sourceParent.Parent;

                if (grandParent != null)
                    grandParent.ReplaceChildNode(sourceParent, oldSibling);
            }

            //# get new root element of a tree

            var root_candidate = (IExpressionTreeNode)newConnective;
            while (root_candidate.Parent != null)
                root_candidate = root_candidate.Parent;

            return root_candidate;
        }