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

Public Class ClassInit
    Private _MainForm As frmFlowForm
    Private _Logger As Logger
    Private _LogConfig As LogConfig
    Private _DataASorDB As ClassDataASorDB
    Private _Loader As ClassInitLoader

    Public Event Completed As EventHandler

    Public Sub New(LogConfig As LogConfig, ParentForm As frmFlowForm)
        _MainForm = ParentForm
        _Logger = LogConfig.GetLogger()
        _LogConfig = LogConfig
        _DataASorDB = New ClassDataASorDB(LogConfig)
        clsDataASorDB = _DataASorDB
    End Sub

    Public Sub InitializeApplication()
        ' Init Connectivity
        ' - Database / Service / Application Server
        ' (Init Licensing)
        ' Init User
        ' Init IDB
        ' Zeile -> Objekt / NameValue List

        If Not SetupDatabase() Then
            MsgBox("Keine Verbindungs-Informationen hinterlegt. Anwendung wird beendet.", MsgBoxStyle.Critical, _MainForm.Text)
            Application.Exit()
        Else
            _Loader = New ClassInitLoader()

            ' === Init Schritte definieren
            _Loader.AddStep("Checking connectivity..", AddressOf CheckConnectivity, True)
            _Loader.AddStep("Initializing User..", AddressOf InitializeUser, True)
            _Loader.AddStep("Initializing IDB Database..", AddressOf InitializeIDBDatabase, True)
            _Loader.AddStep("Initializing IDB Service..", AddressOf InitializeIDBService, True)
            _Loader.AddStep("Initializing Language..", AddressOf InitializeLanguage, False)
            _Loader.AddStep("Loading 3rd-party licenses..", AddressOf Initialize3rdParty, False)
            _Loader.AddStep("Loading Basic Configs..", AddressOf InitBasicData, False)
            ' === Init Schritte definieren

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

            _Loader.Run()
        End If
    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 Function SetupDatabase() As Boolean
        If My.SystemConfig.ConnectionString = String.Empty Then
            Dim oConnectionString = My.SystemConfig.ConnectionString

            Dim ofrmSQLConfig As New frmSQLConfig(My.LogConfig) With {.ConnectionString = oConnectionString}

            Dim oResult = ofrmSQLConfig.ShowDialog()

            If oResult = DialogResult.OK Then
                My.SystemConfig.ConnectionString = ofrmSQLConfig.ConnectionString

                Return True
            Else
                MsgBox("Es wurde keine Datenbank hinterlegt. Die Anwendung wird beendet.")
                Return False
            End If
        End If

        Return True
    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 InitCompleted(sender As Object, e As RunWorkerCompletedEventArgs)
        If Not IsNothing(e.Error) Then
            MsgBox("Beim Initialisieren des Programms ist folgender Fehler aufgetreten:" & vbNewLine & vbNewLine & e.Error.Message, 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

    Private Sub CheckConnectivity(MyApplication As My.MyApplication)
        Dim oCrypt As New EncryptionLegacy(CRYPTO_LEGACY_ENCRYPTION_KEY)
        Dim oBuilder = My.SystemConfig.GetConnectionStringBuilder(My.SystemConfig.ConnectionString)
        oBuilder.Password = oCrypt.DecryptData(oBuilder.Password)
        Dim oDecryptedConnectionString = oBuilder.ToString

        My.Database = New MSSQLServer(My.LogConfig, oDecryptedConnectionString)

        If My.Database.DBInitialized = False Then
            _Logger.Warn("Could not initialize DD_ECM-Database!")
            Throw New InitException("Could not initialize DD_ECM-Database!")
        End If
    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 = _DataASorDB.GetDatatable("DD_ECM", oSql, "TBDD_3RD_PARTY_MODULES", "", "")

            If oDatatable.Rows.Count = 0 Then
                Throw New InitException("Konfiguration 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 initializing3rdParty!", ex)
        End Try
    End Sub
    Private Sub InitBasicData(MyApplication As My.MyApplication)
        Try
            Dim oSql = ""

            oSql = "SELECT * FROM TBIDB_COMMON_SQL WHERE ACTIVE = 1"
            My.Tables.DTIDB_COMMON_SQL = _DataASorDB.GetDatatable("IDB", oSql, "TBIDB_COMMON_SQL", "", "")
            oSql = "SELECT * FROM TBIDB_CATALOG"
            My.Tables.DTIDB_CATALOG = _DataASorDB.GetDatatable("IDB", oSql, "TBIDB_CATALOG", "", "")
            For Each oRow As DataRow In My.Tables.DTIDB_CATALOG.Rows
                'Console.WriteLine(oRow.Item("CAT_TITLE").ToString)
                Select Case oRow.Item("CAT_TITLE").ToString
                    Case "FILESTORE_ARCHIVE"
                        My.Filestore_Archive = oRow.Item("CAT_STRING")
                    Case "FILESTORE_WORK"
                        My.Filestore_Work = oRow.Item("CAT_STRING")
                        My.Filestore_Work = "Q:\DigitalData - IDB"

                End Select

            Next
            oSql = "SELECT * FROM TBDD_CONNECTION"

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

    Private Sub InitializeIDBService(MyApplication As My.MyApplication)
        Try
            MyApplication.Service.Address = My.SystemConfig.AppServerConfig

            Dim oSplit() As String = MyApplication.Service.Address.Split(":"c)
            Dim oAppServerAddress As String = oSplit(0)
            Dim oAppServerPort As Integer = 9000
            If oSplit.Length = 2 Then
                oAppServerPort = oSplit(1)
            End If
            My.Application.Service.Client = New Client(_LogConfig, oAppServerAddress, oAppServerPort)
            If Not IsNothing(My.Application.Service.Client) Then
                If My.Application.Service.Client.Connect() Then
                    MyApplication.Service.IsActive = True
                End If
            End If
        Catch ex As Exception
            _Logger.Error(ex)
            Throw New InitException("Error in InitBasicData", ex)
        End Try
    End Sub

    Private Sub InitializeIDBDatabase(MyApplication As My.MyApplication)
        If MyApplication.ModulesActive.Contains(MODULE_ZOOFLOW) Then
            If My.Database.DBInitialized Then
                Dim oSQl = "SELECT * FROM TBDD_CONNECTION WHERE BEZEICHNUNG = 'IDB'"
                Dim oDatatable As DataTable = My.Database.GetDatatable(oSQl)

                If IsNothing(oDatatable) OrElse oDatatable.Rows.Count = 0 Then
                    _Logger.Warn("No IDB connection entries in TBDD_CONNECTION found!")
                    Throw New InitException("Fehler beim Laden der IDB Verbindungsdaten!")
                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.Database.GetConnectionString(
                    oDataRow.Item("SERVER").ToString,
                    oDataRow.Item("DATENBANK").ToString,
                    oDataRow.Item("USERNAME").ToString,
                    oDataRow.Item("PASSWORD").ToString)

                My.DatabaseIDB = New MSSQLServer(My.LogConfig, oConString)
                If My.DatabaseIDB.DBInitialized = False Then
                    _Logger.Warn("Could not initialize IDB-Database!")
                    Throw New InitException("Could not initialize IDB-Database!")
                End If
            End If
        Else
            _Logger.Warn("ZooFlow missing from Active Modules!")
            Throw New InitException("ZooFlow Modul ist nicht aktiv oder nicht lizensiert!")
        End If
    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.GetDatatable(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("TYPE").ToString

                Select Case oType
                    Case "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)
                End Select
            Next

        Catch ex As Exception
            _Logger.Error(ex)
            Throw New InitException("Error while initializing user!", ex)
        End Try
    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
