using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Ookii.Dialogs.Wpf; using S7Explorer.Helpers; using S7Explorer.Models; using S7Explorer.Services; using S7Explorer.Services; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Threading.Tasks; using System.Windows; namespace S7Explorer.ViewModels { public partial class MainViewModel : ViewModelBase { private readonly ProjectService _projectService; private readonly ExportService _exportService; private readonly SearchHelper _searchHelper; [ObservableProperty] private ProjectStructure? _projectStructure; [ObservableProperty] private ProjectItem? _selectedItem; [ObservableProperty] private object? _selectedItemDetails; [ObservableProperty] private string _projectPath = string.Empty; [ObservableProperty] private bool _isProjectLoaded; [ObservableProperty] private string _searchText = string.Empty; [ObservableProperty] private bool _isCaseSensitive; [ObservableProperty] private bool _useRegex; [ObservableProperty] private ObservableCollection _logEntries = new(); [ObservableProperty] private ExportSettings _exportSettings = new(); [ObservableProperty] private bool _isLoading; public MainViewModel() { _projectService = new ProjectService(); _exportService = new ExportService(); _searchHelper = new SearchHelper(); // Initialize log entries collection LogEntries = LogService.Instance.Logs; // Initialize export settings ExportSettings.ExportPath = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "S7Documentation.txt"); } partial void OnSelectedItemChanged(ProjectItem? value) { SelectedItemDetails = value?.GetDetailsObject(); } [RelayCommand] private async Task LoadProject() { try { var dialog = new VistaOpenFileDialog { Title = "Open Siemens S7 Project", Filter = "S7 Projects (*.s7p)|*.s7p|All files (*.*)|*.*", CheckFileExists = true }; if (dialog.ShowDialog() == true) { ProjectPath = dialog.FileName; await LoadProjectFromPath(ProjectPath); } } catch (Exception ex) { _logService.LogError(ex); MessageBox.Show($"Error loading project: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error); } } [RelayCommand] private async Task ReloadProject() { if (string.IsNullOrEmpty(ProjectPath) || !File.Exists(ProjectPath)) { _logService.LogWarning("No project loaded to reload"); return; } await LoadProjectFromPath(ProjectPath); } private async Task LoadProjectFromPath(string path) { try { IsLoading = true; // Load the project _logService.LogInfo($"Loading project from {path}"); ProjectStructure = await _projectService.LoadProjectAsync(path); if (ProjectStructure != null) { IsProjectLoaded = true; _logService.LogInfo("Project loaded successfully"); } else { IsProjectLoaded = false; _logService.LogError("Failed to load project"); MessageBox.Show("Failed to load project", "Error", MessageBoxButton.OK, MessageBoxImage.Error); } } catch (Exception ex) { _logService.LogError(ex); MessageBox.Show($"Error loading project: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error); } finally { IsLoading = false; } } [RelayCommand] private void Search() { if (!IsProjectLoaded || ProjectStructure == null) { _logService.LogWarning("No project loaded to search"); return; } if (string.IsNullOrWhiteSpace(SearchText)) { _logService.LogWarning("No search text specified"); return; } try { var results = _searchHelper.Search(ProjectStructure, SearchText, IsCaseSensitive, UseRegex); if (results.Count == 0) { _logService.LogInfo($"No results found for '{SearchText}'"); MessageBox.Show($"No results found for '{SearchText}'", "Search Results", MessageBoxButton.OK, MessageBoxImage.Information); return; } // Show search results dialog ShowSearchResults(results); } catch (Exception ex) { _logService.LogError(ex); MessageBox.Show($"Error during search: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error); } } private void ShowSearchResults(List results) { // In a full implementation, this would show a dialog or window with search results // For demonstration, we'll just select the first result and expand to it if (results.Count > 0) { var firstResult = results[0]; TreeViewHelper.ExpandToItem(firstResult.Item); SelectedItem = firstResult.Item; _logService.LogInfo($"Found {results.Count} results, highlighted first result"); MessageBox.Show($"Found {results.Count} results", "Search Results", MessageBoxButton.OK, MessageBoxImage.Information); } } [RelayCommand] private async Task ExportDocumentation() { if (!IsProjectLoaded || ProjectStructure == null) { _logService.LogWarning("No project loaded to export"); return; } try { // Show export settings dialog bool proceed = ShowExportSettings(); if (!proceed) return; IsLoading = true; // Export the documentation bool success = await _exportService.ExportProjectAsync(ProjectStructure, ExportSettings); if (success) { _logService.LogInfo($"Documentation exported to {ExportSettings.ExportPath}"); MessageBox.Show($"Documentation exported to {ExportSettings.ExportPath}", "Export Complete", MessageBoxButton.OK, MessageBoxImage.Information); } else { _logService.LogError("Failed to export documentation"); MessageBox.Show("Failed to export documentation", "Export Failed", MessageBoxButton.OK, MessageBoxImage.Error); } } catch (Exception ex) { _logService.LogError(ex); MessageBox.Show($"Error exporting documentation: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error); } finally { IsLoading = false; } } private bool ShowExportSettings() { // Show file save dialog for export path var dialog = new VistaSaveFileDialog { Title = "Export Documentation", Filter = GetExportFilter(), FileName = Path.GetFileName(ExportSettings.ExportPath), InitialDirectory = Path.GetDirectoryName(ExportSettings.ExportPath) }; if (dialog.ShowDialog() == true) { ExportSettings.ExportPath = dialog.FileName; // Determine export format from file extension string extension = Path.GetExtension(dialog.FileName).ToLower(); ExportSettings.ExportFormat = extension switch { ".md" => ExportFormat.MarkDown, ".html" => ExportFormat.HTML, ".json" => ExportFormat.JSON, _ => ExportFormat.PlainText }; return true; } return false; } private string GetExportFilter() { return "Text Files (*.txt)|*.txt|" + "Markdown Files (*.md)|*.md|" + "HTML Files (*.html)|*.html|" + "JSON Files (*.json)|*.json|" + "All Files (*.*)|*.*"; } [RelayCommand] private void ExpandAll() { if (ProjectStructure != null) { TreeViewHelper.ExpandAll(ProjectStructure); _logService.LogInfo("Expanded all tree nodes"); } } [RelayCommand] private void CollapseAll() { if (ProjectStructure != null) { TreeViewHelper.CollapseAll(ProjectStructure); _logService.LogInfo("Collapsed all tree nodes"); } } [RelayCommand] private void ClearLog() { LogEntries.Clear(); _logService.LogInfo("Log cleared"); } } }