Imports System.ComponentModel
Imports System.Threading
Imports Mercury.Mobile.Threading

Namespace Data

    ''' <summary>
    ''' A view of an asynchronous, virtualizing container collection.
    ''' </summary>
    ''' <typeparam name="T">The type of the items referenced by this view.</typeparam>
    ''' <remarks></remarks>
    Public Class AsyncListView(Of T)
        Inherits AsyncVirtualContainerCollection(Of T)
        Implements ITypedList, IBindingList

#Region "Constructors"

        ''' <summary>
        ''' Initializes a new instance of the AsyncListView(Of T) 
        ''' class with the specified item provider.
        ''' </summary>
        ''' <param name="itemProvider">The provider interface for retrieving virtualized items.</param>
        Public Sub New(ByVal itemProvider As IVirtualizingItemProvider(Of T))
            MyBase.New(itemProvider)
        End Sub

        ''' <summary>
        ''' Initializes a new instance of the AsyncListView(Of T) 
        ''' class with the specified item provider and page size.
        ''' </summary>
        ''' <param name="itemProvider">The provider interface for retrieving virtualized items.</param>
        ''' <param name="pageSize">The number of elements in a page.</param>
        Public Sub New(ByVal itemProvider As IVirtualizingItemProvider(Of T), ByVal pageSize As Integer)
            MyBase.New(itemProvider, pageSize)
        End Sub

        ''' <summary>
        ''' Initializes a new instance of the AsyncListView(Of T) class 
        ''' with the specified item provider, page size, and timeout.
        ''' </summary>
        ''' <param name="itemProvider">The provider interface for retrieving virtualized items.</param>
        ''' <param name="pageSize">The number of elements in a page.</param>
        ''' <param name="pageTimeout">The number of milliseconds before the cached page invalidates.</param>
        ''' <remarks></remarks>
        Public Sub New(ByVal itemProvider As IVirtualizingItemProvider(Of T), ByVal pageSize As Integer, ByVal pageTimeout As Long)
            MyBase.New(itemProvider, pageSize, pageTimeout)
        End Sub

        ''' <summary>
        ''' Initializes a new instance of the AsyncListView(Of T) class with the specified 
        ''' item provider, page size, timeout, and synchronization context.
        ''' </summary>
        ''' <param name="itemProvider">The provider interface for retrieving virtualized items.</param>
        ''' <param name="pageSize">The number of elements in a page.</param>
        ''' <param name="pageTimeout">The number of milliseconds before the cached page invalidates.</param>
        ''' <param name="synchronizationContext">A Mercury.Mobile.Threading.ISynchronizationContext that 
        ''' can be used to synchronize access to the virtualizing collection.</param>
        ''' <remarks></remarks>
        Public Sub New(ByVal itemProvider As IVirtualizingItemProvider(Of T), ByVal pageSize As Integer, _
                       ByVal pageTimeout As Long, ByVal synchronizationContext As ISynchronizationContext)
            MyBase.New(itemProvider, pageSize, pageTimeout, synchronizationContext)
        End Sub

        ''' <summary>
        ''' Initializes a new instance of the AsyncListView(Of T) class with the specified 
        ''' item provider, page size, timeout, and synchronization context.
        ''' </summary>
        ''' <param name="itemProvider">The provider interface for retrieving virtualized items.</param>
        ''' <param name="pageSize">The number of elements in a page.</param>
        ''' <param name="pageTimeout">The number of milliseconds before the cached page invalidates.</param>
        ''' <param name="synchronizationContext">A Mercury.Mobile.Threading.ISynchronizationContext that 
        ''' can be used to synchronize access to the virtualizing collection.</param>
        ''' <param name="throwOnUnsupported">A value indicating whether to throw an error on an unsupported method.</param>
        ''' <remarks></remarks>
        Public Sub New(ByVal itemProvider As IVirtualizingItemProvider(Of T), ByVal pageSize As Integer, _
                       ByVal pageTimeout As Long, ByVal synchronizationContext As ISynchronizationContext, _
                       ByVal throwOnUnsupported As Boolean)
            MyBase.New(itemProvider, pageSize, pageTimeout, synchronizationContext)
            Me._throwOnUnsupported = throwOnUnsupported
        End Sub

#End Region

#Region "Collection Changed"

        ''' <summary>
        ''' Suggests a requery of the virtual collection for the items in the specified range.
        ''' </summary>
        ''' <param name="startIndex">The index of the first item in the range.</param>
        ''' <param name="endIndex">The index of the last item in the range.</param>
        ''' <remarks></remarks>
        Public Overloads Sub SuggestRequery(ByVal startIndex As Integer, ByVal endIndex As Integer)
            For i As Integer = startIndex To endIndex
                Me.OnListChanged(New NotifyListChangedEventArgs(ListChangedType.ItemChanged, Nothing, i))
            Next
        End Sub

        Protected Overrides Sub OnCollectionReset(ByVal e As System.EventArgs)
            MyBase.OnCollectionReset(e)
            Me.OnListChanged(AsyncListView(Of T).ResetEventArgs)
        End Sub

        Protected Overridable Sub OnListChanged(ByVal e As ListChangedEventArgs)
            Dim flag = (Me.ListChangedEvent Is Nothing)
            RaiseEvent ListChanged(Me, e)
        End Sub

        Friend Sub RaiseListChanged(ByVal e As ListChangedEventArgs)
            Me.OnListChanged(e)
        End Sub

        Friend Shared ResetEventArgs As ListChangedEventArgs = New ListChangedEventArgs(ListChangedType.Reset, -1)

#End Region

#Region "IBindingList"

        ''' <summary>
        ''' For a description of this member, see <see cref="IBindingList"/>.
        ''' </summary>
        ''' <param name="property">For a description of this member, see <see cref="IBindingList"/>.</param>
        ''' <remarks></remarks>
        Public Sub AddIndex(ByVal [property] As System.ComponentModel.PropertyDescriptor) Implements System.ComponentModel.IBindingList.AddIndex
            If Me.ThrowOnUnsupported Then _
                Throw New NotSupportedException()
        End Sub

        ''' <summary>
        ''' Adds a new record view.
        ''' </summary>
        ''' <returns>The record view that was added.</returns>
        ''' <remarks></remarks>
        Public Function AddNew() As Object Implements System.ComponentModel.IBindingList.AddNew
            If Me.ThrowOnUnsupported Then _
                Throw New NotSupportedException()
            Return Nothing
        End Function

        Private ReadOnly Property AllowEditBinding() As Boolean Implements System.ComponentModel.IBindingList.AllowEdit
            Get
                Return False
            End Get
        End Property

        Private ReadOnly Property AllowNewBinding() As Boolean Implements System.ComponentModel.IBindingList.AllowNew
            Get
                Return False
            End Get
        End Property

        Private ReadOnly Property AllowRemoveBinding() As Boolean Implements System.ComponentModel.IBindingList.AllowRemove
            Get
                Return False
            End Get
        End Property

        ''' <summary>
        ''' Sorts the recordset on the specified property and direction.
        ''' </summary>
        ''' <param name="property">The property on which to sort.</param>
        ''' <param name="direction">The direction of the sort.</param>
        ''' <remarks></remarks>
        Public Sub ApplySort(ByVal [property] As System.ComponentModel.PropertyDescriptor, ByVal direction As System.ComponentModel.ListSortDirection) Implements System.ComponentModel.IBindingList.ApplySort
            If Me.ThrowOnUnsupported Then _
                Throw New NotSupportedException()
        End Sub

        ''' <summary>
        ''' For a description of this member, see <see cref="IBindingList"/>.
        ''' </summary>
        ''' <param name="property">For a description of this member, see <see cref="IBindingList"/>.</param>
        ''' <param name="key">For a description of this member, see <see cref="IBindingList"/>.</param>
        ''' <returns>For a description of this member, see <see cref="IBindingList"/>.</returns>
        ''' <remarks></remarks>
        Public Function Find(ByVal [property] As System.ComponentModel.PropertyDescriptor, ByVal key As Object) As Integer Implements System.ComponentModel.IBindingList.Find
            If Me.ThrowOnUnsupported Then _
                Throw New NotSupportedException()
            Return Nothing
        End Function

        Private _isSorted As Boolean

        ''' <summary>
        ''' Gets a value indicating whether the view is sorted.
        ''' </summary>
        ''' <returns>True if the view is sorted; otherwise, false.</returns>
        ''' <remarks></remarks>
        Public ReadOnly Property IsSorted() As Boolean Implements System.ComponentModel.IBindingList.IsSorted
            Get
                Return Me._isSorted
            End Get
        End Property

        Public Event ListChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ListChangedEventArgs) Implements System.ComponentModel.IBindingList.ListChanged

        ''' <summary>
        ''' For a description of this member, see <see cref="IBindingList"/>.
        ''' </summary>
        ''' <param name="property">For a description of this member, see <see cref="IBindingList"/>.</param>
        ''' <remarks></remarks>
        Public Sub RemoveIndex(ByVal [property] As System.ComponentModel.PropertyDescriptor) Implements System.ComponentModel.IBindingList.RemoveIndex
            If Me.ThrowOnUnsupported Then _
                Throw New NotSupportedException()
        End Sub

        ''' <summary>
        ''' Removes the previously applied sort.
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub RemoveSort() Implements System.ComponentModel.IBindingList.RemoveSort
            If Me.ThrowOnUnsupported Then _
                Throw New NotSupportedException()
        End Sub

        Private _sortDirection As ListSortDirection

        ''' <summary>
        ''' Gets the direction of an ApplySort() operation.
        ''' </summary>
        ''' <returns>The direction of an ApplySort() operation.</returns>
        ''' <remarks></remarks>
        Public ReadOnly Property SortDirection() As System.ComponentModel.ListSortDirection Implements System.ComponentModel.IBindingList.SortDirection
            Get
                Return Me._sortDirection
            End Get
        End Property

        Private _sortProperty As PropertyDescriptor

        ''' <summary>
        ''' Gets the property on which to sort.
        ''' </summary>
        ''' <returns>The property on which to sort.</returns>
        ''' <remarks></remarks>
        Public ReadOnly Property SortProperty() As System.ComponentModel.PropertyDescriptor Implements System.ComponentModel.IBindingList.SortProperty
            Get
                Return Me._sortProperty
            End Get
        End Property

        ''' <summary>
        ''' Gets a value indicating whether change notifications are supported.
        ''' </summary>
        ''' <returns>True if the view supports change notifications; otherwise, false.</returns>
        ''' <remarks></remarks>
        Public ReadOnly Property SupportsChangeNotification() As Boolean Implements System.ComponentModel.IBindingList.SupportsChangeNotification
            Get
                Return True
            End Get
        End Property

        ''' <summary>
        ''' Gets a value indicating whether searching is supported.
        ''' </summary>
        ''' <returns>True if searching is supported; otherwise, false.</returns>
        ''' <remarks></remarks>
        Public ReadOnly Property SupportsSearching() As Boolean Implements System.ComponentModel.IBindingList.SupportsSearching
            Get
                Return False
            End Get
        End Property

        ''' <summary>
        ''' Gets a value indicating whether sorting is supported.  Implemented to prevent errors.
        ''' </summary>
        ''' <returns>True if the view supports sorting; otherwise, false.</returns>
        ''' <remarks></remarks>
        Public ReadOnly Property SupportsSorting() As Boolean Implements System.ComponentModel.IBindingList.SupportsSorting
            Get
                Return True
            End Get
        End Property

#End Region

#Region "ITypedList"

        Private _reflectedProperties As ReflectedProperties(Of T) = New ReflectedProperties(Of T)(AddressOf _RedirectPropertyGetValue, Nothing, True)

        ''' <summary>
        ''' Returns  the System.ComponentModel.PropertyDescriptorCollection 
        ''' that represents the properties on each item used to bind data.
        ''' </summary>
        ''' <param name="listAccessors">An array of System.ComponentModel.PropertyDescriptor 
        ''' objects to find in the collection as bindable. This can be null.</param>
        ''' <returns>The System.ComponentModel.PropertyDescriptorCollection 
        ''' that represents the properties on each item used to bind data.</returns>
        ''' <remarks></remarks>
        Public Function GetItemProperties(ByVal listAccessors() As System.ComponentModel.PropertyDescriptor) As System.ComponentModel.PropertyDescriptorCollection Implements System.ComponentModel.ITypedList.GetItemProperties
            If Me._reflectedProperties IsNot Nothing Then _
                Return Me._reflectedProperties.Descriptors
            Return New PropertyDescriptorCollection(Nothing)
        End Function

        ''' <summary>
        ''' Returns the name of the list.
        ''' </summary>
        ''' <param name="listAccessors">An array of System.ComponentModel.PropertyDescriptor 
        ''' objects, for which the list name is returned. This can be null.</param>
        ''' <returns>The name of the list.</returns>
        ''' <remarks></remarks>
        Public Function GetListName(ByVal listAccessors() As System.ComponentModel.PropertyDescriptor) As String Implements System.ComponentModel.ITypedList.GetListName
            Return String.Empty
        End Function

        Private Function _RedirectPropertyGetValue(ByVal propertyName As String, ByVal component As Object) As Object
            Dim container = TryCast(component, DataContainer(Of T))
            If container IsNot Nothing Then _
                Return Me._reflectedProperties.GetReflectedPropertyValue(propertyName, container.Data)
            Return Nothing
        End Function

#End Region

        Private _throwOnUnsupported As Boolean = True

        ''' <summary>
        ''' Gets a value indicating whether to throw an error on an unsupported method.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property ThrowOnUnsupported() As Boolean
            Get
                Return Me._throwOnUnsupported
            End Get
        End Property

        Default Public Overrides Property Item(ByVal index As Integer) As DataContainer(Of T)
            Get
                Dim current = MyBase.Item(index)
                Return current
            End Get
            Set(ByVal value As DataContainer(Of T))
                MyBase.Item(index) = value
            End Set
        End Property

        Protected Overrides Sub UntypedCopyTo(ByVal array As System.Array, ByVal index As Integer)
            'If Me.ThrowOnUnsupported Then _
            '    Throw New NotSupportedException()
        End Sub

    End Class

End Namespace