Imports System.Windows.Forms
Imports DevExpress.XtraEditors.Repository
Imports DevExpress.XtraSplashScreen
Imports DevExpress.XtraEditors
Imports DevExpress.XtraLayout
Imports DigitalData.GUIs.Common.Base
Imports DigitalData.Modules.EDMI.API
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Language
Imports DigitalData.Modules.ZooFlow
Imports DigitalData.Modules.Base.IDB

Public Class ctrlObjectPropertyDialog
    Implements IBaseForm

    Private Property LogConfig As LogConfig Implements IBaseForm.LogConfig
    Private Property Logger As Logger Implements IBaseForm.Logger
    Private Property ControlManager As AttributeControls
    Private Property GridBuilder As GridBuilder
    Private Property Client As Client
    Private Property Environment As Environment
    Private Property ObjectId As Long
    Private Property HostForm As Form
    Private Property Helper As FormHelper

    Private ReadOnly Changes As New Dictionary(Of String, Object)

    Public ReadOnly Property HasChanges As Boolean
        Get
            Return Changes.Count > 0
        End Get
    End Property

    Private IsLoading As Boolean = False
    Private LastEntityId As Integer = 0

    Private Sub ctrlObjectPropertyDialog_Load(sender As Object, e As EventArgs) Handles Me.Load
        XtraTabControl1.SelectedTabPage = XtraTabPageAttributes
    End Sub

    Public Sub Initialize(pLogConfig As LogConfig, pHostForm As Form, pClient As Client, pEnv As Environment)
        LogConfig = pLogConfig
        Logger = pLogConfig.GetLogger()
        HostForm = pHostForm
        ControlManager = New AttributeControls(pLogConfig, pEnv, pClient)
        Helper = New FormHelper(pLogConfig, pHostForm)

        GridBuilder = New GridBuilder(ViewObjectHistory, ViewValueHistory)
        GridBuilder.
            WithDefaults().
            WithReadOnlyOptions().
            WithClipboardHandler()

        AddHandler ControlManager.EditValueChanged, AddressOf BaseEdit_EditValueChanged

        Client = pClient
        Environment = pEnv
    End Sub

    Public Async Function SaveChanges() As Task(Of Boolean)
        Try
            For Each oChange As KeyValuePair(Of String, Object) In Changes
                Logger.Info("Updating Attribute [{0}] with value [{1}]", oChange.Key, oChange.Value.ToString)
                Await Client.SetAttributeValueAsync(ObjectId, oChange.Key, oChange.Value, New Options.SetAttributeValueOptions With {
                    .Language = Environment.User.Language,
                    .Username = Environment.User.UserName
                })
            Next

            Helper.ShowInfoMessage($"{Changes.Count} Änderungen gespeichert!", "SaveChanges")
            Changes.Clear()

            Return True
        Catch ex As Exception
            Helper.ShowErrorMessage(ex, "SaveChanges")
            Return False
        End Try
    End Function

    Public Async Function LoadObject(pObjectId As Long) As Task(Of Boolean)
        ' Load Business Entities
        Dim oEntityIds = Await GetBusinessEntitiesForObjectId(pObjectId)
        Dim oActiveEntity = oEntityIds.FirstOrDefault()

        Dim oCombobox As RepositoryItemComboBox = DirectCast(cmbEntityId.Edit, RepositoryItemComboBox)
        oCombobox.Items.Clear()
        oCombobox.Items.AddRange(oEntityIds)
        cmbEntityId.EditValue = oEntityIds.First()

        Return Await LoadObject(pObjectId, oActiveEntity)
    End Function

    Public Async Function LoadObject(pObjectId As Long, pEntityId As Long) As Task(Of Boolean)
        If pObjectId = 0 Then
            Return True
        End If

        IsLoading = True
        Enabled = False

        Try
            ObjectId = pObjectId

            ' Load History of attribute value changes
            Dim oAttributeHistoryTable = Await GetValueHistoryForObjectId(pObjectId)
            ShowAttributeHistory(oAttributeHistoryTable)

            ' Load History of object state changes
            Dim oObjectHistoryTable = Await GetObjectHistoryForObjectId(pObjectId)
            ShowObjectHistory(oObjectHistoryTable)

            ' Load Object Properties
            Dim oObjectProperties = Await GetPropertiesForObjectId(ObjectId)
            ShowObjectProperties(oObjectProperties)


            ' Load All attributes for current entity id
            Dim oAttributes = Await ControlManager.GetAttributesForBusinessEntity(cmbEntityId.EditValue)

            ' Load Attribute controls
            If pEntityId <> LastEntityId Then
                ControlManager.LoadControlsForAttributes(oAttributes, Root)
            End If

            ' Load values for all controls
            Await ControlManager.LoadControlValuesForAttributes(pObjectId, Root)

            ' Save the current entity id
            LastEntityId = pEntityId

            ' Delete all existing changes from other objects
            Changes.Clear()

            Return True
        Catch ex As Exception
            Logger.Error(ex)
            Return False
        Finally
            Enabled = True
            IsLoading = False
        End Try
    End Function

    Private Function ShowAttributeHistory(pDatatable As DataTable) As Boolean
        Try
            GridValueHistory.DataSource = pDatatable

            Return True
        Catch ex As Exception
            Logger.Error(ex)
            Return False
        End Try
    End Function

    Private Function ShowObjectHistory(pDatatable As DataTable) As Boolean
        Try
            GridObjectHistory.DataSource = pDatatable

            Return True
        Catch ex As Exception
            Logger.Error(ex)
            Return False
        End Try
    End Function

    Private Function ShowObjectProperties(pDatatable As DataTable) As Boolean
        Try
            Dim oRow As DataRow = pDatatable.Rows.Item(0)
            txtObjectId.Text = oRow.Item("IDB_OBJ_ID")
            txtCreatedWhen.Text = oRow.Item("ADDED_WHEN")
            txtCreatedWho.Text = oRow.Item("ADDED_WHO")
            txtChangedWhen.Text = Utils.NotNull(oRow.Item("CHANGED_WHEN_SUBSTRUCTURE"), String.Empty)
            txtChangedWho.Text = Utils.NotNull(oRow.Item("CHANGED_WHO_SUBSTRUCTURE"), String.Empty)

            lbLifecycleStart.Text = DirectCast(oRow.Item("ADDED_WHEN"), Date).ToShortDateString
            lbLifecycleEnd.Text = Date.MaxValue.ToShortDateString
            progressLifecycle.Position = 30

            Return True
        Catch ex As Exception
            Logger.Error(ex)
            Return False
        End Try
    End Function

    Private Async Function GetBusinessEntitiesForObjectId(ObjectId As Long) As Task(Of List(Of Long))
        Try
            Dim oSQL = $"SELECT BE_ID FROM TBIDB_OBJECT_BE WHERE IDB_OBJ_ID = {ObjectId}"
            Dim oResult = Await Client.GetDatatableFromIDBAsync(oSQL)

            If oResult.OK = False Then
                Throw New ApplicationException($"Business Entities could not be retrieved!")

            ElseIf oResult.Table.Rows.Count = 0 Then
                Throw New ApplicationException($"ObjectId {ObjectId} is not assigned to any business entity!")

            Else
                Dim oEntities As New List(Of Long)

                For Each oRow In oResult.Table.Rows
                    oEntities.Add(oRow.item("BE_ID"))
                Next

                Return oEntities
            End If
        Catch ex As Exception
            Logger.Error(ex)
            Return New List(Of Long)
        End Try
    End Function

    Private Async Function GetValueHistoryForObjectId(ObjectId As Long) As Task(Of DataTable)
        Dim oSQL As String = $"
            SELECT * FROM VWIDB_CHANGE_LOG 
            WHERE IDB_OBJ_ID = {ObjectId}
            ORDER BY ChangeID DESC
        "
        Dim oResult = Await Client.GetDatatableFromIDBAsync(oSQL)

        Return oResult.Table
    End Function

    Private Async Function GetObjectHistoryForObjectId(ObjectId As Long) As Task(Of DataTable)
        Dim oSQL As String = $"
            SELECT * FROM VWIDB_DOC_STATES 
            WHERE IDB_OBJ_ID = {ObjectId} AND LANG_CODE = '{Environment.User.Language}'
            ORDER BY ADDED_WHEN DESC
        "
        Dim oResult = Await Client.GetDatatableFromIDBAsync(oSQL)

        Return oResult.Table
    End Function

    Private Async Function GetPropertiesForObjectId(ObjectId As Long) As Task(Of DataTable)
        Dim oSQL As String = $"SELECT * FROM TBIDB_OBJECT WHERE IDB_OBJ_ID = {ObjectId}"
        Dim oResult = Await Client.GetDatatableFromIDBAsync(oSQL)

        Return oResult.Table
    End Function

    Private Async Sub Load_Attributes(pObjectId As Long, pBusinessEntityId As Long)
        Try
            Dim oAttributes = Await ControlManager.GetAttributesForBusinessEntity(pBusinessEntityId)
            If oAttributes.Count = 0 Then
                MsgBox($"Es konnten keine Attribute für das Objekt '{pObjectId}' geladen werden!", MsgBoxStyle.Critical, Text)
            End If

            ControlManager.LoadControlsForAttributes(oAttributes, Root)
            Await ControlManager.LoadControlValuesForAttributes(pObjectId, Root)
        Catch ex As Exception
            Logger.Error(ex)
        End Try
    End Sub

    Private Async Sub cmbEntityId_EditValueChanged(sender As Object, e As EventArgs) Handles cmbEntityId.EditValueChanged
        Dim oEntityId As Long

        If Integer.TryParse(cmbEntityId.EditValue, oEntityId) AndAlso IsLoading = False Then
            Await LoadObject(ObjectId, oEntityId)
        End If
    End Sub

    Private Sub BaseEdit_EditValueChanged(sender As Object, e As EventArgs)
        If IsLoading = True Then
            Exit Sub
        End If

        Dim oControlItem As LayoutControlItem = sender
        Dim oControl As BaseEdit = oControlItem.Control
        Dim oAttribute As Attribute = oControl.Tag
        Dim oValue = oControl.EditValue
        Dim oKey = oAttribute.Title

        If Changes.ContainsKey(oKey) Then
            Changes.Item(oKey) = oValue
        Else
            Changes.Add(oAttribute.Title, oValue)

        End If
    End Sub

End Class
