/// <summary>
        /// Returns all intervals that overlaps with this interval
        /// </summary>
        /// <param name="interval"></param>
        /// <returns></returns>
        private List <AsInterval <T> > GetOverlaps(AsIntervalRedBlackTreeNode <AsInterval <T> > current,
                                                   AsInterval <T> searchInterval, List <AsInterval <T> > result = null)
        {
            if (result == null)
            {
                result = new List <AsInterval <T> >();
            }

            if (current == null)
            {
                return(result);
            }

            if (doOverlap(current.Value, searchInterval))
            {
                result.Add(current.Value);
            }

            //if left max is greater than search start
            //then the search interval can occur in left sub tree
            if (current.Left != null &&
                current.Left.Value.MaxEnd.CompareTo(searchInterval.Start) >= 0)
            {
                GetOverlaps(current.Left, searchInterval, result);
            }

            //otherwise look in right subtree
            GetOverlaps(current.Right, searchInterval, result);

            return(result);
        }
        /// <summary>
        /// Insert a new Interval
        /// </summary>
        /// <param name="newInterval"></param>
        public void Insert(AsInterval <T> newInterval)
        {
            SortInterval(newInterval);

            RedBlackTree.Insert(newInterval);
            Count++;
        }
        /// <summary>
        /// Delete this interval
        /// </summary>
        /// <param name="interval"></param>
        public void Delete(AsInterval <T> interval)
        {
            SortInterval(interval);

            RedBlackTree.Delete(interval);
            Count--;
        }
        /// <summary>
        /// Does this interval a overlap with b
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        private bool doOverlap(AsInterval <T> a, AsInterval <T> b)
        {
            //lazy reset
            a.MatchingEndIndex = -1;
            b.MatchingEndIndex = -1;

            for (var i = 0; i < a.End.Count; i++)
            {
                for (var j = 0; j < b.End.Count; j++)
                {
                    //a.Start less than b.End and a.End greater than b.Start
                    if (a.Start.CompareTo(b.End[j]) > 0 || a.End[i].CompareTo(b.Start) < 0)
                    {
                        continue;
                    }

                    a.MatchingEndIndex = i;
                    b.MatchingEndIndex = j;

                    return(true);
                }
            }

            return(false);
        }
 /// <summary>
 /// Swap intervals so that start always appear before end
 /// </summary>
 /// <param name="value"></param>
 private void SortInterval(AsInterval <T> value)
 {
     if (value.Start.CompareTo(value.End[0]) > 0)
     {
         var tmp = value.End[0];
         value.End[0] = value.Start;
         value.Start  = tmp;
     }
 }
            //O(log(n)) always
            public void Delete(AsInterval <T> value)
            {
                if (Root == null)
                {
                    throw new Exception("Empty Tree");
                }

                delete(Root, value, false);
                Count--;
            }
        /// <summary>
        /// Swap intervals so that start always appear before end
        /// </summary>
        /// <param name="value"></param>
        private void sortInterval(AsInterval <T> value)
        {
            if (value.Start.CompareTo(value.End[0]) <= 0)
            {
                return;
            }

            var tmp = value.End[0];

            value.End[0] = value.Start;
            value.Start  = tmp;
        }
            /// <summary>
            /// returns the index of a matching value in this End range List
            /// </summary>
            /// <param name="end"></param>
            /// <param name="value"></param>
            /// <returns></returns>
            private int GetIndex(List <T> end, AsInterval <T> value)
            {
                var index = -1;

                for (int i = 0; i < end.Count; i++)
                {
                    if (end[i].CompareTo(value.End[0]) == 0)
                    {
                        index = i;
                    }
                }

                return(index);
            }
            //O(log(n)) always
            private AsIntervalRedBlackTreeNode <AsInterval <T> > insert(
                AsIntervalRedBlackTreeNode <AsInterval <T> > currentNode, AsInterval <T> newNodeValue)
            {
                var compareResult = currentNode.Value.CompareTo(newNodeValue);

                //current node is less than new item
                if (compareResult < 0)
                {
                    //no right child
                    if (currentNode.Right == null)
                    {
                        //insert
                        var newNode = new AsIntervalRedBlackTreeNode <AsInterval <T> >(currentNode, newNodeValue);
                        currentNode.Right = newNode;
                        UpdateMax(newNode);
                        BalanceInsertion(newNode);
                        return(newNode);
                    }
                    else
                    {
                        var newNode = insert(currentNode.Right, newNodeValue);
                        return(newNode);
                    }
                }
                //current node is greater than new node
                else if (compareResult > 0)
                {
                    if (currentNode.Left == null)
                    {
                        //insert
                        var newNode = new AsIntervalRedBlackTreeNode <AsInterval <T> >(currentNode, newNodeValue);
                        currentNode.Left = newNode;
                        UpdateMax(newNode);
                        BalanceInsertion(newNode);
                        return(newNode);
                    }
                    else
                    {
                        var newNode = insert(currentNode.Left, newNodeValue);
                        return(newNode);
                    }
                }
                else
                {
                    currentNode.Value.End.Add(newNodeValue.End[0]);
                    UpdateMax(currentNode);
                    return(currentNode);
                }
            }
            //O(log(n)) always
            public void Insert(AsInterval <T> value)
            {
                //empty tree
                if (Root == null)
                {
                    Root           = new AsIntervalRedBlackTreeNode <AsInterval <T> >(null, value);
                    Root.NodeColor = RedBlackTreeNodeColor.Black;
                    UpdateMax(Root);
                    Count++;
                    return;
                }

                insert(Root, value);
                Count++;
            }
        /// <summary>
        /// Returns an interval that overlaps with this interval
        /// </summary>
        /// <param name="interval"></param>
        /// <returns></returns>
        private AsInterval <T> GetOverlap(AsIntervalRedBlackTreeNode <AsInterval <T> > current,
                                          AsInterval <T> searchInterval)
        {
            if (current == null)
            {
                return(null);
            }

            if (doOverlap(current.Value, searchInterval))
            {
                return(current.Value);
            }

            //if left max is greater than search start
            //then the search interval can occur in left sub tree
            if (current.Left != null &&
                current.Left.Value.MaxEnd.CompareTo(searchInterval.Start) >= 0)
            {
                return(GetOverlap(current.Left, searchInterval));
            }

            //otherwise look in right subtree
            return(GetOverlap(current.Right, searchInterval));
        }
        /// <summary>
        ///  does any interval overlaps with this search interval
        /// </summary>
        /// <param name="searchInterval"></param>
        /// <returns></returns>
        internal bool DoOverlap(AsInterval <T> searchInterval)
        {
            SortInterval(searchInterval);

            return(GetOverlap(RedBlackTree.Root, searchInterval) != null);
        }
        /// <summary>
        ///  Returns an interval in this tree that overlaps with this search interval
        /// </summary>
        /// <param name="searchInterval"></param>
        /// <returns></returns>
        internal List <AsInterval <T> > GetOverlaps(AsInterval <T> searchInterval)
        {
            SortInterval(searchInterval);

            return(GetOverlaps(RedBlackTree.Root, searchInterval));
        }
            /// <summary>
            /// Deletes the node and return a reference to the parent of actual node deleted
            /// O(log(n)) always
            /// </summary>
            /// <param name="node"></param>
            /// <param name="value"></param>
            /// <returns></returns>
            private AsIntervalRedBlackTreeNode <AsInterval <T> > delete(AsIntervalRedBlackTreeNode <AsInterval <T> > node,
                                                                        AsInterval <T> value, bool deleteByStartOnly)
            {
                var compareResult = node.Value.CompareTo(value);

                //node is less than the search value so move right to find the deletion node
                if (compareResult < 0)
                {
                    if (node.Right == null)
                    {
                        throw new Exception("Item do not exist");
                    }

                    return(delete(node.Right, value, deleteByStartOnly));
                }
                //node is less than the search value so move left to find the deletion node
                else if (compareResult > 0)
                {
                    if (node.Left == null)
                    {
                        throw new Exception("Item do not exist");
                    }

                    return(delete(node.Left, value, deleteByStartOnly));
                }
                else
                {
                    AsIntervalRedBlackTreeNode <AsInterval <T> > nodeToBalance = null;

                    //if not a leaf deletion caused by replacement
                    //of an ancestor deleted with this node
                    if (!deleteByStartOnly)
                    {
                        var index = GetIndex(node.Value.End, value);

                        if (index == -1)
                        {
                            throw new Exception("Interval do not exist");
                        }

                        if (node.Value.End.Count > 1)
                        {
                            node.Value.End.RemoveAt(index);
                            UpdateMax(node);
                            return(node);
                        }
                    }

                    //node is a leaf node
                    if (node.IsLeaf)
                    {
                        //if color is red, we are good; no need to balance
                        if (node.NodeColor == RedBlackTreeNodeColor.Red)
                        {
                            deleteLeaf(node);
                            UpdateMax(node.Parent);
                            return(node.Parent);
                        }


                        nodeToBalance = handleDoubleBlack(node);
                        deleteLeaf(node);
                        UpdateMax(node.Parent);
                    }
                    else
                    {
                        //case one - right tree is null (move sub tree up)
                        if (node.Left != null && node.Right == null)
                        {
                            nodeToBalance = handleDoubleBlack(node);
                            deleteLeftNode(node);
                            UpdateMax(node.Parent);
                        }
                        //case two - left tree is null  (move sub tree up)
                        else if (node.Right != null && node.Left == null)
                        {
                            nodeToBalance = handleDoubleBlack(node);
                            deleteRightNode(node);
                            UpdateMax(node.Parent);
                        }
                        //case three - two child trees
                        //replace the node value with maximum element of left subtree (left max node)
                        //and then delete the left max node
                        else
                        {
                            var index = GetIndex(node.Value.End, value);

                            if (index == -1)
                            {
                                throw new Exception("Interval do not exist");
                            }

                            //if this is the only element
                            //do regular bst deletion
                            if (node.Value.End.Count == 1 && index == 0)
                            {
                                var maxLeftNode = FindMax(node.Left);

                                node.Value        = maxLeftNode.Value;
                                node.Value.MaxEnd = defaultValue.Value;

                                //delete left max node
                                return(delete(node.Left, maxLeftNode.Value, true));
                            }
                            else
                            {
                                //just remove the end
                                node.Value.End.RemoveAt(index);
                                UpdateMax(node);
                                return(node);
                            }
                        }
                    }

                    var returnNode = nodeToBalance;

                    //handle six cases
                    while (nodeToBalance != null)
                    {
                        nodeToBalance = handleDoubleBlack(nodeToBalance);
                    }

                    return(returnNode);
                }
            }
 /// <summary>
 ///  Returns an interval in this tree that overlaps with this search interval
 /// </summary>
 /// <param name="searchInterval"></param>
 /// <returns></returns>
 internal AsInterval <T> GetOverlap(AsInterval <T> searchInterval)
 {
     sortInterval(searchInterval);
     return(getOverlap(redBlackTree.Root, searchInterval));
 }