Imports System.ComponentModel
Imports DevExpress.XtraEditors
Imports DevExpress.XtraEditors.Controls
Imports DevExpress.XtraLayout
Imports DevExpress.XtraTab
Imports DigitalData.Modules.Language.Utils
Imports DigitalData.Modules.Logging

''' <summary>
''' 
''' </summary>
Public Class ClassDetailPages
    Private ReadOnly LogConfig As LogConfig
    Private ReadOnly Logger As Logger
    Private ReadOnly HostForm As IAdminForm

    Public Items As New Dictionary(Of String, DetailPage)

    Public Event AnyControl_Focus As EventHandler(Of DetailPageEventArgs)
    Public Event AnyControl_Changed As EventHandler(Of DetailPageEventArgs)
    Public Event CurrentPage_Changed As EventHandler(Of DetailPageEventArgs)

    Private RaiseChangedEvents As Boolean = True
    Private CurrentPage As DetailPage

    Public Property Current As DetailPage
        Get
            Return CurrentPage
        End Get
        Set(value As DetailPage)
            CurrentPage = value

            RaiseEvent CurrentPage_Changed(Me, New DetailPageEventArgs With {.Page = CurrentPage})
        End Set
    End Property

    Public Class DetailPageEventArgs
        Public Property Page As DetailPage
    End Class

    Public Class DetailPage
        Public Property IsPrimary As Boolean = False
        Public Property IsInsert As Boolean = False
        Public Property TabPage As XtraTabPage
        Public Property Name As String
        <Description("The Binding Source for the Form")>
        Public Property BindingSource As BindingSource
        <Description("The Bound Datatable in the Dataset (eg. MyDataset.TB_FOO_TABLE)")>
        Public Property DataTable As DataTable
        <Description("The TextEdit Control containing the AddedWho value")>
        Public Property AddedWhoEdit As TextEdit
        <Description("The TextEdit Control containing the ChangedWhoEdit value")>
        Public Property ChangedWhoEdit As TextEdit
    End Class

    ''' <summary>
    ''' Detail page which represents the primary page of a form
    ''' </summary>
    Public Class PrimaryPage
        Inherits DetailPage

        Public Sub New(Insert As Boolean)
            IsInsert = Insert
            IsPrimary = True
        End Sub
    End Class

    Public Class ComboBoxItem
        Public Property Text
        Public Property Value

        Public Overrides Function ToString() As String
            Return Text
        End Function
    End Class

    Public Sub New(LogConfig As LogConfig, Form As IAdminForm, LayoutControls As List(Of LayoutControl))
        Me.LogConfig = LogConfig
        Logger = LogConfig.GetLogger()
        HostForm = Form

        For Each oLayoutControl In LayoutControls
            AddHandler oLayoutControl.Click, AddressOf Handle_Focus
            AddHandler oLayoutControl.GotFocus, AddressOf Handle_Focus

            For Each oContainer As LayoutControlItem In oLayoutControl.Root.Items
                If TypeOf oContainer Is EmptySpaceItem Then
                    Continue For
                End If

                If TypeOf oContainer.Control IsNot BaseEdit Then
                    Continue For
                End If

                Dim oControl As BaseEdit = oContainer.Control
                AddHandler oControl.GotFocus, AddressOf Handle_Focus
                AddHandler oControl.EditValueChanged, AddressOf Handle_EditValueChanged
                AddHandler oControl.Validating, AddressOf Handle_Validating
            Next
        Next
    End Sub

    ''' <summary>
    ''' Add a new DetailPage or a new PrimaryPage
    ''' </summary>
    Public Sub Add(Page As DetailPage)
        If Page.TabPage Is Nothing Then
            Items.Add("Primary", Page)
        Else
            Items.Add(Page.TabPage.Name, Page)
        End If

        AddHandler Page.BindingSource.AddingNew, Sub(sender As Object, e As EventArgs)
                                                     RaiseChangedEvents = False
                                                     Page.AddedWhoEdit.EditValue = Environment.UserName
                                                     RaiseChangedEvents = True
                                                 End Sub
    End Sub

    ''' <summary>
    ''' Add a list of new DetailPages or new PrimaryPages
    ''' </summary>
    Public Sub AddRange(ParamArray Pages As DetailPage())
        For Each oPage In Pages
            Add(oPage)
        Next
    End Sub

    ''' <summary>
    ''' Get the DetailPage which uses the given `TabPage`
    ''' </summary>
    Public Function GetDetailPage(TabPage As XtraTabPage) As DetailPage
        Try
            Dim oItem = Items.
                Where(Function(Item) TabPage.Equals(Item.Value.TabPage)).
                FirstOrDefault()

            Return oItem.Value
        Catch ex As Exception
            Return Nothing
        End Try
    End Function

    Public Function PrepareLoad() As Boolean
        Dim oItem = Items.
            Where(Function(Item) Item.Value.IsPrimary).
            FirstOrDefault()

        Dim oPage = oItem.Value
        If oPage Is Nothing Then
            Return False
        End If

        If oPage.IsInsert Then
            RaiseChangedEvents = False
            oPage.BindingSource.AddNew()
            RaiseChangedEvents = True
        End If

        CurrentPage = oPage

        Return True
    End Function

    ''' <summary>
    ''' Saves the pending changes to the binding source
    ''' </summary>
    ''' <returns>True, if changes were made, otherwise False</returns>
    Public Function PrepareSave() As Boolean
        Dim oPage = CurrentPage

        If oPage Is Nothing Then
            Return False
        End If

        Try
            oPage.BindingSource.EndEdit()

            If oPage.DataTable.GetChanges() IsNot Nothing Then
                RaiseChangedEvents = False
                HostForm.HasChanges = True

                If oPage.IsInsert Then
                    oPage.AddedWhoEdit.EditValue = My.Application.User.UserName
                Else
                    oPage.ChangedWhoEdit.EditValue = My.Application.User.UserName
                End If

                RaiseChangedEvents = True

                oPage.BindingSource.EndEdit()
                Return True
            Else
                Return False
            End If
        Catch ex As Exception
            Logger.Error(ex)
            Return False
        End Try
    End Function

    Private Sub Handle_Validating(sender As Object, e As BaseEditValidatingEventArgs)
        Dim oControl As BaseEdit = sender
        Dim oColumn As DataColumn = Get_DataColumnFromBaseEdit(oControl)

        If oColumn IsNot Nothing Then
            Dim oNullable As Boolean = oColumn.AllowDBNull

            If oNullable = False Then
                If TypeOf oControl Is ComboBoxEdit AndAlso DirectCast(oControl, ComboBoxEdit).SelectedIndex = -1 Then
                    e.ErrorText = "Please select a value from the list."
                    e.Cancel = True

                ElseIf NotNull(oControl.EditValue.ToString, String.Empty) = String.Empty Then
                    e.ErrorText = "Please input a value"
                    e.Cancel = True

                End If
            End If
        End If
    End Sub

    Private Function Get_DataColumnFromBaseEdit(Control As BaseEdit) As DataColumn
        Dim oBinding As Binding = Control.DataBindings.Item("EditValue")

        If Control.DataBindings.Count = 0 OrElse oBinding Is Nothing Then
            Return Nothing
        End If

        If oBinding.DataSource Is Nothing Then
            Return Nothing
        End If

        If TypeOf oBinding.DataSource IsNot BindingSource Then
            Return Nothing
        End If

        Try
            Dim oSource As BindingSource = oBinding.DataSource
            Dim oTableName As String = oSource.DataMember
            Dim oDataSet As DataSet = oSource.DataSource
            Dim oTable = oDataSet.Tables(oTableName)
            Dim oColumnName As String = oBinding.BindingMemberInfo.BindingField
            Dim oColumn As DataColumn = oTable.Columns.Item(oColumnName)

            Return oColumn
        Catch ex As Exception
            Logger.Error(ex)
            Return Nothing
        End Try
    End Function

    Private Sub Handle_Focus(sender As Control, e As EventArgs)
        Dim oControl As Control = sender
        Dim oLayoutControl As LayoutControl = Nothing

        ' Get the Layout Control containing the Edit Contol
        If TypeOf oControl.Parent Is LayoutControl Then
            oLayoutControl = oControl.Parent
        ElseIf TypeOf oControl Is LayoutControl Then
            oLayoutControl = oControl
        End If

        If oLayoutControl Is Nothing Then
            Exit Sub
        End If

        If TypeOf oLayoutControl.Parent Is XtraTabPage Then
            Dim oTabPage As XtraTabPage = oLayoutControl.Parent

            If Items.ContainsKey(oTabPage.Name) Then
                CurrentPage = Items.Item(oTabPage.Name)

                Dim oData As New DetailPageEventArgs With {.Page = Items.Item(oTabPage.Name)}
                RaiseEvent CurrentPage_Changed(Me, oData)
                RaiseEvent AnyControl_Focus(oControl, oData)
            Else
                CurrentPage = Nothing

                RaiseEvent CurrentPage_Changed(Me, Nothing)
                RaiseEvent AnyControl_Focus(oControl, Nothing)
            End If
        End If
    End Sub

    Private Sub Handle_EditValueChanged(sender As BaseEdit, e As EventArgs)
        Dim oControl As BaseEdit = sender

        If RaiseChangedEvents = False Then
            Exit Sub
        End If

        ' Get the Layout Control containing the Edit Contol
        If TypeOf oControl.Parent Is LayoutControl Then
            Dim oLayoutControl As LayoutControl = oControl.Parent

            ' Get the TabPage containing the Layout Control
            If TypeOf oLayoutControl.Parent Is XtraTabPage Then
                Dim oTabPage As XtraTabPage = oLayoutControl.Parent

                If Items.ContainsKey(oTabPage.Name) Then
                    Dim oData As New DetailPageEventArgs With {.Page = Items.Item(oTabPage.Name)}
                    RaiseEvent AnyControl_Changed(oControl, oData)
                Else
                    RaiseEvent AnyControl_Changed(oControl, Nothing)
                End If
            End If
        End If
    End Sub
End Class


