using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.IO; using System.Linq; using System.Threading.Tasks; using System.Windows; using System.Windows.Input; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Ookii.Dialogs.Wpf; using S7Explorer.Models; using S7Explorer.Parsers; namespace S7Explorer.ViewModels { public class MainViewModel : ObservableObject { private string _searchText; private object _selectedObject; private object _selectedTreeItem; private S7Project _currentProject; private ObservableCollection _projectStructure; private string _projectInfo; private bool _isLoading; public string SearchText { get => _searchText; set => SetProperty(ref _searchText, value); } public object SelectedObject { get => _selectedObject; set => SetProperty(ref _selectedObject, value); } public object SelectedTreeItem { get => _selectedTreeItem; set { if (SetProperty(ref _selectedTreeItem, value)) { // Actualizar el objeto seleccionado para PropertyGrid SelectedObject = _selectedTreeItem; // Acciones específicas según el tipo de objeto seleccionado if (_selectedTreeItem is S7Function fc) { // Si el objeto seleccionado es una función, actualizar su interfaz UpdateFunctionInterface(fc); } } } } /// /// Actualiza la información de interfaz de una función seleccionada /// private void UpdateFunctionInterface(S7Function fc) { try { // Aquí podríamos cargar información adicional específica de la función // Por ejemplo, cargar el código de la función, detalles de parámetros, etc. // Actualizar estadísticas o análisis de la función // Por ejemplo, mostrar uso de la función en otros bloques // Este método se ejecutará cuando el usuario seleccione una FC en el árbol } catch (Exception) { // Ignorar errores para no interrumpir la experiencia del usuario } } public ObservableCollection ProjectStructure { get => _projectStructure; set => SetProperty(ref _projectStructure, value); } public string ProjectInfo { get => _projectInfo; set => SetProperty(ref _projectInfo, value); } public bool IsLoading { get => _isLoading; set => SetProperty(ref _isLoading, value); } public IRelayCommand OpenProjectCommand { get; } public IRelayCommand SearchCommand { get; } public MainViewModel() { ProjectStructure = new ObservableCollection(); OpenProjectCommand = new RelayCommand(OpenProject); SearchCommand = new RelayCommand(SearchInProject); ProjectInfo = "No hay proyecto abierto"; } private void OpenProject() { var dialog = new VistaOpenFileDialog { Title = "Seleccionar archivo de proyecto STEP7", Filter = "Proyectos STEP7 (*.s7p)|*.s7p|Todos los archivos (*.*)|*.*", CheckFileExists = true }; if (dialog.ShowDialog() == true) { LoadProjectAsync(dialog.FileName); } } private async void LoadProjectAsync(string filePath) { try { IsLoading = true; ProjectInfo = "Cargando proyecto..."; // Reiniciar estado ProjectStructure.Clear(); _currentProject = null; // Parsear proyecto var parser = new S7ProjectParser(filePath); _currentProject = await parser.ParseProjectAsync(); // Actualizar UI ProjectStructure.Add(_currentProject); _currentProject.IsExpanded = true; // Actualizar info ProjectInfo = $"Proyecto: {Path.GetFileNameWithoutExtension(filePath)}"; } catch (Exception ex) { MessageBox.Show($"Error al cargar el proyecto: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error); ProjectInfo = "Error al cargar el proyecto"; } finally { IsLoading = false; } } private void SearchInProject() { if (_currentProject == null || string.IsNullOrWhiteSpace(SearchText)) return; try { // Recopilar todos los objetos en el proyecto var allObjects = GetAllObjects(_currentProject); // Lista para almacenar coincidencias var matchingObjects = new List(); // Buscar en función del texto de búsqueda string searchText = SearchText.Trim().ToLowerInvariant(); // Buscar objetos que coincidan con el texto foreach (var obj in allObjects) { // Comprobar si el texto de búsqueda parece ser una referencia a FC específica if (searchText.StartsWith("fc") && searchText.Length >= 3) { // Si es una función específica (por ejemplo "fc5") if (obj is S7Function func && func.Number.ToLowerInvariant() == searchText) { matchingObjects.Add(func); } } // Comprobar si queremos encontrar todas las FCs else if (searchText == "fc" || searchText == "función" || searchText == "funcion") { if (obj is S7Function) { matchingObjects.Add(obj); } } // Búsqueda en parámetros de función else if (obj is S7Function func) { if (func.ContainsText(searchText)) { matchingObjects.Add(func); } else if (func.Parameters != null) { // Buscar en los parámetros de la función foreach (var param in func.Parameters) { if (param.Name.ToLowerInvariant().Contains(searchText) || param.DataType.ToLowerInvariant().Contains(searchText) || (param.Description?.ToLowerInvariant().Contains(searchText) ?? false)) { matchingObjects.Add(func); break; } } } } // Búsqueda general para otros objetos else if (obj.ContainsText(searchText)) { matchingObjects.Add(obj); } } if (matchingObjects.Count == 0) { MessageBox.Show($"No se encontraron coincidencias para: {SearchText}", "Búsqueda", MessageBoxButton.OK, MessageBoxImage.Information); return; } // Seleccionar el primer objeto coincidente y expandir su ruta var firstMatch = matchingObjects.First(); SelectAndExpandToObject(firstMatch); // Informar al usuario if (matchingObjects.Count > 1) { MessageBox.Show($"Se encontraron {matchingObjects.Count} coincidencias. " + "Mostrando la primera coincidencia.", "Búsqueda", MessageBoxButton.OK, MessageBoxImage.Information); } } catch (Exception ex) { MessageBox.Show($"Error durante la búsqueda: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error); } } private IEnumerable GetAllObjects(S7Object root) { // Devolver el objeto raíz yield return root; // Recursivamente devolver todos los hijos foreach (var child in root.Children) { foreach (var obj in GetAllObjects(child)) { yield return obj; } } } private void SelectAndExpandToObject(S7Object obj) { // Expandir todos los nodos padres hasta llegar al objeto var parent = obj.Parent; while (parent != null) { parent.IsExpanded = true; parent = parent.Parent; } // Seleccionar el objeto SelectedTreeItem = obj; } } }