Imports System.Reflection
Imports System.Drawing
Imports System.Windows.Forms
Imports Mercury.Mobile.Forms.Win32
Imports System.ComponentModel

''' <summary>
''' A control that displays data in a scrollable grid.
''' </summary>
''' <remarks></remarks>
Public Class DataGrid
    Inherits System.Windows.Forms.DataGrid

    ''' <summary>
    ''' Initializes a default instance of the <see cref="Mercury.Mobile.Forms.DataGrid"/> class.
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub New()
        If Not (Design.InDesignMode) Then
            Dim vsb As VScrollBar = Nothing
            For Each current As Control In MyBase.Controls
                If vsb Is Nothing Then _
                    vsb = TryCast(current, VScrollBar)
                If vsb IsNot Nothing Then _
                    Exit For
            Next
            WindowHook.Hook(vsb, AddressOf InternalWndProc)
            Me.m_vScroll = vsb
        End If
    End Sub

    Private WithEvents m_vScroll As VScrollBar
    Private _scrolling As Boolean
    Private _firstVisibleRow As Integer
    Private _deferredScrolling As Boolean

    ''' <summary>
    ''' Notifies the user that a scroll event has ended.
    ''' </summary>
    Public Event ScrollCompleted(ByVal sender As Object, ByVal e As EventArgs)

    ''' <summary>
    ''' Gets the index of the first visible row in the current view area.
    ''' </summary>
    ''' <returns>The index of the first visible row in the current view area.</returns>
    ''' <remarks></remarks>
    Public ReadOnly Property FirstVisibleRow() As Integer
        Get
            Return Me._firstVisibleRow
        End Get
    End Property

    Private Function InternalWndProc(ByVal hWnd As IntPtr, ByVal msg As UInteger, ByVal wParam As UInteger, ByVal lParam As Integer, ByRef handled As Boolean) As Integer
        handled = False
        Dim message = CType(msg, WM)
        If message = WM.LBUTTONDOWN Then
            Me._scrolling = True
        ElseIf message = WM.LBUTTONUP Then
            Me._scrolling = False
            Me.OnScrollCompleted(EventArgs.Empty)
        End If
    End Function

    Private Sub _VScrollChanged(ByVal sender As Object, ByVal e As EventArgs) Handles m_vScroll.ValueChanged
        Me._firstVisibleRow = Me.m_vScroll.Value
    End Sub

    Protected Overridable Sub OnScrollCompleted(ByVal e As EventArgs)
        RaiseEvent ScrollCompleted(Me, e)
    End Sub

    ''' <summary>
    ''' Sets the display row to the specified rowIndex.
    ''' </summary>
    ''' <param name="rowIndex">Index of the row to display.</param>
    ''' <remarks></remarks>
    Public Sub SetDisplayRow(ByVal rowIndex As Integer)
        Me.Select(rowIndex)
        Me.CurrentRowIndex = rowIndex
        Me.UnSelect(rowIndex)
    End Sub

    ''' <summary>
    ''' Gets the expected visible row count based on the client height and the preferred row height.
    ''' </summary>
    ''' <returns>The expected visible row count based on the client height and the preferred row height.</returns>
    ''' <remarks></remarks>
    Public Function CalculateVisibleRowCount() As Integer
        Return Math.Ceiling(Me.ClientSize.Height / Me.PreferredRowHeight)
    End Function

    'Private Sub _UnsafeReplaceVerticalScrollbar(ByVal value As VScrollBar)
    '    If value Is Nothing Then _
    '        Return
    '    Try
    '        Dim fi As FieldInfo = Me.GetType().GetField("m_sbVert", BindingFlags.NonPublic Or BindingFlags.GetField Or BindingFlags.Instance)
    '        Dim current = TryCast(fi.GetValue(Me), VScrollBar)
    '        fi.SetValue(Me, value)
    '        If current IsNot Nothing Then
    '            current.Visible = False
    '            current.Dispose()
    '        End If
    '    Catch ex As Exception
    '    End Try
    'End Sub

    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        MyBase.Dispose(disposing)
        Try
            If Me.m_vScroll IsNot Nothing AndAlso Not (Me.m_vScroll.IsDisposed) Then _
                Me.m_vScroll.Dispose()
        Catch ex As Exception
            ' Swallow all exceptions to prevent throwing inside of dispose
        End Try
    End Sub

End Class