Imports DevExpress.Xpf.Grid.Native
Imports DevExpress.Xpf.Grid
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Data
Imports System.Windows.Documents
Imports System.Windows.Input
Imports System.Windows.Media
Imports System.Windows.Media.Imaging
Imports System.Windows.Shapes
Imports DevExpress.Xpf.Core
Imports DevExpress.Xpf.Bars

Imports DevExpress.Xpf.Printing
Imports System.ComponentModel
Imports System.Collections.ObjectModel
Imports System.Collections
Imports DevExpress.Xpf.Core.Serialization
Imports DevExpress.Data
Imports tsl5.Extensiones
Imports System.Globalization

Public Class tsGridControl
    Inherits DevExpress.Xpf.Grid.GridControl
    Public ElementosSeleccionados As ObservableCollectionCore(Of Object)
    Public Property PopupFilterModeInicializado As Boolean
    Public Property EjecutarDeleteRowAlEliminar As Boolean = True


    Public ReadOnly Property MySelectedItems() As IList
        Get
            Return ElementosSeleccionados
        End Get
    End Property



    Private _NombreTablaBase As String

    Public Property PropiedadesTS As New PropiedadesTS
    Public Property PropiedadesTSGC As New PropiedadesTSGC

    Public Sub EstableceSoloLectura(Optional SoloLectura As Boolean = True)
        For Each c In Me.Columns
            If c.CellTemplate Is Nothing Then
                c.ReadOnly = SoloLectura
            Else
                c.AllowEditing = If(SoloLectura, DevExpress.Utils.DefaultBoolean.False, DevExpress.Utils.DefaultBoolean.True)
            End If
            Dim bes = TryCast(c.EditSettings, DevExpress.Xpf.Editors.Settings.ButtonEditSettings)
            If bes IsNot Nothing Then
                bes.AllowDefaultButton = Not SoloLectura
                For Each bt In bes.Buttons
                    bt.IsEnabled = Not SoloLectura
                Next
            End If
        Next
        If Not Me.ContextMenu Is Nothing AndAlso Me.ContextMenu.HasItems Then
            Dim mi As MenuItem = Me.ContextMenu.Items(0)
            mi.IsEnabled = Not SoloLectura
        End If
    End Sub
    Public Sub ReEstableceValoresDefectoSoloLectura()
        For Each c In Me.Columns
            If c.CellTemplate Is Nothing Then
                If c.GetType Is GetType(tsGridColumn) Then
                    c.ReadOnly = DirectCast(c, tsGridColumn).SoloLectura
                    Dim bes = TryCast(c.EditSettings, DevExpress.Xpf.Editors.Settings.ButtonEditSettings)
                    If bes IsNot Nothing Then
                        bes.AllowDefaultButton = Not c.ReadOnly
                        For Each bt In bes.Buttons
                            bt.IsEnabled = Not c.ReadOnly
                        Next
                    End If
                Else
                    c.ReadOnly = False
                End If
            Else
                If c.GetType Is GetType(tsGridColumn) Then
                    If DirectCast(c, tsGridColumn).SoloLectura Then
                        If c.CellTemplate Is Nothing Then
                            c.ReadOnly = True
                        Else
                            c.AllowEditing = DevExpress.Utils.DefaultBoolean.False
                        End If
                        Dim bes = TryCast(c.EditSettings, DevExpress.Xpf.Editors.Settings.ButtonEditSettings)
                        If bes IsNot Nothing Then
                            bes.AllowDefaultButton = False
                            For Each bt In bes.Buttons
                                bt.IsEnabled = False
                            Next
                        End If
                    Else
                        c.AllowEditing = DevExpress.Utils.DefaultBoolean.True
                        Dim bes = TryCast(c.EditSettings, DevExpress.Xpf.Editors.Settings.ButtonEditSettings)
                        If bes IsNot Nothing Then
                            bes.AllowDefaultButton = True
                            For Each bt In bes.Buttons
                                bt.IsEnabled = True
                            Next
                        End If
                    End If
                Else
                    If c.CellTemplate Is Nothing Then
                        c.ReadOnly = True
                    Else
                        c.AllowEditing = DevExpress.Utils.DefaultBoolean.False
                    End If
                End If
            End If
        Next

    End Sub

    Public Property NombreTablaBase As String
        Get
            Return _NombreTablaBase
        End Get
        Set(value As String)
            _NombreTablaBase = value
        End Set
    End Property
    Public Event AntesEliminar(ByVal gc As tsGridControl, ByRef Cancelar As Boolean)
    Public Event DespuesEliminar(ByVal gc As tsGridControl)
    Public Event EnterPulsado()
    Public Event SeleccionCambiada(ByVal gc As tsGridControl, e As GridSelectionChangedEventArgs)
    Public Event AntesExportar(ByVal gc As tsGridControl, ByRef Cancelar As Boolean)

    Property ComandoDelegado As DevExpress.Mvvm.DelegateCommand(Of Object)

    Friend Function LanzaAntesExportar(gc As tsGridControl) As Boolean
        Dim Cancelar As Boolean
        RaiseEvent AntesExportar(gc, Cancelar)
        Return Cancelar
    End Function
    Friend Function LanzaAntesEliminar(gc As tsGridControl) As Boolean
        Dim Cancelar As Boolean
        RaiseEvent AntesEliminar(gc, Cancelar)
        Return Cancelar
    End Function

    Friend Function LanzaDespuesEliminar(gc As tsGridControl) As Boolean
        Dim Cancelar As Boolean
        RaiseEvent DespuesEliminar(gc)
        Return Cancelar
    End Function
    Friend Function LanzaEnterPulsado() As Boolean
        Dim Cancelar As Boolean
        RaiseEvent EnterPulsado()
        Return Cancelar
    End Function
    Public Sub New()
        MyBase.New()
    End Sub
    Private NumeroColumnasAgrupadas As Integer
    Friend Sub MyGridControl_StartGrouping(sender As Object, e As RoutedEventArgs)

        updateLocker.Lock()
    End Sub
    Public Function ObtieneNumeroColumnasAgrupadas() As Integer
        Return Me.Columns.Where(Function(x) x.IsGrouped).Count
    End Function
    Friend Sub MyGridControl_EndGrouping(sender As Object, e As RoutedEventArgs)
        'Dim nca = ObtieneNumeroColumnasAgrupadas()
        'Dim bDesAgrupando As Boolean = NumeroColumnasAgrupadas > nca
        'NumeroColumnasAgrupadas = nca
        'If bDesAgrupando Then updateLocker.Unlock()
        BeginSelection()
        For Each index As Integer In OrderedSelection
            If CBool(selection(index)) Then
                SelectItem(GetRowHandleByListIndex(index))
            End If
        Next
        EndSelection()
        '     If Not bDesAgrupando Then updateLocker.Unlock()
        updateLocker.Unlock()
    End Sub

    Private selection As New Hashtable()
    Private ReadOnly Property OrderedSelection() As IEnumerable
        Get
            Return selection.Keys.Cast(Of Integer)().OrderBy(Function(x) x)
        End Get
    End Property
    Protected Overrides Sub OnItemsSourceChanged(oldValue As Object, newValue As Object)
        MyBase.OnItemsSourceChanged(oldValue, newValue)
        selection.Clear()
        Dim itemsSource As IEnumerable = TryCast(newValue, IEnumerable)
        If itemsSource Is Nothing Then
            Return
        End If
        Dim i As Integer = 0
        For Each item As Object In itemsSource
            selection(System.Math.Max(System.Threading.Interlocked.Increment(i), i - 1)) = False
        Next
    End Sub
    Protected Overrides Sub OnInitialized(e As EventArgs)
        MyBase.OnInitialized(e)
        Try
            '  If Me.SelectionMode = MultiSelectMode.MultipleRow Then
            AddHandler SelectionChanged, AddressOf MyGridControl_SelectionChanged
            ElementosSeleccionados = New ObservableCollectionCore(Of Object)()
            AddHandler Me.EndGrouping, AddressOf MyGridControl_EndGrouping
            AddHandler Me.StartGrouping, AddressOf MyGridControl_StartGrouping
            If Me.PropiedadesTSGC.BusquedaAcentosInsensitivo Or Configuracion.BusquedaAcentosInsensitivo Then AddHandler Me.CustomRowFilter, AddressOf MyGridControl_CustomRowFilter
            ConSeleccion = True
            ''''       NumeroColumnasAgrupadas = ObtieneNumeroColumnasAgrupadas()
            '  End If
            If Me.View IsNot Nothing Then
                If Me.View.GetType Is GetType(TableView) OrElse Me.View.GetType Is GetType(tsTableView) Then
                    DirectCast(Me.View, TableView).AllowFixedColumnMenu = True
                    ''''  DirectCast(Me.View, TableView).UseLightweightTemplates = UseLightweightTemplates.None
                    ''''  DirectCast(Me.View, TableView).GroupSummaryContentStyle = DirectCast(Me.FindResource("tsGroupSummaryContentStyle"), Style)
                    ''''  DirectCast(Me.View, TableView).TotalSummaryContentStyle = DirectCast(Me.FindResource("tsTotalSummaryContentStyle"), Style)
                End If
                If Configuracion.ModoBusquedaAND Then
                    '  Me.View.SearchPanelCriteriaOperatorType = DevExpress.Xpf.Editors.CriteriaOperatorType.And
                    Me.View.SearchPanelParseMode = DevExpress.Xpf.Editors.SearchPanelParseMode.And
                End If
                DirectCast(Me.View, GridViewBase).SearchPanelPosition = SearchPanelPosition.OverGroupPanel
            End If
        Catch ex As Exception
            Debug.Write(ex.Message)
        End Try
    End Sub

    Private Sub MyGridControl_CustomRowFilter(sender As Object, e As RowFilterEventArgs)
        Dim gc As GridControl = TryCast(sender, GridControl)
        If gc.ItemsSource IsNot Nothing Then
            If gc IsNot Nothing Then
                Dim filterStr As String = gc.View.SearchString.NothingAVacio
                If filterStr <> "" Then
                    Dim Palabras = RemoveDiacriticsCustom(filterStr.ToLowerInvariant).Split(" ")
                    e.Visible = False
                    e.Handled = True
                    For Each c As GridColumn In gc.Columns
                        Dim value As String = RemoveDiacriticsCustom(gc.GetCellDisplayText(gc.GetRowHandleByListIndex(e.ListSourceRowIndex), c).ToLowerInvariant)
                        If c.Visible Then
                            For Each p In Palabras
                                If value.Contains(p) Then
                                    e.Visible = True
                                    Exit For
                                End If
                            Next
                            If e.Visible Then Exit For
                        End If
                    Next
                End If
            End If
        End If
    End Sub
    Private Shared Function RemoveDiacriticsCustom(ByVal text As String) As String
        Return String.Concat(text.Normalize(NormalizationForm.FormD).Where(Function(ch) CharUnicodeInfo.GetUnicodeCategory(ch) <> UnicodeCategory.NonSpacingMark)).Normalize(NormalizationForm.FormC)
    End Function

    Public Sub DeshabilitaSeleccionMultiple()
        RemoveHandler SelectionChanged, AddressOf MyGridControl_SelectionChanged
        RemoveHandler Me.EndGrouping, AddressOf MyGridControl_EndGrouping
        RemoveHandler Me.StartGrouping, AddressOf MyGridControl_StartGrouping
        ConSeleccion = False
    End Sub




    Private updateLocker As New Locker()

    'Public Sub SeleccionaTodo()
    '    Me.SelectAll()
    '    MyGridControl_SelectionChanged(Me, Nothing)
    'End Sub
    Friend Sub MyGridControl_SelectionChanged(sender As Object, e As GridSelectionChangedEventArgs)
        Try
            If ConSeleccion AndAlso Not updateLocker.IsLocked Then
                Dim drhws = GetDataRowHandles()

                'For i As Integer = 0 To VisibleRowCount - 1
                For i As Integer = 0 To drhws.Count - 1
                    'Dim rowHandle As Integer = GetRowHandleByVisibleIndex(i)
                    Dim rowHandle As Integer = drhws(i)
                    selection(GetListIndexByRowHandle(rowHandle)) = View.IsRowSelected(rowHandle)
                Next
                ElementosSeleccionados.BeginUpdate()
                ElementosSeleccionados.Clear()
                For Each index As Integer In OrderedSelection
                    If CBool(selection(index)) Then
                        ElementosSeleccionados.Add(GetRowByListIndex(index))
                    End If
                Next
                ElementosSeleccionados.EndUpdate()
                RaiseEvent SeleccionCambiada(sender, e)
            End If
        Catch ex As Exception
            Debug.Write(ex.Message)
        End Try
    End Sub
    Protected Overrides Sub ApplyFilter(checkFilterEnabled As Boolean, Optional skipIfFilterEquals As Boolean = False)
        If ConSeleccion Then
            If DirectCast(Me.View, TableView).ShowCheckBoxSelectorColumn Then
                updateLocker.DoLockedAction(Sub()
                                                MyBase.ApplyFilter(checkFilterEnabled, skipIfFilterEquals)
                                                BeginSelection()
                                                For Each index As Integer In OrderedSelection
                                                    If CBool(selection(index)) Then
                                                        SelectItem(GetRowHandleByListIndex(index))
                                                    End If
                                                Next
                                                EndSelection()

                                            End Sub)
            Else
                MyBase.ApplyFilter(checkFilterEnabled, skipIfFilterEquals)
            End If
        Else
            MyBase.ApplyFilter(checkFilterEnabled, skipIfFilterEquals)
        End If
    End Sub



    Public Function GetDataRowHandles() As List(Of Integer)
        Dim rowHandles As New List(Of Integer)()
        For i As Integer = 0 To Me.VisibleRowCount - 1
            Dim rowHandle As Integer = Me.GetRowHandleByVisibleIndex(i)
            If Me.IsGroupRowHandle(rowHandle) Then
                If Not Me.IsGroupRowExpanded(rowHandle) Then
                    rowHandles.AddRange(GetDataRowHandlesInGroup(rowHandle))
                End If
            Else
                rowHandles.Add(rowHandle)
            End If
        Next
        Return rowHandles
    End Function
    Public Function GetDataRowHandlesInGroup(groupRowHandle As Integer) As List(Of Integer)
        Dim rowHandles As New List(Of Integer)()
        For i As Integer = 0 To Me.GetChildRowCount(groupRowHandle) - 1
            Dim rowHandle As Integer = Me.GetChildRowHandle(groupRowHandle, i)
            If Me.IsGroupRowHandle(rowHandle) Then
                rowHandles.AddRange(GetDataRowHandlesInGroup(rowHandle))
            Else
                rowHandles.Add(rowHandle)
            End If
        Next
        Return rowHandles
    End Function
    Public Sub New(dcoe As IDataControlOriginationElement)
        MyBase.New(dcoe)
        '   MyBase.New()
    End Sub
    'Protected Overrides Sub OnPreviewKeyDown(e As KeyEventArgs)
    '    Try
    '        If e.Key = Key.Space AndAlso DirectCast(Me.View, TableView).ShowCheckBoxSelectorColumn Then
    '            e.Handled = True
    '            DirectCast(Me.View, TableView).SearchString &= " "
    '            Debug.WriteLine("ESPACIO")
    '            ' MyBase.OnPreviewKeyDown(e)
    '        Else
    '            MyBase.OnPreviewKeyDown(e)
    '        End If

    '    Catch ex As Exception
    '        MyBase.OnPreviewKeyDown(e)
    '    End Try

    'End Sub
    '  Private Cargado As Boolean = False
    Private ConSeleccion As Boolean = False
    'Private Sub tsGridControl_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
    '    If Not ConSeleccion AndAlso DirectCast(Me.View, TableView).ShowCheckBoxSelectorColumn AndAlso Me.SelectionMode = MultiSelectMode.MultipleRow Then
    '        AddHandler SelectionChanged, AddressOf MyGridControl_SelectionChanged
    '        ElementosSeleccionados = New ObservableCollectionCore(Of Object)()
    '        AddHandler Me.EndGrouping, AddressOf MyGridControl_EndGrouping
    '        AddHandler Me.StartGrouping, AddressOf MyGridControl_StartGrouping
    '        NumeroColumnasAgrupadas = ObtieneNumeroColumnasAgrupadas()
    '        ConSeleccion = True

    '    End If

    'End Sub
    Public Function GetColumnType(ByVal column As GridColumn) As Type
        Dim columnInfo As DataColumnInfo = DataProviderBase.Columns(column.FieldName)
        If columnInfo Is Nothing Then Return Nothing
        Return columnInfo.Type
    End Function
    Public Shared Sub EstableceFilterPopupModePredeterminados(gr As tsGridControl)
        If Not gr.PopupFilterModeInicializado AndAlso gr.ItemsSource IsNot Nothing Then
            gr.PopupFilterModeInicializado = True
            For Each cl In gr.Columns
                Dim tipo = gr.GetColumnType(cl)
                Select Case tipo
                    Case GetType(String), GetType(Integer), GetType(Integer?), GetType(Double), GetType(Double?)
                        cl.FilterPopupMode = FilterPopupMode.CheckedList
                    Case GetType(Date), GetType(DateTime), GetType(Date?), GetType(DateTime?)
                        cl.FilterPopupMode = FilterPopupMode.Excel
                End Select
            Next
        End If
    End Sub

    Private Sub tsGridControl_ItemsSourceChanged(sender As Object, e As ItemsSourceChangedEventArgs) Handles Me.ItemsSourceChanged
        EstableceFilterPopupModePredeterminados(sender)
        ElementosSeleccionados = New ObservableCollectionCore(Of Object)()
    End Sub
    Private Property _SeleccionMultiple As Boolean
    Public Property SeleccionMultiple As Boolean
        Get
            Return _SeleccionMultiple
        End Get
        Set(value As Boolean)
            _SeleccionMultiple = value
            If value Then
                Me.SelectionMode = MultiSelectMode.MultipleRow
            Else
                Me.SelectionMode = MultiSelectMode.None
            End If
        End Set
    End Property

    Private Sub tsGridControl_PreviewKeyDown(sender As Object, e As KeyEventArgs) Handles Me.PreviewKeyDown
        Select Case e.Key
            Case Key.Add
                If _SeleccionMultiple Then
                    Me.SelectAll()
                    e.Handled = True
                End If
            Case Key.Subtract
                If _SeleccionMultiple Then
                    Me.UnselectAll()
                    e.Handled = True
                End If
            Case Key.N
                If e.KeyboardDevice.IsKeyDown(Key.LeftCtrl) Then
                    Me.View.MoveNextRow()
                    Me.CurrentColumn = Me.Columns(0)
                End If
        End Select
    End Sub

    Public Shared Sub ExpandirTodosDetalles(Grid As GridControl)
        Dim d As TabViewDetailDescriptor = Nothing

        For i As Integer = 0 To Grid.VisibleRowCount - 1
            Dim rowHandle As Integer = Grid.GetRowHandleByVisibleIndex(i)

            If Grid.DetailDescriptor IsNot Nothing AndAlso Grid.DetailDescriptor.GetType Is GetType(TabViewDetailDescriptor) Then
                For Each dd In d.DetailDescriptors.OfType(Of DataControlDetailDescriptor)().Reverse()
                    ExpandirDetalle(Grid, rowHandle, dd)
                Next
            Else
                ExpandirDetalle(Grid, rowHandle)
            End If
        Next
    End Sub

    Public Shared Sub ExpandirDetalle(ByVal grid As GridControl, ByVal rowHandle As Integer, ByVal Optional descriptor As DataControlDetailDescriptor = Nothing)
        grid.ExpandMasterRow(rowHandle, descriptor)
        Dim detailGrid = TryCast(grid.GetDetail(rowHandle, descriptor), GridControl)
        If detailGrid Is Nothing Then Return
        ExpandirTodosDetalles(detailGrid)
    End Sub

End Class

Public Class tsGridColumn
    Inherits DevExpress.Xpf.Grid.GridColumn

    Public Property SoloLectura As Boolean
    Public Property Imprimible As Boolean = True
    Property ValorMinimo As Nullable(Of Double)
    Property ValorMaximo As Nullable(Of Double)
    Public Property MayusculasMinusculas As CharacterCasing? = Nothing
    Public Property CapturarEnter As Boolean

    Private Sub tsGridColumn_Validate(sender As Object, e As DevExpress.Xpf.Grid.GridCellValidationEventArgs) Handles Me.Validate
        If Not ValorMinimo Is Nothing Then
            If ValorMinimo > e.Value Then
                e.IsValid = False
                e.SetError("Valor Mínimo=" & ValorMinimo.ToString)
            End If
        End If
        If Not ValorMaximo Is Nothing Then
            If ValorMaximo < e.Value Then
                e.IsValid = False
                e.SetError("Valor Máximo=" & ValorMaximo.ToString)
            End If
        End If
    End Sub

    'Private Function IsColumnCheckBoxSelectorColumn(column As ColumnBase) As Boolean
    '    Return column = DirectCast(Me.View, TableView).VisibleColumns.First()
    'End Function
End Class