/// <summary>
 /// Initialises a new instance of the MoreComplexDataStructures.DoublyLinkedTreeNode class.
 /// </summary>
 /// <param name="item">The item held by the node.</param>
 /// <param name="parentNode">The parent node of this node.</param>
 public DoublyLinkedTreeNode(T item, DoublyLinkedTreeNode <T> parentNode)
     : base(item)
 {
     this.parentNode = parentNode;
     leftChildNode   = null;
     rightChildNode  = null;
 }
        /// <summary>
        /// Adds the specified item to the heap.
        /// </summary>
        /// <param name="item">The item to add.</param>
        public override void Insert(T item)
        {
            if (rootNode == null)
            {
                rootNode = new DoublyLinkedTreeNode <T>(item, null);
            }
            else
            {
                // Navigate to the parent of the next insert position
                Int32 nextInsertPositionParentHorizontalPosition = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(nextInsertHorizontalPosition) / 2.0));
                DoublyLinkedTreeNode <T> parentNode = TraverseToPosition(nextInsertDepth - 1, nextInsertPositionParentHorizontalPosition);

                // Create the new node
                DoublyLinkedTreeNode <T> newNode = new DoublyLinkedTreeNode <T>(item, parentNode);

                // If nextInsertHorizontalPosition has a remainder after division by 2 insert on the left, otherwise insert on the right
                if ((Convert.ToDouble(nextInsertHorizontalPosition) % 2) != 0)
                {
                    parentNode.LeftChildNode = newNode;
                }
                else
                {
                    parentNode.RightChildNode = newNode;
                }

                // Traverse up the tree to preserve the correct ordering.  Keep traversing and swapping values with the parent until the parent item is greater than the child item.
                DoublyLinkedTreeNode <T> currentNode = newNode;
                while (currentNode.ParentNode != null && currentNode.Item.CompareTo(currentNode.ParentNode.Item) >= 1)
                {
                    // Swap the values
                    T tempItem = currentNode.Item;
                    currentNode.Item            = currentNode.ParentNode.Item;
                    currentNode.ParentNode.Item = tempItem;

                    currentNode = currentNode.ParentNode;
                }
            }

            IncrementNextInsertPosition();

            count++;
        }
        /// <summary>
        /// Performs breadth-first search of the tree underlying the heap, invoking the specified action at each node.
        /// </summary>
        /// <param name="nodeAction">The action to perform at each node.  Accepts a single parameter which is the current node to perform the action on.</param>
        public void BreadthFirstSearch(Action <DoublyLinkedTreeNode <T> > nodeAction)
        {
            Queue <DoublyLinkedTreeNode <T> > traversalQueue = new Queue <DoublyLinkedTreeNode <T> >();

            if (rootNode != null)
            {
                traversalQueue.Enqueue(rootNode);
            }

            while (traversalQueue.Count > 0)
            {
                DoublyLinkedTreeNode <T> currentNode = traversalQueue.Dequeue();
                nodeAction.Invoke(currentNode);
                if (currentNode.LeftChildNode != null)
                {
                    traversalQueue.Enqueue(currentNode.LeftChildNode);
                }
                if (currentNode.RightChildNode != null)
                {
                    traversalQueue.Enqueue(currentNode.RightChildNode);
                }
            }
        }
        /// <summary>
        /// Removes and returns the maxmimum item in the heap.
        /// </summary>
        /// <returns>The maxmimum item in the heap.</returns>
        public T ExtractMax()
        {
            T returnItem = default(T);

            CheckNotEmpty();
            if (count == 1)
            {
                returnItem = rootNode.Item;
                rootNode   = null;
            }
            else
            {
                returnItem = rootNode.Item;

                // Find the position in the tree which was the last inserted to
                Tuple <Int32, Int32> previousPosition = CalculatePreviousPosition(nextInsertDepth, nextInsertHorizontalPosition);
                Int32 previoustDepth = previousPosition.Item1;
                Int32 previoustHorizontalPosition = previousPosition.Item2;

                // Get the node at this position
                DoublyLinkedTreeNode <T> lastInsertedNode = TraverseToPosition(previoustDepth, previoustHorizontalPosition);

                // Set root node's value to that of the last inserted node
                rootNode.Item = lastInsertedNode.Item;

                // Remove the last inserted node from the tree
                if (lastInsertedNode.ParentNode.LeftChildNode == lastInsertedNode)
                {
                    lastInsertedNode.ParentNode.LeftChildNode = null;
                }
                else
                {
                    lastInsertedNode.ParentNode.RightChildNode = null;
                }

                // Traverse down the tree to preserve the proper ordering
                DoublyLinkedTreeNode <T> currentNode = rootNode;
                Boolean keepTraversing = true;
                // Need to keep traversing until either of the following conditions are true...
                //   Both child nodes of currentNode are null
                //   The items of both child nodes of currentNode are less then currentNode's item
                while (keepTraversing == true)
                {
                    // If currentNode is not the root, swap its item with its parent
                    if (currentNode.ParentNode != null)
                    {
                        T tempItem = currentNode.ParentNode.Item;
                        currentNode.ParentNode.Item = currentNode.Item;
                        currentNode.Item            = tempItem;
                    }
                    if (currentNode.LeftChildNode == null && currentNode.RightChildNode == null)
                    {
                        keepTraversing = false;
                    }
                    else if (currentNode.RightChildNode == null)
                    {
                        // Traverse to the left child if it's item is greater than currentNode's item
                        if (currentNode.Item.CompareTo(currentNode.LeftChildNode.Item) < 0)
                        {
                            currentNode = currentNode.LeftChildNode;
                        }
                        else
                        {
                            keepTraversing = false;
                        }
                    }
                    // TODO: If the tree structure is properly maintained, this else branch will never be used (impossible to have a tree node which has a right child, but no left child)
                    //   Consider removing this branch once functionality is solid
                    else if (currentNode.LeftChildNode == null)
                    {
                        // Traverse to the right child if it's item is greater than currentNode's item
                        if (currentNode.Item.CompareTo(currentNode.RightChildNode.Item) < 0)
                        {
                            currentNode = currentNode.RightChildNode;
                        }
                        else
                        {
                            keepTraversing = false;
                        }
                    }
                    else
                    {
                        if (currentNode.Item.CompareTo(currentNode.LeftChildNode.Item) < 0 || currentNode.Item.CompareTo(currentNode.RightChildNode.Item) < 0)
                        {
                            // Traverse to the node with the higher value
                            if (currentNode.LeftChildNode.Item.CompareTo(currentNode.RightChildNode.Item) > 0)
                            {
                                currentNode = currentNode.LeftChildNode;
                            }
                            else
                            {
                                currentNode = currentNode.RightChildNode;
                            }
                        }
                        else
                        {
                            keepTraversing = false;
                        }
                    }
                }
            }

            DecrementNextInsertPosition();

            count--;

            return(returnItem);
        }