Imports System.Windows.Forms
Imports System.Drawing
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Language.Utils
Imports DevExpress.XtraEditors
Imports DigitalData.Controls.LookupGrid

Public Class ControlCreator
    Private Form As Form
    Private Panel As Panel
    Private LogConfig As LogConfig
    Private Logger As Logger

    Private Const DEFAULT_HEIGHT = 27
    Private Const DEFAULT_WIDTH = 450
    Private Const DEFAULT_POSITION_X = 11

    Private Const TYPE_BOOLEAN = "BOOLEAN"
    Private Const TYPE_DATE = "DATE"
    Private Const TYPE_INTEGER = "INTEGER"
    Private Const TYPE_VARCHAR = "VARCHAR"

    Private Const PLACEHOLDER_NULL = "$NULL"
    Private Const VECTORSEPARATOR = "╚"

    Public Property HightlightColor As Color = Color.FromArgb(255, 214, 49)
    Public Property OnControlChanged As Action(Of Control)

    ''' <summary>
    ''' Callback Function to Return the Lookup Control's Datasource
    ''' Receives the following values:
    ''' - Control
    ''' - SQL Command
    ''' - Connection ID
    ''' </summary>
    ''' <returns>The Datatable which  contains the Control's Data</returns>
    Public Property OnLookupData As Func(Of Control, String, Integer, DataTable)

    Public Class ControlMeta
        Public Property IndexName As String
        Public Property IndexType As String
        Public Property ControlType As String
        Public Property MultipleValues As Boolean = False
    End Class

    Public Sub New(LogConfig As LogConfig, Panel As Panel, Form As Form)
        Me.Form = Form
        Me.Panel = Panel
        Me.LogConfig = LogConfig
        Me.Logger = LogConfig.GetLogger
    End Sub

    Function AddLabel(pIndexName As String, hinweis As String, ylbl As Integer, anz As String) As Label
        Dim lbl As New Label With {
            .Name = "lbl" & pIndexName,
            .AutoSize = True,
            .Text = hinweis,
            .Location = New Point(11, ylbl)
        }

        Return lbl
    End Function

    Public Function AddDateTimePicker(pIndexname As String, pY As Integer, pDefaultValue As String) As DateEdit
        Dim oPicker As New DateEdit With {
            .Name = "dtp" & pIndexname,
            .Size = New Size(DEFAULT_WIDTH, DEFAULT_HEIGHT),
            .Location = New Point(DEFAULT_POSITION_X, pY),
            .Tag = New ControlMeta() With {
                .IndexName = pIndexname,
                .IndexType = TYPE_DATE,
                .ControlType = "dtp"
            }
        }

        If pDefaultValue.ToUpper = PLACEHOLDER_NULL Then
            oPicker.EditValue = Nothing
        ElseIf pDefaultValue IsNot Nothing Then
            oPicker.EditValue = pDefaultValue
        End If

        oPicker.Properties.AppearanceFocused.BackColor = HightlightColor

        Return oPicker
    End Function

    Public Function AddTextBox(pIndexname As String, pY As Integer, pDefaultValue As String, pDataType As String) As TextEdit
        Dim oEdit As New TextEdit With {
            .Name = "txt" & pIndexname,
            .Size = New Size(DEFAULT_WIDTH, DEFAULT_HEIGHT),
            .Location = New Point(DEFAULT_POSITION_X, pY),
            .Tag = New ControlMeta() With {
                .IndexName = pIndexname,
                .IndexType = pDataType,
                .ControlType = "txt"
            }
        }

        Select Case pDataType
            Case TYPE_INTEGER
                oEdit.Properties.Mask.MaskType = Mask.MaskType.Numeric
                oEdit.Properties.Mask.EditMask = "d"
        End Select

        If pDefaultValue IsNot Nothing Then
            oEdit.Text = pDefaultValue
            oEdit.SelectAll()
        End If

        AddHandler oEdit.GotFocus, AddressOf OnTextBoxFocus
        AddHandler oEdit.LostFocus, AddressOf OnTextBoxLostFocus
        AddHandler oEdit.KeyUp, AddressOf OnTextBoxKeyUp
        AddHandler oEdit.TextChanged, AddressOf OnTextBoxTextChanged

        Return oEdit
    End Function

    Private Sub OnTextBoxFocus(sender As TextEdit, e As EventArgs)
        sender.BackColor = HightlightColor
        sender.SelectAll()
    End Sub

    Private Sub OnTextBoxTextChanged(sender As TextEdit, e As System.EventArgs)
        Using oGraphics As Graphics = sender.CreateGraphics()
            Dim oNewWidth = oGraphics.MeasureString(sender.Text, sender.Font).Width + 15
            If oNewWidth >= DEFAULT_WIDTH Then
                sender.Width = oNewWidth
            End If
        End Using
    End Sub

    Private Sub OnTextBoxLostFocus(sender As TextEdit, e As EventArgs)
        sender.BackColor = Color.White
    End Sub

    Private Sub OnTextBoxKeyUp(sender As TextEdit, e As KeyEventArgs)
        If sender.Text = String.Empty Then
            Exit Sub
        End If

        If e.KeyCode = Keys.Return Or e.KeyCode = Keys.Enter Or e.KeyCode = Keys.Tab Then
            OnControlChanged.Invoke(sender)
        End If

        If e.KeyCode = Keys.Return Then
            SendKeys.Send("{TAB}")
        End If
    End Sub

    Public Function AddCheckBox(pIndexname As String, pY As Integer, pDefaultValue As String, pCaption As String) As CheckEdit
        Try
            Dim oValue As Boolean = False
            Dim oCheckBox As New CheckEdit With {
                .Name = "chk" & pIndexname,
                .AutoSize = False,
                .Size = New Size(DEFAULT_WIDTH, DEFAULT_HEIGHT),
                .Location = New Point(DEFAULT_POSITION_X, pY),
                .Tag = New ControlMeta() With {
                    .IndexName = pIndexname,
                    .IndexType = TYPE_BOOLEAN,
                    .ControlType = "chk"
                }
            }

            If pCaption <> "" Then
                oCheckBox.Text = pCaption
                oCheckBox.Size = New Size(CInt(pCaption.Length * 15), 27)
            End If

            If Boolean.TryParse(pDefaultValue, oValue) = False Then
                If pDefaultValue = "1" Or pDefaultValue = "0" Then
                    oCheckBox.Checked = CBool(pDefaultValue)
                Else
                    oCheckBox.Checked = False
                End If
            Else
                oCheckBox.Checked = oValue
            End If

            AddHandler oCheckBox.CheckedChanged, Sub(sender As CheckEdit, e As EventArgs)
                                                     OnControlChanged.Invoke(sender)
                                                 End Sub

            Return oCheckBox
        Catch ex As Exception
            Logger.Warn("Unhandled Exception in AddCheckBox: " & ex.Message)
            Logger.Error(ex)
            Return Nothing
        End Try
    End Function

    Public Function AddLookupControl(pIndexname As String, pY As Integer, pMultiselect As Boolean, pDataType As String, pSQLCommand As String, pConnectionId As Integer, Optional pDefaultValue As String = "", Optional pAddNewValues As Boolean = False, Optional pPreventDuplicateValues As Boolean = False) As LookupControl3
        Dim oControl As New LookupControl3 With {
            .Location = New Point(DEFAULT_POSITION_X, pY),
            .Size = New Size(DEFAULT_WIDTH, DEFAULT_HEIGHT),
            .Name = "cmbMulti" & pIndexname,
            .Tag = New ControlMeta() With {
                .IndexName = pIndexname,
                .IndexType = pDataType,
                .ControlType = "cmbMulti"
            }
        }

        oControl.Properties.MultiSelect = pMultiselect
        oControl.Properties.AllowAddNewValues = pAddNewValues
        oControl.Properties.PreventDuplicates = pPreventDuplicateValues
        oControl.Properties.AppearanceFocused.BackColor = HightlightColor

        If Not String.IsNullOrEmpty(pDefaultValue) Then
            Dim oDefaultValues As New List(Of String)

            If pDefaultValue.Contains(",") Then
                oDefaultValues = pDefaultValue.
                    Split(",").ToList().
                    Select(Function(item) item.Trim()).
                    ToList()
            Else
                oDefaultValues = pDefaultValue.
                    Split(VECTORSEPARATOR).ToList().
                    Select(Function(item) item.Trim()).
                    ToList()
            End If
            oControl.Properties.SelectedValues = oDefaultValues
        End If

        AddHandler oControl.Properties.SelectedValuesChanged, Sub() OnControlChanged.Invoke(oControl)

        If OnLookupData Is Nothing Then
            Logger.Warn("LookupGrid Datasource could not be set, OnLookupData Function is not defined!")
        End If

        Try
            If pSQLCommand IsNot Nothing AndAlso pSQLCommand.Length > 0 Then
                Dim oDataSource = OnLookupData.Invoke(oControl, pSQLCommand, pConnectionId)
                oControl.Properties.DataSource = oDataSource

                If oDataSource IsNot Nothing AndAlso oDataSource.Columns.Count > 0 Then
                    oControl.Properties.DisplayMember = oDataSource.Columns.Item(0).ColumnName
                    oControl.Properties.ValueMember = oDataSource.Columns.Item(0).ColumnName
                Else
                    Logger.Info("Lookup {0} Datasource did not contain any columns!", oControl.Name)
                End If
            End If
        Catch ex As Exception
            Logger.Error(ex)
        End Try

        Return oControl
    End Function
End Class
