
Namespace Data

    ''' <summary>
    ''' An object representing a page of data.
    ''' </summary>
    ''' <remarks></remarks>
    Public NotInheritable Class DataPage(Of T)

        ''' <summary>
        ''' Initializes a new instance of the DataPage(Of T) class with the specified index and page length.
        ''' </summary>
        ''' <param name="firstIndex">The first index contained in this page.</param>
        ''' <param name="pageLength">The maximum number of elements allowed in this page.</param>
        ''' <param name="virtualizeExplicit">A value indicating whether containers can be explicitly marked to virtualize.</param>
        ''' <remarks></remarks>
        Public Sub New(ByVal firstIndex As Integer, ByVal pageLength As Integer, ByVal virtualizeExplicit As Boolean)
            Me.VirtualizeExplicit = virtualizeExplicit
            Me.Items = New List(Of DataContainer(Of T))(pageLength)
            For i As Integer = 0 To pageLength - 1
                Me.Items.Add(Me.GetContainer(firstIndex + i))
            Next
            Me.TouchTime = GlobalDateTime.Now
        End Sub

        Private _items As IList(Of DataContainer(Of T))

        ''' <summary>
        ''' Gets or sets a list of data page item containers.
        ''' </summary>
        ''' <returns>A list of data page item containers.</returns>
        ''' <remarks></remarks>
        Public Property Items() As IList(Of DataContainer(Of T))
            Get
                Return Me._items
            End Get
            Set(ByVal value As IList(Of DataContainer(Of T)))
                Me._items = value
            End Set
        End Property

        Private _virtualizeExplicit As Boolean

        ''' <summary>
        ''' Gets or sets a value indicating whether containers can be explicitly marked to virtualize.
        ''' </summary>
        ''' <returns>True if containers can be explicitly marked to virtualize; otherwise, false.</returns>
        ''' <remarks></remarks>
        Public Property VirtualizeExplicit() As Boolean
            Get
                Return Me._virtualizeExplicit
            End Get
            Set(ByVal value As Boolean)
                Me._virtualizeExplicit = value
            End Set
        End Property

        Private _touchTime As DateTime

        ''' <summary>
        ''' Gets or sets a date and time at which this page was last accessed.
        ''' </summary>
        ''' <returns>A date and time at which this page was last accessed.</returns>
        ''' <remarks></remarks>
        Public Property TouchTime() As DateTime
            Get
                Return Me._touchTime
            End Get
            Set(ByVal value As DateTime)
                Me._touchTime = value
            End Set
        End Property

        ''' <summary>
        ''' Gets a value indicating whether this page is still in use.
        ''' </summary>
        ''' <returns>True if the page or any of its items are still in use; otherwise, false.</returns>
        ''' <remarks></remarks>
        Public ReadOnly Property IsInUse() As Boolean
            Get
                If Me.Items IsNot Nothing Then _
                    Return (Me.Items.Any(Function(itm) itm.IsInUse))
                Return False
            End Get
        End Property

        ''' <summary>
        ''' Gets a value indicating whether this page can be virtualized.
        ''' </summary>
        ''' <returns>True if this page can be virtualized; otherwise, false.</returns>
        ''' <remarks></remarks>
        Public ReadOnly Property CanVirtualize() As Boolean
            Get
                If Me.Items IsNot Nothing Then _
                    Return Not (Me.Items.Any(Function(itm) Not (itm.CanVirtualize)))
                Return False
            End Get
        End Property

        ''' <summary>
        ''' Returns the index of the specified item.
        ''' </summary>
        ''' <param name="data">The data item to find.</param>
        ''' <returns>The index of the specified item or -1 if not found.</returns>
        ''' <remarks></remarks>
        Public Function IndexOfData(ByVal data As T) As Integer
            Dim container As DataContainer(Of T) = Nothing
            For i As Integer = 0 To Me.Items.Count - 1
                container = Me.Items(i)
                If DataContainer(Of T).DataEquals(container.Data, data) Then _
                    Return i
            Next
            Return -1
        End Function

        ''' <summary>
        ''' Returns a value indicating whether the page data has expired.
        ''' </summary>
        ''' <param name="timeout">The timeout value for the page.</param>
        ''' <returns>True if the page has expired; otherwise, false.</returns>
        ''' <remarks></remarks>
        Public Function HasExpired(ByVal timeout As Long) As Boolean
            Dim diff As Long = GlobalDateTime.Now.Subtract(Me._touchTime).TotalMilliseconds
            If diff > timeout Then _
                Return True
            Return False
        End Function

        ''' <summary>
        ''' Populates the page with the specified data items.
        ''' </summary>
        ''' <param name="newItems">The data items to populate.</param>
        ''' <remarks></remarks>
        Public Sub Populate(ByVal newItems As IList(Of T))
            Dim i As Integer = 0
            Dim index As Integer = 0

            ' Update current item containers
            For i = 0 To newItems.Count - 1
                If i >= Me.Items.Count Then _
                    Exit For
                Me.Items(i).SetData(newItems(i))
                index = Me.Items(i).Index
            Next

            ' Add item containers
            Dim container As DataContainer(Of T) = Nothing
            Do While (i < newItems.Count)
                index += 1
                container = Me.GetContainer(index)
                container.SetData(newItems(i))
                Me.Items.Add(container)
                i += 1
            Loop

            ' Remove extra containers
            Do While (i < Me.Items.Count)
                Me.Items.RemoveAt(Me.Items.Count - 1)
            Loop
        End Sub

        ''' <summary>
        ''' Gets a new data container initialized with the specified index.
        ''' </summary>
        ''' <param name="index">The initial index to set.</param>
        ''' <returns>A new Mercury.Mobile.Data.DataContainer(of T) object initialized with the specified index.</returns>
        ''' <remarks></remarks>
        Public Function GetContainer(ByVal index As Integer) As DataContainer(Of T)
            Return DataPage(Of T).CreateDataContainer(index, Me.VirtualizeExplicit)
        End Function

        ''' <summary>
        ''' Returns a data container created with the specified index and virtualize values.
        ''' </summary>
        ''' <param name="index">The initial index to set.</param>
        ''' <param name="virtualize">A value indicating whether the container can virtualize.</param>
        ''' <returns>A Mercury.Mobile.Data.DataContainer(of T) object created with the specified index and virtualize values.</returns>
        ''' <remarks></remarks>
        Public Shared Function CreateDataContainer(ByVal index As Integer, ByVal virtualize As Boolean) As DataContainer(Of T)
            Dim container = New DataContainer(Of T)(index)
            container.Virtualize(virtualize)
            Return container
        End Function

    End Class

End Namespace