Imports System.Text.RegularExpressions Imports System.Windows.Forms Imports DigitalData.Modules.Database Imports DigitalData.Modules.Language.Utils Imports DigitalData.Modules.Logging Imports DigitalData.Modules.Windows Imports DigitalData.Modules.ZooFlow.Params Imports DigitalData.Modules.ZooFlow.State Imports DigitalData.Modules.Patterns Public Class ProfileFilter Private _ProfileMatch As ProfileMatch Private _ProfileTable As DataTable Private _ProcessTable As DataTable Private _WindowTable As DataTable Private _ControlTable As DataTable Private _Profiles As List(Of ProfileData) Private _TreeView As TreeView Private _LogConfig As LogConfig Private _Logger As Logger Public ReadOnly Property Profiles As List(Of ProfileData) Get Return _Profiles End Get End Property Public Sub New(LogConfig As LogConfig, ProfileDatatable As DataTable, ProcessTable As DataTable, WindowDatatable As DataTable, ControlDatatable As DataTable, TreeView As TreeView) Try _ProfileMatch = New ProfileMatch(LogConfig) _ProfileTable = ProfileDatatable _ProcessTable = ProcessTable _WindowTable = WindowDatatable _ControlTable = ControlDatatable _Profiles = TransformProfiles() _TreeView = TreeView _LogConfig = LogConfig _Logger = LogConfig.GetLogger() Catch ex As Exception _Logger.Error(ex) Throw ex End Try End Sub Public Function ToList() As List(Of ProfileData) Return _Profiles End Function Public Function FilterProfilesByClipboardRegex(Profiles As List(Of ProfileData), ClipboardContents As String) As List(Of ProfileData) Dim oFilteredProfiles As New List(Of ProfileData) Dim oRootNode As TreeNode = New TreeNode() With { .Text = $"Suche nach '{ClipboardContents}'", .Tag = "ROOT" } _TreeView.Nodes.Add(oRootNode) For Each oProfile In Profiles _Logger.Debug("Current Profile: {0}", oProfile.Name) Dim oNode = _ProfileMatch.NewProfileNode(oProfile) oRootNode.Nodes.Add(oNode) Try Dim oRegex As New Regex(oProfile.Regex) Dim oMatch = oRegex.Match(ClipboardContents) If oMatch.Success Then _Logger.Debug("FilterProfilesByClipboardRegex: Clipboard Regex Matched: {0}", ClipboardContents) oFilteredProfiles.Add(oProfile) oProfile.IsMatched = True Dim oSubnode = _ProfileMatch.NewClipboardRegexNode(oProfile, oMatch.Success) oNode.Nodes.Add(oSubnode) End If Catch ex As Exception _Logger.Warn("Regex '{0}' could not be processed for input '{1}'", oProfile.Regex, ClipboardContents) _Logger.Error(ex) End Try Next Return oFilteredProfiles End Function Public Function FilterProfilesByProcess(Profiles As List(Of ProfileData), CurrentProcessName As String) As List(Of ProfileData) Dim oFilteredProfiles As New List(Of ProfileData) Try For Each oProfile In Profiles Dim oGuid = oProfile.Guid If oProfile.IsMatched = False Then Continue For End If Dim oProcesses As New List(Of ProcessData) For Each oProcessDef As ProcessData In oProfile.Processes If oProcessDef.PROFILE_ID <> oGuid Then Continue For End If Dim oIsMatch = oProcessDef.ProcessName.ToLower = CurrentProcessName.ToLower Dim oParent = _ProfileMatch.FindNodeByTag(_TreeView.Nodes, oProfile.Name & "-REGEX") If oParent IsNot Nothing Then Dim oNode = _ProfileMatch.NewProcessNode(oProfile, oProcessDef, oIsMatch) oParent.Nodes.Add(oNode) End If _Logger.Debug($"FilterProfilesByProcess: Checking Profile: {oProfile.Name} ...") If oIsMatch Then _Logger.Debug($"Yes...Processname Matched: {oProcessDef.ProcessName}") 'TODO: Add Debug Data oFilteredProfiles.Add(oProfile) oProfile.MatchedProcessID = oProcessDef.Guid oProcessDef.IsMatched = True oProcesses.Add(oProcessDef) oProfile.IsMatched = True oProfile.MatchedProcessID = oProcessDef.Guid End If Next If oFilteredProfiles.Count > 0 Then oProfile.Processes = oProcesses End If Next Return oFilteredProfiles Catch ex As Exception _Logger.Warn("Unexpected error in FilterProfilesByProcess...") _Logger.Error(ex) End Try End Function Public Function FilterWindowsByWindowTitleRegex(Profiles As List(Of ProfileData), WindowTitle As String) As List(Of ProfileData) Dim oProfiles As New List(Of ProfileData) For Each oProfile As ProfileData In Profiles _Logger.Debug("Checking WindowDefinition for profile: {0}...", oProfile.Name) If oProfile.IsMatched = False Then Continue For Dim oWindows As New List(Of WindowData) For Each oWindowDef As WindowData In oProfile.Windows If oWindowDef.WindowProcessID <> oProfile.MatchedProcessID Then Continue For Try If oWindowDef.Regex = String.Empty Then oProfile.MatchedWindowID = oWindowDef.Guid oWindowDef.IsMatched = True oWindows.Add(oWindowDef) Exit For End If Dim oRegex As New Regex(oWindowDef.Regex) Dim oMatch = oRegex.Match(WindowTitle) If oMatch.Success Then _Logger.Debug("MATCH on WindowTitle: {0}", WindowTitle) oProfile.MatchedWindowID = oWindowDef.Guid oWindowDef.IsMatched = True oWindows.Add(oWindowDef) End If Dim oParent = _ProfileMatch.FindNodeByTag(_TreeView.Nodes, oWindowDef.WindowProcessID & "-PROCESS") If oParent IsNot Nothing Then Dim oNode = _ProfileMatch.NewWindowNode(oProfile, oWindowDef, oMatch.Success) oParent.Nodes.Add(oNode) End If Catch ex As Exception _Logger.Warn("Regex '{0}' could not be processed for input '{1}'", oWindowDef.Regex, WindowTitle) _Logger.Error(ex) End Try Next If oWindows.Count > 0 Then oProfile.Windows = oWindows oProfile.IsMatched = True oProfiles.Add(oProfile) End If Next Return oProfiles End Function Public Function FilterProfilesByFocusedControlLocation(Profiles As List(Of ProfileData), ClipboardContents As String, WindowHandle As IntPtr) As List(Of ProfileData) Dim oFilteredProfiles As New List(Of ProfileData) Dim oWindow As New Window(_LogConfig) For Each oProfile In Profiles If oProfile.IsMatched = False Then Continue For If oProfile.Controls.Count = 0 Then oFilteredProfiles.Add(oProfile) Continue For End If Dim oControls As New List(Of ControlData) For Each oControl In oProfile.Controls Dim oControlBounds = oWindow.GetFocusedControlLocation(WindowHandle) Dim oFound As Boolean = False For Each oItem As KeyValuePair(Of String, Window.RectangleInfo) In oControlBounds Select Case oItem.Key Case "TOPLEFT" If oControl.TopLeft.Top = oItem.Value.Top And oControl.TopLeft.Left = oItem.Value.Left Then oFound = True End If Case "TOPRIGHT" If oControl.TopRight.Top = oItem.Value.Top And oControl.TopLeft.Right = oItem.Value.Right Then oFound = True End If Case "BOTTOMLEFT" If oControl.BottomLeft.Bottom = oItem.Value.Bottom And oControl.TopLeft.Left = oItem.Value.Left Then oFound = True End If Case "BOTTOMRIGHT" If oControl.BottomRight.Bottom = oItem.Value.Bottom And oControl.TopLeft.Right = oItem.Value.Right Then oFound = True End If End Select Next If oFound Then oControls.Add(oControl) End If Dim oParent = _ProfileMatch.FindNodeByTag(_TreeView.Nodes, oControl.WindowId & "-WINDOW") If oParent IsNot Nothing Then Dim oNode = _ProfileMatch.NewControlNode(oProfile, oControl, oFound) oParent.Nodes.Add(oNode) End If Next If oControls.Count > 0 Then oProfile.Controls = oControls oFilteredProfiles.Add(oProfile) End If Next Return oFilteredProfiles End Function Public Function FilterProfilesBySearchResults(Profiles As List(Of ProfileData), Database As MSSQLServer, User As UserState, ClipboardContents As String) As List(Of ProfileData) Dim oProfiles As New List(Of ProfileData) For Each oProfile In Profiles Dim oResultDocs As Integer = 0 Dim oResultData As Integer = 0 Dim oPatterns As New ClassPatterns(_LogConfig) Dim oDataSearches As DataTable Dim oDocSearches As DataTable Try oDataSearches = Database.GetDatatable($"SELECT COUNT_COMMAND FROM TBCW_PROF_DATA_SEARCH WHERE ACTIVE = 1 AND PROFILE_ID = {oProfile.Guid}") Catch ex As Exception _Logger.Error(ex) Continue For End Try Try oDocSearches = Database.GetDatatable($"SELECT COUNT_COMMAND FROM TBCW_PROF_DOC_SEARCH WHERE ACTIVE = 1 AND PROFILE_ID = {oProfile.Guid}") Catch ex As Exception _Logger.Error(ex) Continue For End Try For Each oRow As DataRow In oDataSearches.Rows Dim oCountCommand = String.Empty Try oCountCommand = NotNull(oRow.Item("COUNT_COMMAND"), String.Empty) If oCountCommand = String.Empty Then Continue For End If oCountCommand = oPatterns.ReplaceInternalValues(oCountCommand) oCountCommand = oPatterns.ReplaceUserValues(oCountCommand, User) oCountCommand = oPatterns.ReplaceClipboardContents(oCountCommand, ClipboardContents) oResultData += NotNull(Of Integer)(Database.GetScalarValue(oCountCommand), 0) Catch ex As Exception _Logger.Warn("Invalid SQL Query for Counting Data in Profile {0}: {1}", oProfile.Guid, oCountCommand) End Try Next For Each oRow As DataRow In oDocSearches.Rows Dim oCountCommand = String.Empty Try oCountCommand = NotNull(oRow.Item("COUNT_COMMAND"), String.Empty) If oCountCommand = String.Empty Then Continue For End If oCountCommand = oPatterns.ReplaceInternalValues(oCountCommand) oCountCommand = oPatterns.ReplaceUserValues(oCountCommand, User) oCountCommand = oPatterns.ReplaceClipboardContents(oCountCommand, ClipboardContents) oResultDocs += NotNull(Of Integer)(Database.GetScalarValue(oCountCommand), 0) Catch ex As Exception _Logger.Warn("Invalid SQL Query for Counting Data in Profile {0}: {1}", oProfile.Guid, oCountCommand) End Try Next If oResultData > 0 Or oResultDocs > 0 Then oProfile.CountData = oResultData oProfile.CountDocs = oResultDocs oProfiles.Add(oProfile) End If Next Return oProfiles End Function Public Function FilterWindowsByWindowClipboardRegex(Profiles As List(Of ProfileData), ClipboardContents As String) As List(Of ProfileData) Dim oProfiles As New List(Of ProfileData) For Each oProfile As ProfileData In Profiles _Logger.Debug("Current Profile: {0}", oProfile.Name) Dim oWindows As New List(Of WindowData) For Each w As WindowData In oProfile.Windows Try If w.Regex = String.Empty Then oWindows.Add(w) End If Dim oRegex As New Regex(w.Regex) Dim oMatch = oRegex.Match(ClipboardContents) If oMatch.Success Then _Logger.Debug("Window Clipboard Regex Matched: {0}", ClipboardContents) oWindows.Add(w) End If Dim oResult As TreeNode = _ProfileMatch.FindNodeByTag(_TreeView.Nodes, oProfile.Name & "-REGEX") If Not IsNothing(oResult) Then Dim oNode As New TreeNode($"MATCH on WINDOW Clipboard Regex [{w.Regex}]: {oMatch.Success}") oNode.ImageIndex = 2 oNode.Tag = oProfile.Name & "-WINDOW_REGEX" oResult.Nodes.Add(oNode) End If Catch ex As Exception _Logger.Warn("Regex '{0}' could not be processed for input '{1}'", w.Regex, ClipboardContents) _Logger.Error(ex) End Try Next If oWindows.Count > 0 Then oProfile.Windows = oWindows oProfiles.Add(oProfile) End If Next Return oProfiles End Function Public Function ClearNotMatchedProfiles(Profiles As List(Of ProfileData)) As List(Of ProfileData) Dim oFilteredProfiles As New List(Of ProfileData) For Each oProfile In Profiles If oProfile.IsMatched Then oFilteredProfiles.Add(oProfile) End If Next Return oFilteredProfiles End Function Public Function ClearDuplicateProfiles(Profiles As List(Of ProfileData)) As List(Of ProfileData) Return Profiles. GroupBy(Function(Profile) Profile.Guid). Select(Function(GroupedProfiles) GroupedProfiles.First). ToList() End Function Private Function TransformProfiles() As List(Of ProfileData) Dim oList As New List(Of ProfileData) For Each oRow As DataRow In _ProfileTable.Rows Dim oProfileId = oRow.Item("GUID") Dim oProcessList As List(Of ProcessData) = TransformProcesses(oProfileId, _ProcessTable) Dim oWindowList As List(Of WindowData) = TransformWindows(oProfileId, _WindowTable) Dim oControlList As List(Of ControlData) = TransformControls(oProfileId, _ControlTable) oList.Add(New ProfileData() With { .Guid = oRow.Item("GUID"), .Regex = oRow.Item("REGEX_EXPRESSION"), .Name = NotNull(oRow.Item("NAME"), String.Empty), .Comment = NotNull(oRow.Item("COMMENT"), String.Empty), .ProfileType = NotNull(oRow.Item("PROFILE_TYPE"), String.Empty), .Processes = oProcessList, .Windows = oWindowList, .Controls = oControlList }) Next oList = oList. Distinct(). ToList() Return oList End Function Private Function TransformControls(ProfileId As Integer, ControlDatatable As DataTable) As List(Of ControlData) Dim oControlList As New List(Of ControlData) For Each oRow As DataRow In ControlDatatable.Rows If oRow.Item("PROFILE_ID") = ProfileId Then oControlList.Add(New ControlData() With { .Guid = oRow.Item("GUID"), .Description = NotNull(oRow.Item("DESCRIPTION"), String.Empty), .WindowId = oRow.Item("WINDOW_ID"), .TopLeft = New ControlBounds() With { .Left = oRow.Item("TOPLEFT_LEFT"), .Right = oRow.Item("TOPLEFT_RIGHT"), .Top = oRow.Item("TOPLEFT_TOP"), .Bottom = oRow.Item("TOPLEFT_BOTTOM") }, .TopRight = New ControlBounds() With { .Left = oRow.Item("TOPRIGHT_LEFT"), .Right = oRow.Item("TOPRIGHT_RIGHT"), .Top = oRow.Item("TOPRIGHT_TOP"), .Bottom = oRow.Item("TOPRIGHT_BOTTOM") }, .BottomLeft = New ControlBounds() With { .Left = oRow.Item("BOTTOMLEFT_LEFT"), .Right = oRow.Item("BOTTOMLEFT_RIGHT"), .Top = oRow.Item("BOTTOMLEFT_TOP"), .Bottom = oRow.Item("BOTTOMLEFT_BOTTOM") }, .BottomRight = New ControlBounds() With { .Left = oRow.Item("BOTTOMRIGHT_LEFT"), .Right = oRow.Item("BOTTOMRIGHT_RIGHT"), .Top = oRow.Item("BOTTOMRIGHT_TOP"), .Bottom = oRow.Item("BOTTOMRIGHT_BOTTOM") } }) End If Next Return oControlList End Function Private Function TransformProcesses(ProfileId As Integer, ProcessDatatable As DataTable) As List(Of ProcessData) Dim oProcessList As New List(Of ProcessData) For Each oRow As DataRow In ProcessDatatable.Rows If oRow.Item("PROFILE_ID") = ProfileId Then oProcessList.Add(New ProcessData() With { .Guid = oRow.Item("GUID"), .PROFILE_ID = oRow.Item("PROFILE_ID"), .ProcessName = NotNull(oRow.Item("PROC_NAME"), String.Empty) }) End If Next oProcessList = oProcessList. Distinct(). ToList() Return oProcessList End Function Private Function TransformWindows(ProfileId As Integer, WindowDatatable As DataTable) As List(Of WindowData) Dim oWindowList As New List(Of WindowData) For Each oRow As DataRow In WindowDatatable.Rows If oRow.Item("PROFILE_ID") = ProfileId Then oWindowList.Add(New WindowData() With { .Guid = oRow.Item("GUID"), .WindowProcessID = oRow.Item("PROCESS_ID"), .Title = NotNull(oRow.Item("DESCRIPTION"), String.Empty), .Regex = NotNull(oRow.Item("REGEX"), String.Empty), .Sequence = NotNull(oRow.Item("SEQUENCE"), 0) }) End If Next Return oWindowList End Function End Class