Imports Mercury.Mobile.Data
Imports System.Threading
Imports System.Reflection

''' <summary>
''' A default item provider.
''' </summary>
''' <remarks></remarks>
Public Class DefaultItemProvider(Of T)
    Implements IVirtualizingItemProvider(Of T)

    Public Sub New(ByVal items As IList(Of T), ByVal comparer As PropertySortComparer(Of T))
        Me._items = items
        Me._comparer = comparer
    End Sub

    Private _comparer As PropertySortComparer(Of T)
    Private _items As IList(Of T)
    Private _view As IList(Of T)

    Public ReadOnly Property Items() As IList(Of T)
        Get
            If Me._view IsNot Nothing Then _
                Return Me._view
            Return Me._items
        End Get
    End Property

    Private _delay As TimeSpan = TimeSpan.Zero

    Public Property Delay() As TimeSpan
        Get
            Return Me._delay
        End Get
        Set(ByVal value As TimeSpan)
            Me._delay = value
        End Set
    End Property

    Public Sub Apply(ByVal info As Data.FilterInfo, ByVal sortExpression As System.Collections.Generic.IList(Of Data.SortField)) Implements Data.IVirtualizingItemProvider(Of T).Apply
        Me.SetView(info, sortExpression)
    End Sub

    Public Sub ClearFilters() Implements Data.IVirtualizingItemProvider(Of T).ClearFilters
        Me._view = Nothing
    End Sub

    Public Function FetchAll() As System.Collections.Generic.IList(Of T) Implements Data.IVirtualizingItemProvider(Of T).FetchAll
        Dim ct As Integer = 0
        Return Me.FetchRange(0, Me.Items.Count, ct)
    End Function

    Public Function FetchCount() As Integer Implements Data.IVirtualizingItemProvider(Of T).FetchCount
        Thread.Sleep(Me.Delay.TotalMilliseconds)
        Return Me.Items.Count
    End Function

    Public Function FetchRange(ByVal offset As Integer, ByVal length As Integer, ByRef count As Integer) As System.Collections.Generic.IList(Of T) Implements Data.IVirtualizingItemProvider(Of T).FetchRange
        Thread.Sleep(Me.Delay.TotalMilliseconds)
        count = Me.Items.Count
        Dim fetchList As New List(Of T)()
        If Me.Items IsNot Nothing Then
            Dim lesser = Math.Min(length, Me.Items.Count - offset)
            Dim finalLength = offset + lesser
            For i As Integer = offset To finalLength - 1
                fetchList.Add(Me.Items(i))
            Next
        End If
        Return fetchList
    End Function

    Private Sub SetView(ByVal info As FilterInfo, ByVal sortExpression As IList(Of SortField))
        ' Filter
        Dim pInfo As PropertyInfo = Nothing
        Dim currType = GetType(T)
        If info IsNot Nothing Then
            pInfo = currType.GetProperty(info.PropertyName, BindingFlags.Instance Or BindingFlags.Public)
        End If

        Dim newList As New List(Of T)()
        For Each itm As T In Me._items
            If IsFilterMatch(itm, info, pInfo) Then _
                newList.Add(itm)
        Next

        ' Sort
        If sortExpression IsNot Nothing AndAlso sortExpression.Count > 0 Then
            Dim current = sortExpression(0)
            Me._comparer.PropertyName = current.PropertyName
            Me._comparer.Direction = current.Direction
            newList.Sort(Me._comparer)
        End If

        Me._view = newList
    End Sub

    Private Shared Function IsFilterMatch(ByVal item As T, ByVal info As FilterInfo, ByVal pInfo As PropertyInfo) As Boolean
        If info Is Nothing Then _
            Return True
        If pInfo Is Nothing Then _
            Return False

        Dim current = pInfo.GetValue(item, Nothing)
        If current Is Nothing Then _
            Return False

        Return info.IsMatch(current.ToString())
    End Function

End Class