Imports System.ComponentModel
Imports System.Windows.Forms
Imports DevExpress.XtraBars.Ribbon
Imports DevExpress.XtraRichEdit.Services
Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Patterns

Public Class frmSQLEditor

    Private ReadOnly Patterns As ClassPatterns
    Private ReadOnly LogConfig As LogConfig
    Private ReadOnly Database As MSSQLServer
    Private ReadOnly Placeholders As SQLEditor.Placeholders
    Private ReadOnly FormHelper As FormHelper
    Private ReadOnly GridHelper As GridBuilder

    Private ClearPlaceholdersAfterSuccessfulExecute As Boolean = False
    Private FormLoading As Boolean = False
    Private FormResult As DialogResult = DialogResult.Cancel

    Public Property SQLCommand As String = ""
    Public Property SQLConnection As Integer = 0
    Public Property AllowSQLConnectionSelection As Boolean = True

    Public Property LoadClipboardPlaceholders As Boolean = False

    Public Property PlaceholdersManual As Dictionary(Of String, String)
    Public Property PlaceholdersManualPrefix As String
    Public Property PlaceholdersManualTitle As String = "Manuelles Attribut"

    Public Property PlaceholdersAutomatic As Dictionary(Of String, String)
    Public Property PlaceholdersAutomaticPrefix As String
    Public Property PlaceholdersAutomaticTitle As String = "Automatisches Attribut"
    Public Property PlaceholdersWindream As List(Of String)

    Public Sub New(pLogConfig As LogConfig, pDatabase As MSSQLServer)
        MyClass.New(pLogConfig, pDatabase, True)
    End Sub

    Public Sub New(pLogConfig As LogConfig, pDatabase As MSSQLServer, pAllowConnectionIdSelection As Boolean)
        ' Dieser Aufruf ist für den Designer erforderlich.
        InitializeComponent()

        ' Fügen Sie Initialisierungen nach dem InitializeComponent()-Aufruf hinzu.
        LogConfig = pLogConfig
        Database = pDatabase
        Patterns = New ClassPatterns(LogConfig)
        Placeholders = New SQLEditor.Placeholders()
        FormHelper = New FormHelper(pLogConfig, Me)
        GridHelper = New GridBuilder()
        AllowSQLConnectionSelection = pAllowConnectionIdSelection
    End Sub

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        FormLoading = True

        txtSQLCommand.BeginUpdate()

        Try
            If AllowSQLConnectionSelection = False Then
                GalleryConnection.Visibility = DevExpress.XtraBars.BarItemVisibility.Never
            End If

            If PlaceholdersAutomatic Is Nothing Then
                PlaceholdersAutomatic = New Dictionary(Of String, String)
            End If

            If PlaceholdersManual Is Nothing Then
                PlaceholdersManual = New Dictionary(Of String, String)
            End If

            If PlaceholdersWindream Is Nothing Then
                PlaceholdersWindream = New List(Of String)
            End If

            If SQLCommand <> String.Empty Then
                txtSQLCommand.Document.Text = SQLCommand
            End If

            Dim oConnectionGroup = LoadConnections()
            Dim oSelectedItem = Nothing

            ' Missing/Negative connection will always result in default (DD_ECM) connection
            If SQLConnection <= 0 Then
                SQLConnection = 1
            End If

            ' Select the supplied connection in the ribbon gallery
            For Each oItem As GalleryItem In oConnectionGroup.Items
                Dim oConnection = oItem.Tag
                If SQLConnection = oConnection.id Then
                    oSelectedItem = oItem
                End If
            Next

            GalleryConnection.Gallery.Groups.Add(oConnectionGroup)

            If oSelectedItem IsNot Nothing Then
                GalleryConnection.Gallery.SetItemCheck(oSelectedItem, True)
            End If

            Dim oPlaceholderGroups = LoadPlaceholders()
            GalleryPlaceholders.Gallery.Groups.AddRange(oPlaceholderGroups.ToArray)

            ConfigureRichEditControl()

            GridHelper.SetDefaults(ViewPlaceholders)
            ViewPlaceholders.OptionsView.ShowAutoFilterRow = False

            chkClearPlaceholders.Checked = ClearPlaceholdersAfterSuccessfulExecute

            ResizePlaceholderPanel()
        Catch ex As Exception
        Finally
            txtSQLCommand.EndUpdate()
            FormLoading = False
        End Try

    End Sub

    Private Sub RibbonGalleryBarItem1_GalleryItemClick(sender As Object, e As GalleryItemClickEventArgs) Handles GalleryPlaceholders.GalleryItemClick
        Dim oPlaceholder As SQLEditor.Placeholder = e.Item.Tag
        Dim pPosition = txtSQLCommand.Document.CaretPosition
        txtSQLCommand.Document.InsertSingleLineText(pPosition, Patterns.WrapPatternValue(oPlaceholder.Module, oPlaceholder.Name))
    End Sub

    Private Sub RibbonGalleryBarItem2_GalleryItemClick(sender As Object, e As GalleryItemClickEventArgs) Handles GalleryConnection.GalleryItemClick
        Dim oConnection As Connection = e.Item.Tag
        SQLConnection = oConnection.Id
    End Sub

    Private Function LoadPlaceholders() As List(Of GalleryItemGroup)
        Dim oPlaceholders = New List(Of GalleryItemGroup)()

        Dim oAutomaticAttributes = Placeholders.GetAutomaticPlaceholders(PlaceholdersAutomatic, PlaceholdersAutomaticPrefix, PlaceholdersAutomaticTitle)
        If oAutomaticAttributes IsNot Nothing Then
            oPlaceholders.Add(oAutomaticAttributes)
        End If

        Dim oManualPlaceholders = Placeholders.GetManualPlaceholders(PlaceholdersManual, PlaceholdersManualPrefix, PlaceholdersManualTitle)
        If oManualPlaceholders IsNot Nothing Then
            oPlaceholders.Add(oManualPlaceholders)
        End If

        Dim oWindreamPlaceholders = Placeholders.GetWindreamPlaceholders(PlaceholdersWindream)
        If oWindreamPlaceholders IsNot Nothing Then
            oPlaceholders.Add(oWindreamPlaceholders)
        End If

        If LoadClipboardPlaceholders Then
            oPlaceholders.Add(Placeholders.GetClipboardPlaceholder)
        End If

        oPlaceholders.Add(Placeholders.GetUserPlaceholders())
        oPlaceholders.Add(Placeholders.GetInternalPlaceholders())

        Return oPlaceholders
    End Function

    Private Function LoadConnections() As GalleryItemGroup
        Try
            Dim oSql = "SELECT GUID, Bezeichnung FROM TBDD_CONNECTION WHERE AKTIV = 1"
            Dim oTable = Database.GetDatatable(oSql)
            Dim oConnections = New List(Of Connection)

            For Each oRow As DataRow In oTable.Rows
                oConnections.Add(New Connection() With {
                                 .Id = oRow.Item("GUID"),
                                 .Name = oRow.Item("Bezeichnung")})
            Next

            Dim oConnectionGroup = New GalleryItemGroup() With {.Caption = "Verbindungen"}
            Dim oItems As New List(Of GalleryItem)

            For Each oConnection In oConnections

                'Preselect the first connection if no selection was made
                Dim oChecked = False
                If SQLConnection = 0 AndAlso oConnection.Id = oConnections.First.Id Then
                    oChecked = True
                Else : oChecked = False
                End If

                oItems.Add(GetConnectionGalleryItem(oConnection, oChecked))
            Next

            oConnectionGroup.Items.AddRange(oItems.ToArray)

            Return oConnectionGroup
        Catch ex As Exception
            Return Nothing
        End Try
    End Function

    Private Sub ConfigureRichEditControl()
        txtSQLCommand.Options.Search.RegExResultMaxGuaranteedLength = 500
        txtSQLCommand.ReplaceService(Of ISyntaxHighlightService)(New SQLEditor.SQLSyntaxHighlightService(txtSQLCommand.Document))
        txtSQLCommand.ActiveViewType = DevExpress.XtraRichEdit.RichEditViewType.Simple
        txtSQLCommand.Document.Sections(0).Page.Width = DevExpress.Office.Utils.Units.InchesToDocumentsF(80.0F)

        txtSQLCommand.Document.DefaultCharacterProperties.FontName = "Courier New"
        txtSQLCommand.Document.DefaultCharacterProperties.FontSize = 10
    End Sub


    Private Sub ClearPlaceholders()
        Dim oPlaceholders As List(Of SQLEditor.Placeholder) = GridPlaceholders.DataSource

        oPlaceholders.ForEach(Sub(placeholder) placeholder.Value = "")

        GridPlaceholders.DataSource = oPlaceholders
    End Sub

    Private Function GetConnectionGalleryItem(pConnection As Connection, Optional pChecked As Boolean = False) As GalleryItem
        Dim oItem = New GalleryItem(Nothing, pConnection.Name, Nothing) With {
            .Tag = pConnection,
            .Checked = pChecked
        }

        oItem.ImageOptions.SvgImage = My.Resources.actions_database

        Return oItem
    End Function

    Private Property LastPatterns As New List(Of Pattern)

    Private Sub RichEditControl1_ContentChanged(sender As Object, e As EventArgs) Handles txtSQLCommand.ContentChanged
        UpdatePlaceholders()
    End Sub

    Private Sub BarButtonItem3_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles btnExecuteSQL.ItemClick
        ExecuteSQL()
    End Sub

    Private Class Connection
        Public Property Id As Integer
        Public Property Name As String
    End Class

    Private Sub UpdatePlaceholders()
        Dim oSqlText = txtSQLCommand.Document.Text
        Dim oPatterns = Patterns.GetAllPatterns(oSqlText)

        If oPatterns.Count = 0 Then
            GridPlaceholders.DataSource = New List(Of SQLEditor.Placeholder)
        ElseIf oPatterns.Count.Equals(LastPatterns.Count) Then
            ' noop
        Else
            Dim oPlaceholders = oPatterns.
                Distinct().
                Select(Function(pattern) New SQLEditor.Placeholder(pattern.Value, pattern.Value, pattern.Type, pattern.Value) With {.Pattern = pattern}).
                ToList()
            GridPlaceholders.DataSource = oPlaceholders
        End If

        LastPatterns = oPatterns
    End Sub

    Private Sub ExecuteSQL()
        Try
            ViewPlaceholders.FocusInvalidRow()

            Dim oSql = txtSQLCommand.Document.Text
            Dim oPlaceholders As List(Of SQLEditor.Placeholder) = GridPlaceholders.DataSource

            If oPlaceholders IsNot Nothing Then
                For Each oPlaceholder In oPlaceholders
                    Dim oWrapped = Patterns.WrapPatternValue(oPlaceholder.Module, oPlaceholder.Name)

                    If oPlaceholder.Value Is Nothing Then
                        Throw New ApplicationException($"Der Platzhalter '{oWrapped}' wurde nicht ausgefüllt!")
                    End If

                    oSql = oSql.Replace(oWrapped, oPlaceholder.Value)
                Next
            End If

            Dim oDatatable As DataTable

            If SQLConnection > 0 Then
                Dim oConnectionString = Database.GetConnectionStringForId(SQLConnection)
                oDatatable = Database.GetDatatableWithConnection(oSql, oConnectionString)
            Else
                oDatatable = Database.GetDatatable(oSql)
            End If

            If ClearPlaceholdersAfterSuccessfulExecute Then
                ClearPlaceholders()
            End If

            Dim oForm As New frmSQLResult(oDatatable)
            oForm.Show()

        Catch ex As ApplicationException
            MsgBox(ex.Message, MsgBoxStyle.Exclamation, Text)

        Catch ex As Exception
            MsgBox(ex.Message, MsgBoxStyle.Critical, Text)
        End Try
    End Sub

    Private Sub BarCheckItem1_CheckedChanged(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles chkClearPlaceholders.CheckedChanged
        If FormLoading = False Then
            ClearPlaceholdersAfterSuccessfulExecute = chkClearPlaceholders.Checked
        End If
    End Sub

    Private Sub btnClearPlaceholders_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles btnClearPlaceholders.ItemClick
        ClearPlaceholders()
    End Sub

    Private Sub chkShowPlaceholders_CheckedChanged(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles chkShowPlaceholders.CheckedChanged
        SplitContainerControl1.Collapsed = Not chkShowPlaceholders.Checked
    End Sub
    Private Sub SplitContainerControl1_SplitGroupPanelCollapsed(sender As Object, e As DevExpress.XtraEditors.SplitGroupPanelCollapsedEventArgs) Handles SplitContainerControl1.SplitGroupPanelCollapsed
        chkShowPlaceholders.Checked = Not e.Collapsed
    End Sub

    Private Sub btnSave_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles btnSave.ItemClick
        SQLCommand = txtSQLCommand.Text
        FormResult = DialogResult.OK
        Close()
    End Sub

    Private Sub frmSQLEditor_KeyDown(sender As Object, e As KeyEventArgs) Handles MyBase.KeyDown
        If e.KeyCode = Keys.F5 Then
            ExecuteSQL()
        End If
    End Sub

    Private Sub frmSQLEditor_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
        DialogResult = FormResult

    End Sub

    Private Sub frmSQLEditor_ResizeEnd(sender As Object, e As EventArgs) Handles MyBase.ResizeEnd
        ResizePlaceholderPanel()
    End Sub

    Private LastWindowState As FormWindowState = FormWindowState.Normal
    Private Sub frmSQLEditor_Resize(sender As Object, e As EventArgs) Handles MyBase.Resize
        If LastWindowState <> WindowState Then
            LastWindowState = WindowState
            ResizePlaceholderPanel()
        End If
    End Sub

    Private Sub ResizePlaceholderPanel()
        Dim oSplitterPosition As Integer = SplitContainerControl1.SplitterPosition
        Dim oWindowWidth As Integer = Width
        Dim oPlaceholdersExpanded As Boolean = Not SplitContainerControl1.Collapsed

        If oSplitterPosition > oWindowWidth Then
            oSplitterPosition = oWindowWidth * 0.7
        ElseIf oSplitterPosition < (oWindowWidth * 0.5) Then
            oSplitterPosition = oWindowWidth * 0.7
        ElseIf oSplitterPosition > (oWindowWidth * 0.9) Then
            oSplitterPosition = oWindowWidth * 0.7
        End If

        SplitContainerControl1.SplitterPosition = oSplitterPosition
    End Sub
End Class
