Imports System.ComponentModel
Imports System.Reflection
Imports System.Windows.Forms

Public Class MyDatagridview
    Inherits DataGridView
    Implements INotifyPropertyChanged

    Dim SQL_STR As String = ""
    Dim CONN_ART As String = ""
    Dim SQL_PARAM As List(Of SQLVariable) = Nothing

    Public RELOAD_PARAMS() As String = Nothing ' Die Spaltennamen, anhand dieser die Auswhal bei einem Reload wiederhergesatllt wird
    Dim RELOAD_PARAMS_Save As New List(Of VERAG_PROG_ALLGEMEIN.MyListItem)

    Property AKTUALISIERUNGS_INTERVALL As Integer = -1
    WithEvents timer As New Timer
    Public VALUE_CHANGED As Boolean = False

    Event RELOADED()

    ' Protected Overrides Sub OnCheckedChanged(ByVal e As EventArgs)
    '     Me.Checked = Me.Checked_value
    '  End Sub

    Dim SortColumn = Nothing
    Dim sel_row_index = -1
    Dim SortDirection As Windows.Forms.SortOrder
    Dim ScrollPos_X = Nothing
    Dim ScrollPos_Y = Nothing
    'Dim ScrollPos_Y2 = Nothing
    Dim SQL As New SQL

    Public Sub GetOrder()
        '   dataGridView1.HorizontalScrollingOffset = dataGridView1.HorizontalScrollingOffset + 10

        If Me.Columns.Count > 0 Then
            RELOAD_PARAMS_Save.Clear()
            If Me.SortedColumn IsNot Nothing Then
                SortColumn = Me.SortedColumn.Index
                SortDirection = Me.SortedColumn.HeaderCell.SortGlyphDirection
            End If
            ScrollPos_X = Me.HorizontalScrollingOffset
            ScrollPos_Y = Me.FirstDisplayedScrollingRowIndex  'Me.VerticalScrollingOffset

            'ScrollPos_Y2 = Me.VerticalScrollingOffset
            If Me.SelectedRows.Count > 0 Then
                sel_row_index = Me.SelectedRows(0).Index


                If RELOAD_PARAMS IsNot Nothing Then
                    For Each p In RELOAD_PARAMS
                        RELOAD_PARAMS_Save.Add(New VERAG_PROG_ALLGEMEIN.MyListItem(p, Me.SelectedRows(0).Cells(p).Value))
                    Next
                End If
            End If


        End If
    End Sub

    Protected Overrides Sub OnPaint(e As PaintEventArgs)
        Try
            MyBase.OnPaint(e)
            If AKTUALISIERUNGS_INTERVALL > 0 Then timer.Interval = AKTUALISIERUNGS_INTERVALL : timer.Enabled = True

        Catch ex As Exception
            Me.Invalidate()
        End Try
    End Sub

    Public Sub SET_SQL(SQL_STR As String, CONN_ART As String, Optional SQL_PARAM As List(Of SQLVariable) = Nothing, Optional RELOAD_PARAMS As String() = Nothing)
        Me.SQL_STR = SQL_STR
        Me.CONN_ART = CONN_ART
        Me.SQL_PARAM = SQL_PARAM
        Me.RELOAD_PARAMS = RELOAD_PARAMS
    End Sub

    Public Sub SetOrder()
        If Me.Columns.Count > 0 Then
            If SortColumn IsNot Nothing Then
                If SortDirection = Windows.Forms.SortOrder.Ascending Then
                    Me.Sort(Me.Columns(CInt(SortColumn)), ListSortDirection.Ascending)
                ElseIf SortDirection = Windows.Forms.SortOrder.Descending Then
                    Me.Sort(Me.Columns(CInt(SortColumn)), ListSortDirection.Descending)
                Else
                    Me.Sort(Me.Columns(CInt(SortColumn)))
                End If
            End If
            If ScrollPos_X IsNot Nothing Then Me.HorizontalScrollingOffset = ScrollPos_X
            Try
                '  Me.DataBind
                Me.FirstDisplayedScrollingRowIndex = ScrollPos_Y
            Catch ex As Exception
                'If ScrollPos_Y IsNot Nothing Then Me.HorizontalScrollBar.Value = ScrollPos_Y2

            End Try

            If RELOAD_PARAMS IsNot Nothing And RELOAD_PARAMS_Save.Count > 0 Then
                For Each r As DataGridViewRow In Me.Rows
                    Dim found = True
                    For Each p In RELOAD_PARAMS_Save
                        If r.Cells(p.Text).Value <> p.Value Then found = False
                    Next
                    If found Then
                        r.Selected = True

                        For Each c As DataGridViewCell In Me.Rows(sel_row_index).Cells
                            If c.Visible Then
                                Me.CurrentCell = c 'Damit der Cursor in der DGV richtig steht
                                Exit For
                            End If
                        Next
                        Exit For
                    End If

                Next
            Else
                If sel_row_index > 0 And Me.Rows.Count > sel_row_index Then
                    Me.ClearSelection()
                    Me.Rows(sel_row_index).Selected = True
                    For Each c As DataGridViewCell In Me.Rows(sel_row_index).Cells
                        If c.Visible Then
                            Me.CurrentCell = c 'Damit der Cursor in der DGV richtig steht
                            Exit For
                        End If
                    Next

                End If
            End If
        End If
    End Sub

    Public Sub LOAD(Optional showErr As Boolean = False, Optional ByRef errOccured As Boolean = False)
        If SQL_STR <> "" Then
            Me.DataSource = SQL.loadDgvBySql_Param(SQL_STR, CONN_ART, , SQL_PARAM, showErr, errOccured)
            Me._TRANSLATE()
        End If
    End Sub

    Public Sub RELOAD()
        GetOrder()
        LOAD()
        SetOrder()
        RaiseEvent RELOADED()
    End Sub

    Public Event PropertyChanged As PropertyChangedEventHandler _
      Implements INotifyPropertyChanged.PropertyChanged

    Protected Sub OnPropertyChanged(ByVal name As String)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(name))
    End Sub


    '  Private Sub MyDatagridview_Layout(sender As Object, e As LayoutEventArgs) Handles Me.Layout
    ' End Sub

    Private Sub timer_Tick(sender As Object, e As EventArgs) Handles timer.Tick
        If VALUE_CHANGED Then
            RELOAD()
            VALUE_CHANGED = False
        End If


    End Sub


    '_______________________________________________________________________________

#Region "Operations"

    Public Sub DefineSingleClickColumns(ParamArray columns As DataGridViewColumn())
        singleClickColumns.Clear()

        For Each column As DataGridViewColumn In columns
            If Me.Columns.IndexOf(column) = -1 Then
                Throw New ArgumentException("Instance of column (" + column.Name + ") is not in this DataGridView")
            End If

            singleClickColumns.Add(column)
        Next
    End Sub

    Public Sub DefineSingleClickColumns(ParamArray columnIndexes As Integer())
        singleClickColumns.Clear()

        For Each columnIndex As Integer In columnIndexes
            If columnIndex < 0 OrElse columnIndex >= Me.Columns.Count Then
                Throw New ArgumentOutOfRangeException("Column index (" + columnIndex + ") is out of range")
            End If

            singleClickColumns.Add(Me.Columns(columnIndex))
        Next
    End Sub

    Protected Sub BaseOnMouseDown(ByVal e As MouseEventArgs)
        MyBase.OnMouseDown(e)
    End Sub

#End Region


#Region "Overrides"

    Protected Overloads Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)
        ' If primary mouse button not down, do standard processing
        If e.Button <> MouseButtons.Left Then
            MyBase.OnMouseDown(e)

            Return
        End If

        ' Get info on where user clicked
        Dim hitInfo As DataGridView.HitTestInfo = HitTest(e.X, e.Y)

        ' If a cell wasn't clicked, column isn't text or it's read only, do standard processing
        If hitInfo.Type <> DataGridViewHitTestType.Cell OrElse Not (TypeOf Me.Columns(hitInfo.ColumnIndex) Is DataGridViewTextBoxColumn) OrElse Me.Columns(hitInfo.ColumnIndex).[ReadOnly] Then
            MyBase.OnMouseDown(e)

            Return
        End If

        ' If functionality enabled for specific columns and column clicked is not
        ' one of these, do standard processing
        If singleClickColumns.Count >= 1 AndAlso singleClickColumns.IndexOf(Me.Columns(hitInfo.ColumnIndex)) = -1 Then
            MyBase.OnMouseDown(e)

            Return
        End If

        ' Get clicked cell
        Dim clickedCell As DataGridViewCell = Me.Rows(hitInfo.RowIndex).Cells(hitInfo.ColumnIndex)

        ' If cell not current, try and make it so
        If CurrentCell IsNot clickedCell Then
            ' Allow standard processing make clicked cell current
            MyBase.OnMouseDown(e)

            ' If this didn't happen (validation failed etc), abort
            If Me.CurrentCell IsNot clickedCell Then
                Return
            End If
        End If

        ' If already in edit mode, do standard processing (will position caret)
        If Me.CurrentCell.IsInEditMode Then
            MyBase.OnMouseDown(e)

            Return
        End If

        ' Enter edit mode
        Me.BeginEdit(False)

        If Me.EditingControl IsNot Nothing Then

            ' Ensure text is scrolled to the left
            Dim textBox As TextBoxBase = DirectCast(Me.EditingControl, TextBoxBase)

            textBox.SelectionStart = 0

            textBox.ScrollToCaret()

            ' Position caret by simulating a mouse click within control
            Dim editOffset As Integer = e.X - hitInfo.ColumnX - Me.EditingControl.Left

            Dim lParam As Int32 = MakeLong(editOffset, 0)

            SendMessage(Me.EditingControl.Handle, WM_LBUTTONDOWN, 0, lParam)

            SendMessage(Me.EditingControl.Handle, WM_LBUTTONUP, 0, lParam)
        End If
    End Sub

#End Region

#Region "Implementation"

    Const WM_LBUTTONDOWN As Integer = 513

    Const WM_LBUTTONUP As Integer = 514

    <System.Runtime.InteropServices.DllImport("user32.dll")> _
    Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal msg As Int32, ByVal wParam As Int32, ByVal lParam As Int32) As Boolean
    End Function

    Private singleClickColumns As New List(Of DataGridViewColumn)()

    Private Function MakeLong(ByVal loWord As Integer, ByVal hiWord As Integer) As Integer
        Return (hiWord << 16) Or (loWord And 65535)
    End Function

#End Region



    Public Sub _TRANSLATE()
        Try

            If VERAG_PROG_ALLGEMEIN.cAllgemein._LAN = "" Then Exit Sub
            If VERAG_PROG_ALLGEMEIN.cAllgemein._LAN = "DE" Then Exit Sub

            Dim lanTxtAll = VERAG_PROG_ALLGEMEIN.cAllgemein.TRANSLATE.list.FindAll(Function(x) x.trs_object = Me.FindForm.Name And x.trs_control = Me.Name And x.trs_sprache = VERAG_PROG_ALLGEMEIN.cAllgemein._LAN)
            If lanTxtAll.Count > 0 Then
                For Each txt In lanTxtAll
                    If Me.Columns(txt.trs_subControl) IsNot Nothing Then
                        Me.Columns(txt.trs_subControl).HeaderText = txt.trs_text
                    End If
                Next
            End If

        Catch ex As Exception
            MsgBox(ex.Message & ex.StackTrace)
        End Try
    End Sub


End Class
