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 ReadOnly _Logger As Logger
    Private ReadOnly _LogConfig As LogConfig

    Private ReadOnly _Regex As Regex = New Regex("{#(\w+)#([\w\s_-]+)}+")
    Private ReadOnly _AllPatterns As New List(Of String) From {PATTERN_WMI, PATTERN_CTRL, PATTERN_USER, PATTERN_INT}
    Private ReadOnly _ComplexPatterns As New List(Of String) From {PATTERN_WMI, PATTERN_CTRL}
    Private ReadOnly _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(pType As String, pValue As String) As String
        Return New Pattern(pType, pValue).ToString
    End Function

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

    Public Function ReplaceAllValues(pInput As String, pUser As State.UserState, pClipboardContents As String) As String
        Try
            Dim result = pInput

            result = ReplaceClipboardContents(result, pClipboardContents)
            result = ReplaceInternalValues(result)
            result = ReplaceUserValues(result, pUser)

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

    Public Function ReplaceClipboardContents(pInput As String, pClipboardContents As String) As String
        Dim oResult = pInput

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

        Return oResult
    End Function

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

            ' 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 pInput
        End Try
    End Function

    Public Function ReplaceUserValues(pInput As String, pUser As State.UserState) As String
        Try
            Dim oResult = pInput

            While ContainsPatternAndValue(oResult, PATTERN_USER, USER_VALUE_PRENAME)
                oResult = ReplacePattern(pInput, PATTERN_USER, pUser.GivenName)
            End While

            While ContainsPatternAndValue(oResult, PATTERN_USER, USER_VALUE_USER_ID)
                oResult = ReplacePattern(pInput, PATTERN_USER, pUser.UserId.ToString)
            End While

            While ContainsPatternAndValue(oResult, PATTERN_USER, USER_VALUE_SURNAME)
                oResult = ReplacePattern(pInput, PATTERN_USER, pUser.Surname)
            End While

            While ContainsPatternAndValue(oResult, PATTERN_USER, USER_VALUE_SHORTNAME)
                oResult = ReplacePattern(pInput, PATTERN_USER, pUser.ShortName)
            End While

            While ContainsPatternAndValue(oResult, PATTERN_USER, USER_VALUE_EMAIL)
                oResult = ReplacePattern(pInput, PATTERN_USER, pUser.Email)
            End While

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

    Public Function ReplaceControlValues(pInput As String, pPanel As Panel) As String
        Try
            Dim oResult = pInput
            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 = pPanel.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 pInput
        End Try
    End Function

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

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

            If t = pType Then
                Return True
            End If
        Next

        Return False
    End Function

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

        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 = pType Then
                Return New Pattern(oType, oValue)
            End If
        Next

        Return Nothing
    End Function
    Public Function GetAllPatterns(pInput As String) As List(Of Pattern)
        Dim elements As MatchCollection = _Regex.Matches(pInput)
        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(pInput As String, pType As String, pReplacement As String) As String
        Dim oElements As MatchCollection = _Regex.Matches(pInput)

        If IsNothing(pReplacement) Or pReplacement = String.Empty Then
            Return pInput
        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 = pType Then
                Return Regex.Replace(pInput, element.Groups(0).Value, pReplacement)
            End If
        Next

        ' no replacement made
        Return pInput
    End Function
    Private Function ContainsPatternAndValue(pInput As String, pType As String, pValue As String) As Boolean
        Dim oElements As MatchCollection = _Regex.Matches(pInput)

        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 = pType And oValue = pValue Then
                Return True
            End If
        Next

        Return False
    End Function

    Public Function HasAnyPatterns(pInput As String) As Boolean
        Return _AllPatterns.Any(Function(pPattern) HasPattern(pInput, pPattern))
    End Function

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

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

    Public Function HasPattern(pInput As String, pType As String) As Boolean
        Dim oMatches = _Regex.Matches(pInput)

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

        Return False
    End Function
End Class