Imports System.Text.RegularExpressions
Imports System.Windows.Forms
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.ZooFlow

''' <summary>
''' Defines common Functions for Checking for and replacing placeholders.
''' This Class also includes a child class `Pattern` for passing around Patterns.
''' 
''' The format of all placeholders is:
''' {#TYPE#VALUE}
''' 
''' Some Examples:
''' {#INT#USERNAME}
''' {#CTRL#CMB_2}
''' {#WMI#String 39}
''' </summary>
Public Class ClassPatterns
    ' Complex patterns that rely on a datasource like a Database or Windream
    Public Const PATTERN_WMI = "WMI"
    Public Const PATTERN_CTRL = "CTRL"
    ' Simple patterns that only rely on .NET functions
    Public Const PATTERN_INT = "INT"
    ' Simple patterns that rely on Data from the TBDD_USER table
    Public Const PATTERN_USER = "USER"

    Public Const USER_VALUE_PRENAME = "PRENAME"
    Public Const USER_VALUE_SURNAME = "SURNAME"
    Public Const USER_VALUE_EMAIL = "EMAIL"
    Public Const USER_VALUE_SHORTNAME = "SHORTNAME"
    Public Const USER_VALUE_USER_ID = "USER_ID"
    Public Const USER_VALUE_PROFILE_ID = "PROFILE_ID"

    Public Const INT_VALUE_USERNAME = "USERNAME"
    Public Const INT_VALUE_MACHINE = "MACHINE"
    Public Const INT_VALUE_DOMAIN = "DOMAIN"
    Public Const INT_VALUE_DATE = "DATE"

    Public Const CLIPBOARD_VALUE_DE = "@Zwischenablage"
    Public Const CLIPBOARD_VALUE_EN = "@Clipboard"

    Public Const MAX_TRY_COUNT = 100

    Public ReadOnly Property PatternRegex As Regex
        Get
            Return _Regex
        End Get
    End Property

    Private _Logger As Logger
    Private _LogConfig As LogConfig

    Private _Regex As Regex = New Regex("{#(\w+)#([\w\s_-]+)}+")
    Private _AllPatterns As New List(Of String) From {PATTERN_WMI, PATTERN_CTRL, PATTERN_USER, PATTERN_INT}
    Private _ComplexPatterns As New List(Of String) From {PATTERN_WMI, PATTERN_CTRL}
    Private _SimplePatterns As New List(Of String) From {PATTERN_USER, PATTERN_INT}

    ''' <summary>
    ''' Wraps a pattern-type and -value in the common format: {#type#value}
    ''' </summary>
    Public Function WrapPatternValue(type As String, value As String) As String
        Return New Pattern(type, value).ToString
    End Function

    Public Sub New(LogConfig As LogConfig)
        _LogConfig = LogConfig
        _Logger = LogConfig.GetLogger
    End Sub

    Public Function ReplaceAllValues(input As String, User As State.UserState, ClipboardContents As String) As String
        Try
            Dim result = input

            result = ReplaceClipboardContents(result, ClipboardContents)
            result = ReplaceInternalValues(result)
            result = ReplaceUserValues(result, User)

            Return result
        Catch ex As Exception
            _Logger.Error(ex)
            _Logger.Warn("Error in ReplaceAllValues:" & ex.Message)
            Return input
        End Try
    End Function

    Public Function ReplaceClipboardContents(Input As String, ClipboardContents As String) As String
        Dim oResult = Input

        oResult = oResult.Replace(CLIPBOARD_VALUE_DE.ToLower, ClipboardContents)
        oResult = oResult.Replace(CLIPBOARD_VALUE_DE.ToUpper, ClipboardContents)
        oResult = oResult.Replace(CLIPBOARD_VALUE_EN.ToLower, ClipboardContents)
        oResult = oResult.Replace(CLIPBOARD_VALUE_EN.ToUpper, ClipboardContents)
        oResult = oResult.Replace(CLIPBOARD_VALUE_DE, ClipboardContents)
        oResult = oResult.Replace(CLIPBOARD_VALUE_EN, ClipboardContents)

        Return oResult
    End Function

    Public Function ReplaceInternalValues(Input As String) As String
        Try
            Dim oResult = Input

            ' Replace Username(s)
            While ContainsPatternAndValue(oResult, PATTERN_INT, INT_VALUE_USERNAME)
                oResult = ReplacePattern(oResult, PATTERN_INT, System.Environment.UserName)
            End While

            ' Replace Machinename(s)
            While ContainsPatternAndValue(oResult, PATTERN_INT, INT_VALUE_MACHINE)
                oResult = ReplacePattern(oResult, PATTERN_INT, System.Environment.MachineName)
            End While

            ' Replace Domainname(s)
            While ContainsPatternAndValue(oResult, PATTERN_INT, INT_VALUE_DOMAIN)
                oResult = ReplacePattern(oResult, PATTERN_INT, System.Environment.UserDomainName)
            End While

            ' Replace CurrentDate(s)
            While ContainsPatternAndValue(oResult, PATTERN_INT, INT_VALUE_DATE)
                oResult = ReplacePattern(oResult, PATTERN_INT, Now.ToShortDateString)
            End While

            Return oResult
        Catch ex As Exception
            _Logger.Error(ex)
            _Logger.Warn("Error in ReplaceInternalValues:" & ex.Message)
            Return Input
        End Try
    End Function

    Public Function ReplaceUserValues(Input As String, User As State.UserState) As String
        Try
            Dim oResult = Input

            While ContainsPatternAndValue(oResult, PATTERN_USER, USER_VALUE_PRENAME)
                oResult = ReplacePattern(Input, PATTERN_USER, User.GivenName)
            End While

            While ContainsPatternAndValue(oResult, PATTERN_USER, USER_VALUE_USER_ID)
                oResult = ReplacePattern(Input, PATTERN_USER, User.UserId.ToString)
            End While

            While ContainsPatternAndValue(oResult, PATTERN_USER, USER_VALUE_SURNAME)
                oResult = ReplacePattern(Input, PATTERN_USER, User.Surname)
            End While

            While ContainsPatternAndValue(oResult, PATTERN_USER, USER_VALUE_SHORTNAME)
                oResult = ReplacePattern(Input, PATTERN_USER, User.ShortName)
            End While

            While ContainsPatternAndValue(oResult, PATTERN_USER, USER_VALUE_EMAIL)
                oResult = ReplacePattern(Input, PATTERN_USER, User.Email)
            End While

            Return oResult
        Catch ex As Exception
            _Logger.Error(ex)
            _Logger.Warn("Error in ReplaceUserValues:" & ex.Message)
            Return Input
        End Try
    End Function

    Public Function ReplaceControlValues(Input As String, Panel As Panel) As String
        Try
            Dim oResult = Input
            Dim oTryCounter = 0

            While ContainsPattern(oResult, PATTERN_CTRL)
                If oTryCounter > MAX_TRY_COUNT Then
                    Throw New Exception("Max tries in ReplaceControlValues exceeded.")
                End If

                Dim controlName As String = GetNextPattern(oResult, PATTERN_CTRL).Value
                Dim control As Control = Panel.Controls.Find(controlName, False).FirstOrDefault()

                If control IsNot Nothing Then
                    Dim value As String = control.Text
                    oResult = ReplacePattern(oResult, PATTERN_CTRL, value)
                End If

                oTryCounter += 1
            End While

            Return oResult
        Catch ex As Exception
            _Logger.Error(ex)
            _Logger.Warn("Error in ReplaceControlValues:" & ex.Message)
            Return Input
        End Try
    End Function

    Private Function ContainsPattern(input As String, type As String) As Boolean
        Dim elements As MatchCollection = _Regex.Matches(input)

        For Each element As Match In elements
            Dim t As String = element.Groups(1).Value

            If t = type Then
                Return True
            End If
        Next

        Return False
    End Function

    Public Function GetNextPattern(Input As String, Type As String) As Pattern
        Dim oElements As MatchCollection = _Regex.Matches(Input)

        For Each oElement As Match In oElements
            ' Pattern in input
            Dim oType As String = oElement.Groups(1).Value
            Dim oValue As String = oElement.Groups(2).Value

            If oType = Type Then
                Return New Pattern(oType, oValue)
            End If
        Next

        Return Nothing
    End Function
    Public Function GetAllPatterns(Input As String) As List(Of Pattern)
        Dim elements As MatchCollection = _Regex.Matches(Input)
        Dim results As New List(Of Pattern)

        For Each element As Match In elements
            ' Pattern in input
            Dim t As String = element.Groups(1).Value
            Dim v As String = element.Groups(2).Value

            results.Add(New Pattern(t, v))
        Next

        Return results
    End Function
    Public Function ReplacePattern(Input As String, Type As String, Replacement As String) As String
        Dim oElements As MatchCollection = _Regex.Matches(Input)

        If IsNothing(Replacement) Or Replacement = String.Empty Then
            Return Input
        End If

        For Each element As Match In oElements
            ' if group 1 contains the 'pattern' the replace whole group with 'replacement'
            ' and return it
            If element.Groups(1).Value = Type Then
                Return Regex.Replace(Input, element.Groups(0).Value, Replacement)
            End If
        Next

        ' no replacement made
        Return Input
    End Function
    Private Function ContainsPatternAndValue(Input As String, Type As String, Value As String) As Boolean
        Dim oElements As MatchCollection = _Regex.Matches(Input)

        For Each oElement As Match In oElements
            ' Pattern in input
            Dim oType As String = oElement.Groups(1).Value
            Dim oValue As String = oElement.Groups(2).Value

            If oType = Type And oValue = Value Then
                Return True
            End If
        Next

        Return False
    End Function

    Public Function HasAnyPatterns(Input As String) As Boolean
        Return _AllPatterns.Any(Function(p)
                                    Return HasPattern(Input, p)
                                End Function)
    End Function

    Public Function HasOnlySimplePatterns(Input As String) As Boolean
        Return Not HasComplexPatterns(Input)
    End Function

    Public Function HasComplexPatterns(Input As String) As Boolean
        Return _ComplexPatterns.Any(Function(oPattern)
                                        Return HasPattern(Input, oPattern)
                                    End Function)
    End Function

    Public Function HasPattern(Input As String, Type As String) As Boolean
        Dim oMatches = _Regex.Matches(Input)

        For Each oMatch As Match In oMatches
            For Each oGroup As Group In oMatch.Groups
                If oGroup.Value = Type Then
                    Return True
                End If
            Next
        Next

        Return False
    End Function

    Public Class Pattern
        Public ReadOnly Property Type As String
        Public ReadOnly Property Value As String

        Public Sub New(Type As String, Value As String)
            Me.Type = Type
            Me.Value = Value
        End Sub

        Public Overrides Function ToString() As String
            Return $"{{#{Type}#{Value}}}"
        End Function
    End Class
End Class