Imports DevExpress.Utils
Imports DevExpress.XtraEditors.Controls
Imports DevExpress.XtraEditors.Repository
Imports DevExpress.XtraTreeList
Imports DevExpress.XtraTreeList.Columns
Imports DevExpress.XtraTreeList.Nodes
Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Language.Utils

Public Class TreeListManager
    Private ReadOnly SvgImages As SvgImageCollection
    Private ReadOnly LogConfig As LogConfig
    Private ReadOnly Property Database As MSSQLServer
    Private ReadOnly Logger As Logger

    Private ReadOnly DisplayColumns As New List(Of String) From {"COLUMN1", "COLUMN2", "COLUMN3", "ADDED_WHEN", "STATE", "ICON"}
    Private ReadOnly SQLColumns As New List(Of String) From {"SELECT1", "SELECT2", "SELECT3", "SELECT4"}
    Private ReadOnly DocViewColumns As New List(Of String) From {"DOCVIEW1", "DOCVIEW2"}
    Private ReadOnly HtmlViewColumns As New List(Of String) From {"HTML1", "HTML2"}
    Private ReadOnly DataColumns As List(Of String) = SQLColumns.
        Concat(DocViewColumns).
        Concat(HtmlViewColumns).
        ToList

    'Private ReadOnly Items As New List(Of Tuple(Of TreeList, TreeListProperties))
    Private ReadOnly Items As New Dictionary(Of TreeList, TreeListProperties)

    Public ReadOnly Property TreeLists As List(Of TreeList)
        Get
            Return Items.Keys.ToList
        End Get
    End Property

    Public ReadOnly Property CurrentTreeListProps As TreeListProperties
        Get
            If CurrentTreeList IsNot Nothing Then
                Return Items.Item(CurrentTreeList)
            Else
                Return Nothing
            End If
        End Get
    End Property

    Public Property CurrentTreeList As TreeList

    Public Event TreeList_FocusedNodeChanged As EventHandler(Of FocusedNodeChangedEventArgs)
    Public Event TreeList_CustomDrawNodeCell As EventHandler(Of CustomDrawNodeCellEventArgs)

    Public Class TreeListProperties
        Public SearchValue As String
        Public ViewName As String
        Public CreatedAt As Date
    End Class

    Private Enum NodeImage
        [Default] = 0
        SQL = 1
        File = 2
        Mail = 3
        Success = 4
        Failure = 5
        Warning = 6
        Waiting = 7
        User = 8
        Highlight = 9
    End Enum

    Public Sub New(LogConfig As LogConfig, Database As MSSQLServer, SvgImageCollection As SvgImageCollection)
        Me.LogConfig = LogConfig
        Me.Database = Database
        Logger = LogConfig.GetLogger()
        SvgImages = SvgImageCollection
    End Sub

    Public Sub Add(TreeList As TreeList)
        Items.Add(TreeList, New TreeListProperties() With {.CreatedAt = Now})
    End Sub

    Public Sub AddRange(ParamArray TreeLists As TreeList())
        For Each oTreeList In TreeLists
            Add(oTreeList)
        Next
    End Sub

    Public Function GetNextTreeList() As TreeList
        ' Return next free Treelist
        For Each oTreeList In TreeLists
            If oTreeList.DataSource Is Nothing Then
                Return oTreeList
            End If
        Next

        ' Otherwise return oldest TreeList
        Return Items.
            OrderBy(Function(i) i.Value.CreatedAt).
            Select(Of TreeList)(Function(i) i.Key).
            First()
    End Function

    Public Sub LoadDataFor(TreeList As TreeList, DataSource As DataTable, ViewName As String, Value As String)
        Try
            AddHandler TreeList.FocusedNodeChanged, Sub(sender As Object, e As FocusedNodeChangedEventArgs)
                                                        RaiseEvent TreeList_FocusedNodeChanged(sender, e)
                                                    End Sub

            AddHandler TreeList.CustomDrawNodeCell, Sub(sender As Object, e As CustomDrawNodeCellEventArgs)
                                                        RaiseEvent TreeList_CustomDrawNodeCell(sender, e)
                                                    End Sub

            ' Load data
            TreeList.DataSource = DataSource
            TreeList.PopulateColumns()

            ' Show all columns in DisplayColumns List
            For Each oColumn In TreeList.Columns
                oColumn.Visible = DisplayColumns.Contains(oColumn.FieldName)
                If oColumn.FieldName = "ADDED_WHEN" Then
                    oColumn.Format.FormatType = FormatType.DateTime
                    oColumn.Format.FormatString = "dd.MM.yyyy HH:MM:ss"
                End If
            Next

            ' Initialize TreeList visuals
            Init(TreeList)

            ' Expand all nodes that contain state WARNING or FAILURE
            Dim oStateColumn As TreeListColumn = TreeList.Columns.Item("STATE")
            For Each oNode As TreeListNode In TreeList.Nodes
                ExpandNodes(oNode, Function(n)
                                       Dim oObjectValue = n.GetValue(oStateColumn)
                                       Dim oValue As String = NotNull(oObjectValue, String.Empty)
                                       Return oValue IsNot Nothing AndAlso (oValue = Constants.STATE_WARNING Or oValue = Constants.STATE_FAILURE)
                                   End Function)
            Next

            ' Set currently loaded TreeList as current
            CurrentTreeList = TreeList

            ' Update Timestamp and Searchdata for current TreeList
            Dim oItem = Items.Item(TreeList)
            oItem.CreatedAt = Now
            oItem.SearchValue = Value
            oItem.ViewName = ViewName
            Items.Item(TreeList) = oItem
        Catch ex As Exception
            Logger.Error(ex)
        End Try
    End Sub

    Private Sub ExpandNodes(RootNode As TreeListNode, Condition As Predicate(Of TreeListNode))
        If Condition(RootNode) = True Then
            RootNode.Expand()
            ExpandParentNode(RootNode)
        End If

        For Each oNode As TreeListNode In RootNode.Nodes
            ExpandNodes(oNode, Condition)

            If Condition(oNode) = True Then
                oNode.Expand()
                ExpandParentNode(oNode)
            End If
        Next
    End Sub

    Private Sub ExpandParentNode(ChildNode As TreeListNode)
        If ChildNode.ParentNode IsNot Nothing Then
            ChildNode.ParentNode.Expand()
            ExpandParentNode(ChildNode.ParentNode)
        End If
    End Sub

    Private Sub Init(TreeList As TreeList)
        If TreeList.Columns.Count = 0 Then
            Exit Sub
        End If

        TreeList.KeyFieldName = "GUID"
        TreeList.ParentFieldName = "PARENT_ID"

        Dim oStateEdit As New RepositoryItemImageComboBox With {
            .SmallImages = SvgImages,
            .GlyphAlignment = HorzAlignment.Near
        }
        oStateEdit.Buttons.Clear()
        oStateEdit.Items.AddRange(New List(Of ImageComboBoxItem) From {
            New ImageComboBoxItem("Success", Constants.STATE_SUCCESS, NodeImage.Success),
            New ImageComboBoxItem("Failure", Constants.STATE_FAILURE, NodeImage.Failure),
            New ImageComboBoxItem("Warning", Constants.STATE_WARNING, NodeImage.Warning),
            New ImageComboBoxItem("Waiting", Constants.STATE_WAITING, NodeImage.Waiting),
            New ImageComboBoxItem("Default", Constants.STATE_DEFAULT, NodeImage.Default),
            New ImageComboBoxItem("User", Constants.STATE_USER, NodeImage.User),
            New ImageComboBoxItem("Highlight", Constants.STATE_HIGHLIGHT, NodeImage.Highlight)
        })

        Dim oIconEdit As New RepositoryItemImageComboBox With {
            .SmallImages = SvgImages,
            .GlyphAlignment = HorzAlignment.Near
        }
        oIconEdit.Buttons.Clear()
        oIconEdit.Items.AddRange(New List(Of ImageComboBoxItem) From {
            New ImageComboBoxItem("Email", "MAIL", NodeImage.Mail),
            New ImageComboBoxItem("SQL", "SQL", NodeImage.SQL),
            New ImageComboBoxItem("File", "FILE", NodeImage.File)
        })

        Dim oColumn1 = TreeList.Columns.Item("COLUMN1")
        Dim oStateColumn = TreeList.Columns.Item("STATE")
        Dim oIconColumn = TreeList.Columns.Item("ICON")


        oStateColumn.VisibleIndex = 1
        oIconColumn.VisibleIndex = 2

        With oColumn1
            .VisibleIndex = 0
            .MinWidth = 150
        End With

        With oStateColumn
            .ColumnEdit = oStateEdit
            .MaxWidth = 25
            .MinWidth = 25
            .Caption = " "
        End With

        With oIconColumn
            .ColumnEdit = oIconEdit
            .MaxWidth = 25
            .MinWidth = 25
            .Caption = " "
        End With

    End Sub

End Class
