Imports System.ComponentModel
Imports System.Threading
Imports System.Globalization
Imports DevExpress.XtraSplashScreen
Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Language.Utils
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.EDMI.API
Imports DigitalData.GUIs.ZooFlow.ClassConstants
Imports DigitalData.GUIs.ZooFlow.ClassInitLoader
Imports DigitalData.Controls.SQLConfig
Imports System.Data.SqlClient
Imports DigitalData.Modules
Imports DevExpress.LookAndFeel
Imports DigitalData.Modules.Language
Imports DigitalData.GUIs.Common

Public Class ClassInit
    Inherits Base.BaseClass

    Private ReadOnly _MainForm As frmFlowForm
    Private ReadOnly _Database As DatabaseWithFallback
    Private ReadOnly _FormHelper As FormHelper
    Private _Loader As ClassInitLoader

    Public Event Completed As EventHandler

    Public Sub New(LogConfig As LogConfig, ParentForm As frmFlowForm)
        MyBase.New(LogConfig)
        _MainForm = ParentForm
        _FormHelper = New FormHelper(LogConfig, ParentForm)
    End Sub

    Public Sub InitializeApplication()
        _Loader = New ClassInitLoader(LogConfig)

        ' === Init Schritte definieren
        _Loader.AddStep("Initializing Base", AddressOf InitializeBase, True)
        _Loader.AddStep("Initializing EDMI Service", AddressOf InitializeService, True)
        _Loader.AddStep("Initializing Database", AddressOf InitializeDatabaseWithFallback, True)
        _Loader.AddStep("Initializing User", AddressOf InitializeUser, True)
        _Loader.AddStep("Initializing BasicCatalogues", AddressOf InitializeBasicsfromDB, True)
        _Loader.AddStep("Initializing Language", AddressOf InitializeLanguage, False)
        _Loader.AddStep("Initializing 3rd-party licenses", AddressOf Initialize3rdParty, False)
        _Loader.AddStep("Initializing Basic Config", AddressOf InitBasicConfig, False)
        ' === Init Schritte definieren

        AddHandler _Loader.ProgressChanged, AddressOf ProgressChanged
        AddHandler _Loader.InitCompleted, AddressOf InitCompleted

        _Loader.Run()
    End Sub

    Private Sub InitCompleted(sender As Object, e As RunWorkerCompletedEventArgs)
        If Not IsNothing(e.Error) Then
            Dim oMessageStart = $"Beim Initialisieren des Programms ist folgender Fehler aufgetreten:"
            Dim oMessageEnd = "Das Program wird nun beendet"
            Dim oMessage1 = $"{vbNewLine}{vbNewLine}{e.Error.Message}"
            Dim oMessage2 = ""

            If TypeOf e.Error Is InitException Then
                Dim oException As InitException = DirectCast(e.Error, InitException)
                oMessage2 = $"{vbNewLine}{vbNewLine}Details: {oException?.InnerException?.Message}"
            End If

            Dim oMessage = $"{oMessageStart}{oMessage1}{oMessage2}{oMessageEnd}"

            MsgBox(oMessage, MsgBoxStyle.Critical, _MainForm.Text)
            Application.ExitThread()
        Else
            ' Copy back state from MyApplication Helper to My.Application
            Dim oMyApplication As My.MyApplication = DirectCast(e.Result, My.MyApplication)

            My.Application.Settings = oMyApplication.Settings
            My.Application.User = oMyApplication.User
            My.Application.Modules = oMyApplication.Modules
            My.Application.ModulesActive = oMyApplication.ModulesActive
            My.Application.ClipboardWatcher = oMyApplication.ClipboardWatcher

            RaiseEvent Completed(sender, Nothing)
        End If
    End Sub


#Region "=== Init Steps ==="
    Private Sub InitializeBase(MyApplication As My.MyApplication)
    End Sub

    Private Sub InitializeDatabase(MyApplication As My.MyApplication)
        'Dim oConnectionString = MSSQLServer.DecryptConnectionString(My.SystemConfig.ConnectionString)
        'My.DatabaseECM = New MSSQLServer(My.LogConfig, oConnectionString)

        'If My.DatabaseECM.DBInitialized = False Then
        '    Logger.Warn("Could not initialize DD_ECM-Database!")
        '    Throw New InitException("Could not initialize ECM-Database!")

        'Else
        '    Dim oSQl = "SELECT * FROM TBDD_CONNECTION WHERE BEZEICHNUNG = 'IDB' AND AKTIV = 1"
        '    Dim oDatatable As DataTable = My.DatabaseECM.GetDatatable(oSQl)

        '    If IsNothing(oDatatable) OrElse oDatatable.Rows.Count = 0 Then

        '        Dim oForm As New frmSQLConfig(My.LogConfig) With {.FormTitle = "IDB Datenbank"}
        '        Dim oResult = oForm.ShowDialog()

        '        If oResult = DialogResult.OK Then
        '            Dim oConnectionStringSaved = SaveConnectionString(oForm.ConnectionString)

        '            If oConnectionStringSaved = False Then
        '                Throw New InitException("Fehler beim Laden der IDB Verbindungsdaten!")
        '            End If

        '            oDatatable = My.Database.GetDatatableECM(oSQl)
        '        End If

        '    End If

        '    If oDatatable.Rows.Count > 1 Then
        '        Logger.Warn("Multiple IDB connection entries in TBDD_CONNECTION found!")
        '        Throw New InitException("Fehler beim Laden der IDB Verbindungsdaten!")
        '    End If

        '    Dim oDataRow As DataRow = oDatatable.Rows.Item(0)
        '    Dim oConString = My.DatabaseECM.GetConnectionString(
        '        oDataRow.Item("SERVER").ToString,
        '        oDataRow.Item("DATENBANK").ToString,
        '        oDataRow.Item("USERNAME").ToString,
        '        oDataRow.Item("PASSWORD").ToString
        '    )

        '    Dim oDecryptedConnectionString = MSSQLServer.DecryptConnectionString(oConString)
        '    My.DatabaseIDB = New MSSQLServer(My.LogConfig, oDecryptedConnectionString)
        'End If

        'If My.DatabaseIDB.DBInitialized = False Then
        '    Logger.Warn("Could not initialize IDB-Database!")
        '    Throw New InitException("Could not initialize IDB-Database!")
        'End If
    End Sub
    Private Sub InitializeService(MyApplication As My.MyApplication)
        Try
            If My.SystemConfig.AppServerConfig = String.Empty Then
                Dim oForm As New frmServiceConfig()
                Dim oResult = oForm.ShowDialog()

                If oResult <> DialogResult.OK Then
                    Throw New InitException("Could not initialize IDB-Service!")
                End If

                My.SystemConfig.AppServerConfig = oForm.ServiceAddress
                My.SystemConfigManager.Save()
            End If

            ' These Properties need to be set directly on
            My.Application.Service.Address = My.SystemConfig.AppServerConfig
            MyApplication.Service.Address = My.SystemConfig.AppServerConfig

            Dim oClient = New Client(LogConfig, My.SystemConfig.AppServerConfig)
            MyApplication.Service.Client = oClient
            My.Application.Service.Client = oClient

            If oClient Is Nothing Then
                Throw New InitException("Could not initialize IDB-Service!")
            End If

            Dim oConnectionResult = My.Application.Service.Client.Connect()
            If oConnectionResult = False Then
                Throw New InitException("Could not connect to Service!")
            End If
        Catch ex As Exception
            Logger.Error(ex)
            Throw New InitException("Error in InitializeService", ex)
        End Try
    End Sub
    Private Sub InitializeDatabaseWithFallback(MyApplication As My.MyApplication)
        Try
            Logger.Debug("Loading client config..")
            Dim oClientConfig = My.Application.Service.Client.ClientConfig

            Logger.Debug("Establishing ECM connection..")
            Dim oECMConnectionString = oClientConfig.ConnectionStringECM
            My.DatabaseECM = New MSSQLServer(My.LogConfig, oECMConnectionString)

            Logger.Debug("Establishing IDB connection..")
            Dim oIDBConnectionString = oClientConfig.ConnectionStringIDB
            My.DatabaseIDB = New MSSQLServer(My.LogConfig, oIDBConnectionString)

            Logger.Debug("Establishing Database connection with fallback..")
            My.Database = New DatabaseWithFallback(LogConfig, My.Application.Service.Client, My.DatabaseECM, My.DatabaseIDB)
        Catch ex As Exception
            Logger.Error(ex)
            Throw New InitException("Error in InitializeDatabaseWithFallback!", ex)
        End Try
    End Sub
    Private Sub InitializeUser(MyApplication As My.MyApplication)
        Try
            Dim oSql As String = My.Queries.Common.FNDD_MODULE_INIT(Environment.UserName)
            Dim oDatatable As DataTable = My.Database.GetDatatableECM(oSql)

            If oDatatable Is Nothing Then
                Throw New InitException("Benutzer konnte nicht geladen werden!")
            End If

            If oDatatable.Rows.Count <= 1 Then
                Throw New InitException("Benutzer konnte nicht gefunden werden!")
            End If

            For Each oRow As DataRow In oDatatable.Rows
                Dim oType As String = oRow.ItemEx("TYPE", "")

                Select Case oType
                    Case MODULE_USER
                        HandleUserInfo(MyApplication, oRow)

                    Case MODULE_CLIPBOARDWATCHER
                        HandleModuleInfo(MyApplication, oType, oRow)

                    Case MODULE_GLOBAL_INDEXER
                        HandleModuleInfo(MyApplication, oType, oRow)

                    Case MODULE_ZOOFLOW
                        HandleModuleInfo(MyApplication, oType, oRow)
                    Case MODULE_PROCESS_MANAGER
                        HandleModuleInfo(MyApplication, oType, oRow)
                End Select
            Next

        Catch ex As InitException
            Logger.Error(ex)
            Throw ex

        Catch ex As Exception
            Logger.Error(ex)
            Throw New InitException($"Unexpected error while initializing user!", ex)
        End Try
    End Sub
    Private Sub InitializeBasicsfromDB(MyApplication As My.MyApplication)
        Try
            Dim oSql As String = My.Queries.Common.IDB_CATALOG()
            Dim oDatatable As DataTable = My.Database.GetDatatableIDB(oSql)
            For Each oRow As DataRow In oDatatable.Rows
                Dim oCAT_TITLE As String = oRow.Item("CAT_TITLE")
                Logger.Debug($"IDB_CATALOG_STRING: {oRow.Item("CAT_STRING")}")

            Next

        Catch ex As InitException
            Logger.Error(ex)
            Throw ex

        Catch ex As Exception
            Logger.Error(ex)
            Throw New InitException($"Unexpected error while initializing basics from DB!", ex)
        End Try
    End Sub
    Private Sub InitializeLanguage(MyApplication As My.MyApplication)
        Dim oLanguage = MyApplication.User.Language
        Dim oDateFormat = MyApplication.User.DateFormat
        Dim oCultureInfo As New CultureInfo(oLanguage)
        oCultureInfo.DateTimeFormat.ShortDatePattern = oDateFormat
        Thread.CurrentThread.CurrentCulture = oCultureInfo
        Thread.CurrentThread.CurrentUICulture = oCultureInfo
        CultureInfo.DefaultThreadCurrentCulture = oCultureInfo
        CultureInfo.DefaultThreadCurrentUICulture = oCultureInfo
    End Sub
    Private Sub Initialize3rdParty(MyApplication As My.MyApplication)
        Try
            Dim oSql = "Select LICENSE FROM TBDD_3RD_PARTY_MODULES WHERE NAME = 'GDPICTURE'"
            Dim oDatatable As DataTable = My.Database.GetDatatable("TBDD_3RD_PARTY_MODULES", oSql, EDMI.API.Constants.DatabaseType.ECM, "NAME = 'GDPICTURE'")

            If oDatatable.Rows.Count = 0 Then
                Throw New InitException("Konfiguration 3RD_PARTY_MODULES konnte nicht geladen werden!")
            End If

            Dim oRow As DataRow = oDatatable.Rows.Item(0)

            MyApplication.Settings.GdPictureKey = NotNull(oRow.Item("LICENSE"), String.Empty)
        Catch ex As Exception
            Logger.Error(ex)
            Throw New InitException("Error Initialize3rdParty!", ex)
        End Try
    End Sub
    Private Sub InitBasicConfig(MyApplication As My.MyApplication)
        Try
            Dim oSql As String

            oSql = "Select * FROM TBIDB_COMMON_SQL WHERE ACTIVE = 1"
            My.Tables.DTIDB_COMMON_SQL = My.Database.GetDatatable("TBIDB_COMMON_SQL", oSql, EDMI.API.Constants.DatabaseType.IDB)

            For Each oRow As DataRow In My.Tables.DTIDB_COMMON_SQL.Rows
                Dim oTITLE = oRow.Item("TITLE").ToString
                Dim oBaseSQL = oRow.Item("SQL_COMMAND").ToString
                oBaseSQL = oBaseSQL.Replace("@USER_ID", My.Application.User.UserId)
                oBaseSQL = oBaseSQL.Replace("@USERID", My.Application.User.UserId)
                oBaseSQL = oBaseSQL.Replace("@USRID", My.Application.User.UserId)
                oBaseSQL = oBaseSQL.Replace("@USRNAME", My.Application.User.UserName)
                oBaseSQL = oBaseSQL.Replace("@UserName", My.Application.User.UserName)
                oBaseSQL = oBaseSQL.Replace("@LANG_CODE_SHORT", Right(My.Application.User.Language, 2))
                oBaseSQL = oBaseSQL.Replace("@LANG_CODE", My.Application.User.Language)
                oBaseSQL = oBaseSQL.Replace("{#INT#USERNAME}", My.Application.User.UserName)

                If oTITLE = SQLCMD_FLOW_SEARCH_BASE Then
                    SQL_FLOW_SEARCH_BASE = oBaseSQL
                ElseIf oTITLE = SQLCMD_AHW_LAYOUT_SELECT Then
                    SQL_AHW_LAYOUT_SELECT = oBaseSQL
                ElseIf oTITLE = SQLCMD_AHW_USR_SELECT Then
                    SQL_AHW_USR_SELECT = oBaseSQL
                ElseIf oTITLE = SQLCMD_RECENT_FILES_USER Then
                    SQL_RECENT_FILES_USER = oBaseSQL
                End If
            Next

            oSql = $"SELECT * FROM TBIDB_CATALOG_USER WHERE USR_ID = {My.Application.User.UserId}"
            My.Tables.DTIDB_CATALOG_USER = My.Database.GetDatatable("TBIDB_CATALOG_USER", oSql, EDMI.API.Constants.DatabaseType.IDB, $"USR_ID = {My.Application.User.UserId}")

            For Each oRow As DataRow In My.Tables.DTIDB_CATALOG_USER.Rows
                If oRow.Item("CAT_TITLE") = ClassConstants.USER_CATALOG_APPLICATION_THEME Then
                    Dim oThemeName As String = oRow.ItemEx("CAT_STRING", "Digital Data")

                    If oThemeName.Contains("|") Then
                        Dim oSkin = oThemeName.Split("|").ElementAt(0)
                        Dim oPalette = oThemeName.Split("|").ElementAt(1)

                        MyApplication.Skin = oSkin
                        MyApplication.Palette = oPalette
                    Else
                        MyApplication.Skin = oThemeName
                        MyApplication.Palette = ""
                    End If
                ElseIf oRow.Item("CAT_TITLE") = ClassConstants.USER_CATALOG_GLOBIX_DROPAREA Then
                    My.Application.GlobixDropAreaStyle = oRow.Item("CAT_STRING")
                End If
            Next

            oSql = $"Select * From VWIDB_BE_ATTRIBUTE Where LANG_CODE = '{MyApplication.User.Language}'"
            My.Tables.DTIDB_ATTRIBUTE = My.Database.GetDatatable("VWIDB_BE_ATTRIBUTE", oSql, EDMI.API.Constants.DatabaseType.IDB, $"LANG_CODE = '{MyApplication.User.Language}'")


            If SQL_FLOW_SEARCH_BASE = "" Then
                Logger.Warn($"ATTENTION: NO DocResultBaseSearch - Check if entry {SQLCMD_FLOW_SEARCH_BASE} exists in TBIDB_COMMON_SQL")
            End If

        Catch ex As Exception
            Logger.Error(ex)
            Throw New InitException("Error in InitBasicData", ex)
        End Try
    End Sub

#End Region

    Private Function SetupDatabase() As Boolean
        'If My.SystemConfig.ConnectionString = String.Empty Then
        '    Dim oConnectionString = My.SystemConfig.ConnectionString
        '    Dim oForm As New frmSQLConfig(My.LogConfig) With {
        '        .ConnectionString = oConnectionString,
        '        .FormTitle = "ECM Datenbank"
        '    }
        '    Dim oResult = oForm.ShowDialog()

        '    If oResult = DialogResult.OK Then
        '        My.SystemConfig.ConnectionString = oForm.ConnectionString
        '        My.SystemConfigManager.Save()

        '        Return True
        '    Else
        '        Return False
        '    End If
        'End If

        Return True
    End Function

    Private Function SaveConnectionString(pConnectionString As String) As Boolean
        Try
            Dim oBuilder As New SqlConnectionStringBuilder(pConnectionString)
            Dim oSql = $"
                INSERT INTO TBDD_CONNECTION 
                (BEZEICHNUNG, SQL_PROVIDER, SERVER, DATENBANK, USERNAME, PASSWORD, BEMERKUNG, AKTIV, ERSTELLTWER) 
                VALUES ('IDB', 'MS-SQLServer', '{oBuilder.DataSource}', '{oBuilder.InitialCatalog}', '{oBuilder.UserID}', '{oBuilder.Password}', 'Created by Zooflow', 1, '{Environment.UserName}')"

            Return My.Database.ExecuteNonQueryECM(oSql)
        Catch ex As Exception
            Logger.Error(ex)
            Return False
        End Try
    End Function

    Private Sub ProgressChanged(sender As Object, Progress As InitProgress)
        SplashScreenManager.Default.SendCommand(frmSplash.SplashScreenCommand.SetProgress, Progress.CurrentPercent)
        SplashScreenManager.Default.SendCommand(frmSplash.SplashScreenCommand.SetActionName, Progress.CurrentStep.Name)
    End Sub

    Private Sub HandleUserInfo(MyApplication As My.MyApplication, Row As DataRow)
        Dim oValue As Object = Row.Item("VALUE")
        Dim oName As String = Row.Item("NAME").ToString

        Select Case oName
            Case "USER_ID"
                MyApplication.User.UserId = CInt(oValue)
            Case "USER_PRENAME"
                MyApplication.User.GivenName = NotNull(oValue.ToString, String.Empty)
            Case "USER_SURNAME"
                MyApplication.User.Surname = NotNull(oValue.ToString, String.Empty)
            Case "USER_SHORTNAME"
                MyApplication.User.ShortName = NotNull(oValue.ToString, String.Empty)
            Case "USER_EMAIL"
                MyApplication.User.Email = NotNull(oValue.ToString, String.Empty)
            Case "USER_DATE_FORMAT"
                MyApplication.User.DateFormat = NotNull(oValue.ToString, "dd.MM.yyyy")
            Case "USER_LANGUAGE"
                MyApplication.User.Language = NotNull(oValue.ToString, "de-DE")
            Case "USER_LANGUAGEID"
                MyApplication.User.LanguageId = CShort(oValue)
        End Select
    End Sub
    Private Sub HandleModuleInfo(MyApplication As My.MyApplication, ModuleName As String, Row As DataRow)
        Dim oValue As Object = Row.Item("VALUE")
        Dim oName As String = Row.Item("NAME").ToString

        If Not MyApplication.Modules.ContainsKey(ModuleName) Then
            MyApplication.Modules.Item(ModuleName) = New DigitalData.Modules.ZooFlow.State.ModuleState()
        End If

        Select Case oName
            Case "MODULE_ACCESS"
                If CBool(oValue) Then
                    SyncLock MyApplication.ModulesActive
                        MyApplication.ModulesActive.Add(ModuleName)
                    End SyncLock
                End If
                MyApplication.Modules.Item(ModuleName).HasAccess = CBool(oValue)

            Case "IS_ADMIN"
                MyApplication.Modules.Item(ModuleName).IsAdmin = CBool(oValue)

            Case "USER_COUNT_LOGGED_IN"
                MyApplication.Modules.Item(ModuleName).LoggedIn = CInt(oValue) + 1

            Case "RESULT"
                Dim oLines = oValue.ToString.Split("|"c)
                Logger.Debug("Access Result for Module {0}", ModuleName)
                For Each oLine In oLines
                    Logger.Debug(oLine.Trim)
                Next
            Case "WORKING_MODE"
                Dim oLines = oValue.ToString.Split("|"c)
                Logger.Debug("WORKING_MODEs for Module {0}", ModuleName)
                For Each oLine In oLines
                    Logger.Debug(oLine.Trim)
                    If oLine = "NO_BASICCONF" Then
                        MyApplication.User.HideBasicConfig = True

                    ElseIf oLine.StartsWith("SEARCH_STRING_ATTRID") Then
                        Try
                            Dim oResult = oLine.Replace("SEARCH_STRING_ATTRID=", "")
                            MyApplication.Search.SelectInStringAttributeIds = oResult
                        Catch ex As Exception
                            MyApplication.Search.SelectInStringAttributeIds = ""
                        End Try
                    ElseIf oLine.StartsWith("SEARCH_INT_ATTRID") Then
                        Try
                            Dim oResult = oLine.Replace("SEARCH_INT_ATTRID=", "")

                            MyApplication.Search.SelectInIntegerAttributeIds = oResult
                        Catch ex As Exception
                            MyApplication.Search.SelectInIntegerAttributeIds = ""
                        End Try
                    Else
                        Logger.Info($"Wrong WorkingMode: {oLine}")
                    End If
                Next

        End Select
    End Sub
End Class
