using S7Explorer.Models; using S7Explorer.Services; using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; namespace S7Explorer.Helpers { public class SearchHelper { private readonly LogService _logService; public SearchHelper() { _logService = LogService.Instance; } public List Search(ProjectStructure project, string searchText, bool caseSensitive, bool useRegex) { _logService.LogInfo($"Searching for '{searchText}' (Case sensitive: {caseSensitive}, Regex: {useRegex})"); List results = new List(); try { if (string.IsNullOrWhiteSpace(searchText)) return results; // Prepare regex if needed Regex? regex = null; if (useRegex) { try { RegexOptions options = caseSensitive ? RegexOptions.None : RegexOptions.IgnoreCase; regex = new Regex(searchText, options); } catch (Exception ex) { _logService.LogError($"Invalid regex pattern: {ex.Message}"); return results; } } // Search blocks SearchProjectItem(project.BlocksFolder, results, searchText, caseSensitive, regex); // Search symbols SearchProjectItem(project.SymbolsFolder, results, searchText, caseSensitive, regex); // Search hardware SearchProjectItem(project.HardwareFolder, results, searchText, caseSensitive, regex); _logService.LogInfo($"Found {results.Count} results"); return results; } catch (Exception ex) { _logService.LogError($"Error during search: {ex.Message}"); return results; } } private void SearchProjectItem(ProjectItem item, List results, string searchText, bool caseSensitive, Regex? regex) { // Check name bool nameMatch = MatchesSearch(item.Name, searchText, caseSensitive, regex); // For blocks, check content and comments bool contentMatch = false; if (item is BlockItem blockItem) { contentMatch = MatchesSearch(blockItem.BlockContent, searchText, caseSensitive, regex) || MatchesSearch(blockItem.BlockComment, searchText, caseSensitive, regex); } // For symbols, check address, type, and comment else if (item is SymbolItem symbolItem) { contentMatch = MatchesSearch(symbolItem.SymbolAddress, searchText, caseSensitive, regex) || MatchesSearch(symbolItem.SymbolDataType, searchText, caseSensitive, regex) || MatchesSearch(symbolItem.SymbolComment, searchText, caseSensitive, regex); } // For hardware, check module info else if (item is HardwareItem hardwareItem) { contentMatch = MatchesSearch(hardwareItem.ModuleType, searchText, caseSensitive, regex) || MatchesSearch(hardwareItem.OrderNumber, searchText, caseSensitive, regex) || MatchesSearch(hardwareItem.Position, searchText, caseSensitive, regex) || MatchesSearch(hardwareItem.Address, searchText, caseSensitive, regex); } if (nameMatch || contentMatch) { results.Add(new SearchResult { Item = item, MatchType = nameMatch ? (contentMatch ? MatchType.Both : MatchType.Name) : MatchType.Content }); } // Search children recursively foreach (var child in item.Children) { SearchProjectItem(child, results, searchText, caseSensitive, regex); } } private bool MatchesSearch(string text, string searchText, bool caseSensitive, Regex? regex) { if (string.IsNullOrEmpty(text)) return false; if (regex != null) return regex.IsMatch(text); return caseSensitive ? text.Contains(searchText) : text.ToLower().Contains(searchText.ToLower()); } } public class SearchResult { public ProjectItem Item { get; set; } = null!; public MatchType MatchType { get; set; } public override string ToString() { return $"{Item.Name} - {MatchType}"; } } public enum MatchType { Name, Content, Both } }