Imports System.IO
Imports System.Xml.Serialization
Imports DevExpress.Utils
Imports DevExpress.Utils.Svg
Imports DigitalData.GUIs.ZooFlow.Search.SearchToken
Imports DigitalData.Modules.Base
Imports DigitalData.Modules.Config
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Language
Imports DigitalData.Modules.Database
Imports DigitalData.Modules.ZooFlow.State

Namespace Search
    Public Class SearchLoader
        Inherits BaseClass

        Private ReadOnly Images As SvgImageCollection
        Private ReadOnly ImageTable As List(Of ImageTableItem)
        Private ReadOnly Serializer As XmlSerializer
        Private ReadOnly Database As MSSQLServer
        Private ReadOnly UserState As UserState

        Public Sub New(pLogConfig As LogConfig, pDatabase As MSSQLServer, pUserState As UserState, pSvgImages As SvgImageCollection)
            MyBase.New(pLogConfig)

            Images = pSvgImages
            ImageTable = GetImageTable(pSvgImages)
            Database = pDatabase
            UserState = pUserState
            Serializer = New XmlSerializer(GetType(SavedSearch.CustomSearchSerializable))
        End Sub

        Public Sub CreateCustomSearch(pTitle As String, pDescription As String, pTokens As List(Of Token), pImage As String)
            Dim oSearch As New SavedSearch.CustomSearch With {
                .Name = pTitle,
                .Description = pDescription,
                .Tokens = pTokens,
                .Image = Images.Item(pImage)
            }

            Try
                Dim oBuffer As Byte() = SerializeSearch(oSearch)
                Dim oBase64 = System.Convert.ToBase64String(oBuffer)

                If Database.ExecuteNonQuery(
                    $"INSERT INTO TBIDB_SEARCH_DEFINITION (TITLE, DESCRIPTION, XML_VALUE, SYS_SEARCH, ADDED_WHO) 
                    VALUES ('{pTitle}', '{pDescription}', '{oBase64}', 0, '{UserState.UserName}')"
                ) = True Then
                    Dim oSearchId = Database.GetScalarValue("SELECT MAX(GUID) FROM TBIDB_SEARCH_DEFINITION")
                    Database.ExecuteNonQuery(
                        $"INSERT INTO TBIDB_SEARCH_DEF_RELATIONS (SEARCH_ID, USR_ID, ADDED_WHO)
                        VALUES ({oSearchId}, {UserState.UserId}, '{UserState.UserName}')")
                End If
            Catch ex As Exception
                Logger.Warn("Custom Search could not be saved!")
                Logger.Error(ex)
            End Try
        End Sub

        Public Function LoadSearches() As List(Of SavedSearch.SavedSearch)
            Dim oSearches As New List(Of SavedSearch.SavedSearch)
            Dim oCustomSearches = LoadCustomSearches()
            Dim oPredefinedSearches = LoadPredefinedSearches()

            Return oSearches.
                Concat(oCustomSearches).
                Concat(oPredefinedSearches).
                ToList()
        End Function

        Public Function LoadCustomSearches() As List(Of SavedSearch.SavedSearch)
            Dim oSearches As New List(Of SavedSearch.SavedSearch)
            Dim oSQL As String = $"
                SELECT DEF.*
                FROM [TBIDB_SEARCH_DEFINITION] DEF
                JOIN [TBIDB_SEARCH_DEF_RELATIONS] REL ON REL.SEARCH_ID = DEF.GUID
                WHERE REL.USR_ID = {UserState.UserId}
            "
            Dim oTable = Database.GetDatatable(oSQL)

            For Each oRow As DataRow In oTable.Rows
                Dim oBase64 = oRow.Item("XML_VALUE")
                Dim oBuffer = System.Convert.FromBase64String(oBase64)
                Dim oSearch = DeserializeSearch(oBuffer)
                oSearches.Add(oSearch)
            Next

            Return oSearches
        End Function

        Public Function LoadPredefinedSearches() As List(Of SavedSearch.SavedSearch)
            Return New List(Of SavedSearch.SavedSearch) From {
                New SavedSearch.PredefinedDateSearch() With {
                    .Name = "Heute",
                    .Description = "Dokumente, die heute abgelegt wurden",
                    .DateConstraint = SearchRunner.DateConstraint.Today,
                    .Image = Images.Item("today")
                },
                New SavedSearch.PredefinedDateSearch() With {
                    .Name = "Gestern",
                    .Description = "Dokumente, die gestern abgelegt wurden",
                    .DateConstraint = SearchRunner.DateConstraint.Yesterday,
                    .Image = Images.Item("yesterday")
                },
                New SavedSearch.PredefinedDateSearch() With {
                    .Name = "Letzte 7 Tage",
                    .Description = "Dokumente, die in den letzten 7 Tagen abgelegt wurden",
                    .DateConstraint = SearchRunner.DateConstraint.Last7Days,
                    .Image = Images.Item("week")
                },
                New SavedSearch.PredefinedDateSearch() With {
                    .Name = "Dieser Monat",
                    .Description = "Dokumente, die in diesem Monat abgelegt wurden",
                    .DateConstraint = SearchRunner.DateConstraint.CurrentMonth,
                    .Image = Images.Item("month")
                },
                New SavedSearch.PredefinedDateSearch() With {
                    .Name = "Letzter Monat",
                    .Description = "Dokumente, die im letzten Monat abgelegt wurden",
                    .DateConstraint = SearchRunner.DateConstraint.LastMonth,
                    .Image = Images.Item("month")
                },
                New SavedSearch.PredefinedDateSearch() With {
                    .Name = "Dieses Jahr",
                    .Description = "Dokumente, die in diesem Jahr abgelegt wurden",
                    .DateConstraint = SearchRunner.DateConstraint.CurrentYear,
                    .Image = Images.Item("year")
                },
                New SavedSearch.PredefinedDateSearch() With {
                    .Name = "Letztes Jahr",
                    .Description = "Dokumente, die im letzten Jahr abgelegt wurden",
                    .DateConstraint = SearchRunner.DateConstraint.LastYear,
                    .Image = Images.Item("year")
                }
            }
        End Function

        Private Function ConvertSvgImageToString(pImage As SvgImage) As String
            Dim oItem = ImageTable.Where(Function(item) item.Image.Equals(pImage)).FirstOrDefault()
            If oItem Is Nothing Then
                Return Nothing
            End If

            Return oItem.Name
        End Function

        Private Function ConvertStringToImageName(pName As String) As SvgImage
            Dim oItem = ImageTable.Where(Function(item) item.Name.Equals(pName)).FirstOrDefault()
            If oItem Is Nothing Then
                Return Nothing
            End If

            Return oItem.Image
        End Function

        Private Function GetImageTable(pImageCollection As SvgImageCollection) As List(Of ImageTableItem)
            Dim oList As New List(Of ImageTableItem)

            For Each oImageName In pImageCollection.Keys
                Dim oSvgImage = pImageCollection.Item(oImageName)
                oList.Add(New ImageTableItem(oImageName, oSvgImage))
            Next

            Return oList
        End Function

        Private Function SerializeSearch(pSearch As SavedSearch.CustomSearch) As Byte()
            Try
                Dim oSearch As New SavedSearch.CustomSearchSerializable With {
                    .Name = pSearch.Name,
                    .Description = pSearch.Description,
                    .GroupText = pSearch.GroupText,
                    .Tokens = pSearch.Tokens,
                    .ImageName = ConvertSvgImageToString(pSearch.Image)
                }

                Using oStream As New MemoryStream
                    Serializer.Serialize(oStream, oSearch)
                    Return oStream.ToArray()
                End Using
            Catch ex As Exception
                Logger.Error(ex)
                Return Nothing
            End Try
        End Function

        Private Function DeserializeSearch(pBytes As Byte()) As SavedSearch.CustomSearch
            Try
                Using oStream As New MemoryStream(pBytes)
                    Dim oSearch As SavedSearch.CustomSearchSerializable = Serializer.Deserialize(oStream)

                    Return New SavedSearch.CustomSearch With {
                        .Name = oSearch.Name,
                        .Description = oSearch.Description,
                        .GroupText = oSearch.GroupText,
                        .Tokens = oSearch.Tokens,
                        .Image = ConvertStringToImageName(oSearch.ImageName)
                    }
                End Using
            Catch ex As Exception
                Logger.Error(ex)
                Return Nothing
            End Try
        End Function

        Private Class ImageTableItem
            Public ReadOnly Name As String
            Public ReadOnly Image As SvgImage

            Public Sub New(pName As String, pImage As SvgImage)
                Name = pName
                Image = pImage
            End Sub
        End Class
    End Class
End Namespace
