/// <summary>
        /// Creates a union stream reader from the supplied data.
        /// </summary>
        /// <param name="streams">all of the tables to combine in the union</param>
        /// <param name="ownsStream">if this class owns the streams, it will call dispose when <see cref="Dispose"/> is called.
        /// Otherwise, the streams will not be disposed.</param>
        public UnionTreeStream(IEnumerable <TreeStream <TKey, TValue> > streams, bool ownsStream)
        {
            m_firstStream    = null;
            m_ownsStreams    = ownsStream;
            m_tablesOrigList = streams.Select(x => new BufferedTreeStream(x)).ToArray();

            m_sortedArchiveStreams = new UnionTreeStreamSortHelper(m_tablesOrigList);
            m_readWhileUpperBounds.SetMin();

            foreach (var table1 in m_sortedArchiveStreams.Items)
            {
                table1.EnsureCache();
            }
            m_sortedArchiveStreams.Sort();

            //Remove any duplicates
            RemoveDuplicatesIfExists();

            if (m_sortedArchiveStreams.Items.Length > 0)
            {
                m_firstTable = m_sortedArchiveStreams[0];
            }
            else
            {
                m_firstTable = null;
            }

            SetReadWhileUpperBoundsValue();
        }
            /// <summary>
            /// Resorts the entire list. Uses an insertion sort routine
            /// </summary>
            public void Sort()
            {
                //A insertion sort routine.

                //Skip first item in list since it will always be sorted correctly
                for (int itemToInsertIndex = 1; itemToInsertIndex < m_validRecords; itemToInsertIndex++)
                {
                    BufferedTreeStream itemToInsert = Items[itemToInsertIndex];

                    int currentIndex = itemToInsertIndex - 1;
                    //While the current item is greater than itemToInsert, shift the value
                    while ((currentIndex >= 0) && (IsLessThan(itemToInsert, Items[currentIndex])))
                    {
                        Items[currentIndex + 1] = Items[currentIndex];
                        currentIndex--;
                    }
                    Items[currentIndex + 1] = itemToInsert;
                }

                for (int x = m_validRecords - 1; x >= 0; x--)
                {
                    if (Items[x].IsValid)
                    {
                        m_validRecords = x + 1;
                        break;
                    }

                    if (x == 0)
                    {
                        m_validRecords = 0;
                    }
                }
            }
            /// <summary>
            /// Resorts only the item at the specified index assuming:
            /// 1) all other items are properly sorted
            /// 2) this items's value increased.
            /// </summary>
            /// <param name="index">the index of the item to resort.</param>
            public void SortAssumingIncreased(int index)
            {
                BufferedTreeStream itemToMove = Items[index];

                if (!itemToMove.IsValid)
                {
                    m_validRecords--;
                    for (int x = index; x < m_validRecords; x++)
                    {
                        Items[x] = Items[x + 1];
                    }
                    Items[m_validRecords] = itemToMove;
                    return;
                }

                //ToDo: Consider an exponential search algorithm.
                int currentIndex = index + 1;

                while (currentIndex < m_validRecords && Items[currentIndex].CacheKey.IsLessThan(itemToMove.CacheKey))
                {
                    Items[currentIndex - 1] = Items[currentIndex];
                    currentIndex++;
                }
                Items[currentIndex - 1] = itemToMove;
            }
        //-------------------------------------------------------------



        /// <summary>
        /// Compares two Archive Streams together for proper sorting.
        /// </summary>
        /// <param name="item1"></param>
        /// <param name="item2"></param>
        /// <returns></returns>
        private int CompareStreams(BufferedTreeStream item1, BufferedTreeStream item2)
        {
            if (!item1.IsValid && !item2.IsValid)
            {
                return(0);
            }
            if (!item1.IsValid)
            {
                return(1);
            }
            if (!item2.IsValid)
            {
                return(-1);
            }
            return(item1.CacheKey.CompareTo(item2.CacheKey));// item1.CurrentKey.CompareTo(item2.CurrentKey);
        }
 private bool IsLessThan(BufferedTreeStream item1, BufferedTreeStream item2)
 {
     if (!item1.IsValid && !item2.IsValid)
     {
         return(false);
     }
     if (!item1.IsValid)
     {
         return(false);
     }
     if (!item2.IsValid)
     {
         return(true);
     }
     return(item1.CacheKey.IsLessThan(item2.CacheKey));// item1.CurrentKey.CompareTo(item2.CurrentKey);
 }
        private bool Read2(TKey key, TValue value)
        {
TryAgain:
            if (m_firstStream == null)
            {
                //If m_firstStream == null, this means either:
                //  the value is cached.
                // or
                //  the end of the stream has occured.
                if (m_firstTable != null && m_firstTable.IsValid)
                {
                    //The value is cached.
                    m_firstTable.Read(key, value);
                    m_firstStream = m_firstTable.Stream;
                    return(true);
                }
                //The end of the steam has been reached.
                return(false);
            }

            //Condition 1:
            //  The archive stream may no longer be in order and needs to be checked
            //Response:
            //  Resort the archive stream
            //
            //Condition 2:
            //  The end of the frame has been reached
            //Response:
            //  Advance to the next frame
            //  Also test the edge case where the current point might be equal to the end of the frame
            //      since this is an inclusive filter and ReadWhile is exclusive.
            //      If it's part of the frame, return true after Advancing the frame and the point.
            //

            //Since condition 1 and 2 can occur at the same time, verifying the sort of the Archive Stream is a good thing to do.
            // Will verify that the stream is in the proper order and remove any duplicates that were found.
            // May be called after every single read, but better to be called
            // when a ReadWhile function returns false.

            if (m_sortedArchiveStreams.Items.Length > 1)
            {
                //If list is no longer in order
                int compare = CompareStreams(m_sortedArchiveStreams[0], m_sortedArchiveStreams[1]);
                if (compare == 0) //A duplicate value was found.
                {
                    //If a duplicate entry is found, advance the position of the duplicate entry
                    RemoveDuplicatesFromList();
                    SetReadWhileUpperBoundsValue();

                    m_firstTable = m_sortedArchiveStreams[0];
                }
                else if (compare > 0) //List is out of order
                {
                    m_sortedArchiveStreams.SortAssumingIncreased(0);
                    m_firstTable = m_sortedArchiveStreams[0];
                    SetReadWhileUpperBoundsValue();
                }
            }
            else
            {
                //If only 1 stream, we can't resort, so we are done.
                if (!m_sortedArchiveStreams[0].IsValid)
                {
                    return(false);
                }
            }

            m_firstStream = null; //Ensure that the if block is executed when repeating this function call.
            goto TryAgain;
        }