using System; using System.Collections.Generic; using System.Linq; using Project_Periodensystem.Model; using Project_Periodensystem.Persistence; namespace Project_Periodensystem.Controller { /// /// Haupt-Controller für das Periodensystem - implementiert das MVC-Pattern /// /// ZWECK UND ARCHITEKTUR: /// - Zentrale Kontrollschicht zwischen View (UI) und Model/Persistence (Daten) /// - Koordiniert alle Geschäftslogik-Operationen für das Periodensystem /// - Delegiert komplexe Aufgaben an spezialisierte Helper-Klassen (Single Responsibility Principle) /// - Bietet eine einheitliche API für alle UI-Komponenten /// /// DESIGN PATTERN: /// - MVC (Model-View-Controller): Trennt Präsentation von Geschäftslogik /// - Delegation Pattern: Überträgt Verantwortlichkeiten an spezialisierte Klassen /// - Dependency Injection: Nimmt INavigationService als abhängige Komponente entgegen /// /// C# KONZEPTE: /// - Nullable Reference Types (INavigationService?, ElementValidator?) /// - LINQ für Datenoperationen (FirstOrDefault, Where, ToArray) /// - Exception Handling mit try-catch-Blöcken /// - Lambda Expressions für Delegation an Helper-Klassen /// - Tuple-Rückgabewerte für strukturierte Daten /// public class PeriodensystemController { // ===== PRIVATE FELDER ===== /// /// Zentrale Liste aller chemischen Elemente /// List<T> ermöglicht dynamisches Hinzufügen/Entfernen von Elementen /// Private Field mit Underscore-Notation (_elements) nach C#-Konvention /// private List _elements = new List(); /// /// Navigation Service für Seitenwechsel in der Avalonia-Anwendung /// Readonly: Kann nur im Konstruktor zugewiesen werden (Immutability) /// Nullable (?): Kann null sein, da Navigation optional ist /// Interface-basiert: Ermöglicht verschiedene Implementierungen (Dependency Inversion) /// private readonly INavigationService? _navigationService; // ===== HELPER-KLASSEN FÜR CODE-ORGANISATION ===== /// /// Spezialisierte Klasse für Validierungslogik /// Nullable: Wird erst nach dem Laden der Elemente initialisiert /// Separation of Concerns: Validierung ist getrennt von anderen Aufgaben /// private ElementValidator? _validator; /// /// Spezialisierte Klasse für statistische Berechnungen /// Nullable: Wird erst nach dem Laden der Elemente initialisiert /// Single Responsibility: Nur für Statistiken zuständig /// private ElementStatistics? _statistics; // ===== KONSTRUKTOR ===== /// /// Konstruktor mit optionaler Dependency Injection /// /// PARAMETER: /// - navigationService: Optional (null by default), ermöglicht Navigation zwischen Seiten /// /// C# FEATURES: /// - Default Parameter (= null): Macht den Parameter optional /// - Nullable Reference Types: navigationService kann null sein /// - Constructor Chaining: Ruft LoadElements() zur Initialisierung auf /// /// ABLAUF: /// 1. Navigation Service speichern (kann null sein) /// 2. Elemente aus Persistence-Layer laden /// 3. Helper-Klassen mit geladenen Daten initialisieren /// public PeriodensystemController(INavigationService? navigationService = null) { _navigationService = navigationService; LoadElements(); // Daten sofort beim Erstellen laden } // ===== PRIVATE INITIALISIERUNGSMETHODEN ===== /// /// Lädt alle chemischen Elemente aus dem Persistence-Layer /// /// ZWECK: /// - Zentrale Initialisierung aller Elementdaten /// - Fehlerbehandlung beim Laden der Daten /// - Initialisierung der Helper-Klassen nach erfolgreichem Laden /// - Ausführliches Logging für Debugging und Monitoring /// /// C# KONZEPTE: /// - Exception Handling: try-catch für robuste Fehlerbehandlung /// - LINQ: Take(10) für die ersten 10 Elemente /// - Tuple Deconstruction: (totalElements, uniqueSeries, avgWeight) = GetStatistics() /// - Null-Conditional Operator: lightest?.Symbol verhindert NullReferenceException /// - String Interpolation: $"Text {variable}" für lesbare Ausgaben /// /// FEHLERBEHANDLUNG: /// - Bei Exceptions wird eine leere Liste initialisiert (Graceful Degradation) /// - Alle Fehler werden geloggt für spätere Analyse /// private void LoadElements() { try { // Elemente aus DataManager laden (Persistence Layer) _elements = DataManager.LoadElements(); Logger.Log($"Controller: {_elements.Count} Elemente erfolgreich geladen (via DataManager)"); // Helper-Klassen mit den geladenen Daten initialisieren // Delegation Pattern: Spezialisierte Klassen für verschiedene Aufgaben _validator = new ElementValidator(_elements); _statistics = new ElementStatistics(_elements); // ===== DEMONSTRATIVE LOGGING VON C#-FEATURES ===== // Arrays: Alle Element-Symbole als Array var symbols = GetAllSymbols(); Logger.LogArray("Element-Symbole (erste 10)", symbols.Take(10).ToArray()); // Tuples: Strukturierte Rückgabe mehrerer Werte var (totalElements, uniqueSeries, avgWeight) = GetStatistics(); Logger.LogTuple("Statistiken", $"Elemente: {totalElements}, Serien: {uniqueSeries}, Ø-Gewicht: {avgWeight:F2}"); // Tuples mit Objekten: Extremwerte finden var (lightest, heaviest) = GetWeightExtremes(); if (lightest != null && heaviest != null) { Logger.LogTuple("Gewichts-Extreme", $"Leichtestes: {lightest.Symbol} ({lightest.AtomicWeight}), Schwerstes: {heaviest.Symbol} ({heaviest.AtomicWeight})"); } } catch (Exception ex) { // Graceful Degradation: Bei Fehlern eine leere Liste verwenden Logger.Log($"EXCEPTION in LoadElements: {ex.Message}"); _elements = new List(); // Helper-Klassen können nicht initialisiert werden (bleiben null) _validator = null; _statistics = null; } } // ===== PUBLIC API METHODEN - ELEMENTZUGRIFF ===== /// /// Gibt alle Elemente als List<Element> zurück /// /// RÜCKGABETYP: List<Element> /// - Ermöglicht Add/Remove-Operationen /// - LINQ-Operationen verfügbar /// - Dynamische Größe /// /// VERWENDUNG: /// - Hauptsächlich für UI-Bindungen (WPF/Avalonia DataBinding) /// - Für LINQ-Abfragen in der View-Schicht /// public List GetAllElements() { return _elements; } /// /// Gibt alle Elemente als Array zurück /// /// RÜCKGABETYP: Element[] /// - Feste Größe (Read-Only nach Erstellung) /// - Bessere Performance für Iterationen /// - Weniger Speicher-Overhead als List /// /// C# KONZEPT: LINQ ToArray() /// - Konvertiert IEnumerable zu Array /// - Erstellt eine Kopie der Daten /// /// VERWENDUNG: /// - Für Algorithmen, die feste Arrays benötigen /// - Wenn Unveränderlichkeit wichtig ist /// public Element[] GetAllElementsAsArray() { return _elements.ToArray(); } /// /// Extrahiert alle Element-Symbole als String-Array /// /// ZWECK: /// - Demonstriert klassische Array-Initialisierung und -Population /// - Zeigt manuelle Iteration vs. LINQ-Alternativen /// /// C# KONZEPTE: /// - Array-Initialisierung: new string[size] /// - For-Schleifen: Klassische imperative Programmierung /// - Array-Indexing: array[i] = value /// /// ALTERNATIVE (LINQ): /// return _elements.Select(e => e.Symbol).ToArray(); /// /// LERNWERT: /// - Zeigt Unterschied zwischen imperativer und funktionaler Programmierung /// - Arrays vs. Collections /// public string[] GetAllSymbols() { // Klassische Array-Erstellung mit fester Größe string[] symbols = new string[_elements.Count]; // Manuelle Population mit for-Schleife (imperativer Stil) for (int i = 0; i < _elements.Count; i++) { symbols[i] = _elements[i].Symbol; } return symbols; } // ===== DELEGATION AN HELPER-KLASSEN ===== /// /// Diese Methoden implementieren das Delegation Pattern /// /// VORTEILE DER DELEGATION: /// - Single Responsibility Principle: Jede Klasse hat einen klaren Zweck /// - Code-Reduktion: Controller wird schlanker und übersichtlicher /// - Testbarkeit: Helper-Klassen können isoliert getestet werden /// - Wartbarkeit: Änderungen an Validierung/Statistik beeinflussen Controller nicht /// /// C# KONZEPTE: /// - Null-Conditional Operator (?.): Verhindert NullReferenceException /// - Null-Coalescing Operator (??): Liefert Fallback-Werte wenn null /// - Lambda Expressions: Kurze Syntax für einfache Delegationen /// - Expression-bodied Members: => Syntax für einzeilige Methoden /// /// FEHLERBEHANDLUNG: /// - Alle Methoden handhaben null-Helper graceful mit Fallback-Werten /// - Keine Exceptions, sondern sichere Default-Werte /// // ===== VALIDIERUNGS-METHODEN (delegiert an ElementValidator) ===== /// /// Validiert die gesamte Element-Datenbasis /// Delegation an ElementValidator.ValidateData() /// Fallback: false bei null-Validator /// public bool ValidateData() => _validator?.ValidateData() ?? false; /// /// Validiert die Position eines spezifischen Elements im Periodensystem /// Delegation an ElementValidator.ValidateElementPosition() /// Fallback: false bei null-Validator /// public bool ValidateElementPosition(Element? element) => _validator?.ValidateElementPosition(element) ?? false; // ===== STATISTIK-METHODEN (delegiert an ElementStatistics) ===== /// /// Extrahiert alle Atomgewichte als Array /// Delegation an ElementStatistics.GetAtomicWeights() /// Fallback: leeres Array bei null-Statistics /// public double[] GetAtomicWeights() => _statistics?.GetAtomicWeights() ?? new double[0]; /// /// Berechnet das durchschnittliche Atomgewicht /// Delegation an ElementStatistics.GetAverageAtomicWeight() /// Fallback: 0.0 bei null-Statistics /// public double GetAverageAtomicWeight() => _statistics?.GetAverageAtomicWeight() ?? 0.0; /// /// Sammelt alle einzigartigen Element-Serien /// Delegation an ElementStatistics.GetAllSeries() /// Fallback: leere Liste bei null-Statistics /// public List GetAllSeries() => _statistics?.GetAllSeries() ?? new List(); /// /// Sammelt wichtige Statistiken in einem Tuple /// Tuple Deconstruction: (int, int, double) für strukturierte Daten /// Delegation an ElementStatistics.GetStatistics() /// Fallback: (0, 0, 0.0) bei null-Statistics /// public (int totalElements, int uniqueSeries, double avgWeight) GetStatistics() => _statistics?.GetStatistics() ?? (0, 0, 0.0); /// /// Findet das leichteste und schwerste Element /// Tuple mit nullable Elementen: (Element?, Element?) /// Delegation an ElementStatistics.GetWeightExtremes() /// Fallback: (null, null) bei null-Statistics /// public (Element? lightest, Element? heaviest) GetWeightExtremes() => _statistics?.GetWeightExtremes() ?? (null, null); /// /// Extrahiert grundlegende Informationen eines Elements /// Tuple mit gemischten Typen: (string, string, double) /// Delegation an ElementStatistics.GetElementInfo() /// Fallback: ("?", "Unknown", 0.0) bei null-Statistics /// public (string symbol, string name, double weight) GetElementInfo(int atomicNumber) => _statistics?.GetElementInfo(atomicNumber) ?? ("?", "Unknown", 0.0); /// /// Ermittelt die Position eines Elements im Periodensystem /// Tuple mit Koordinaten: (int row, int column) /// Delegation an ElementStatistics.GetElementPosition() /// Fallback: (-1, -1) für "nicht gefunden" bei null-Statistics /// public (int row, int column) GetElementPosition(int atomicNumber) => _statistics?.GetElementPosition(atomicNumber) ?? (-1, -1); // ===== ELEMENT-SUCHFUNKTIONEN ===== /// /// Sucht ein Element anhand seiner Ordnungszahl (Atomzahl) /// /// ZWECK: /// - Eindeutige Identifizierung von Elementen /// - Ordnungszahl ist der Primärschlüssel im Periodensystem /// /// C# KONZEPTE: /// - LINQ FirstOrDefault(): Gibt erstes Element oder null zurück /// - Lambda Expression: e => e.AtomicNumber == atomicNumber /// - Nullable Return Type: Element? kann null sein /// /// PARAMETER: /// - atomicNumber: Ordnungszahl des gesuchten Elements (1-118) /// /// RÜCKGABE: /// - Element-Objekt wenn gefunden, null wenn nicht vorhanden /// /// VERWENDUNG: /// var hydrogen = controller.GetElementByAtomicNumber(1); /// if (hydrogen != null) { /* Element verwenden */ } /// public Element? GetElementByAtomicNumber(int atomicNumber) { return _elements.FirstOrDefault(e => e.AtomicNumber == atomicNumber); } /// /// Sucht ein Element anhand seines chemischen Symbols /// /// ZWECK: /// - Benutzerfreundliche Suche mit bekannten Symbolen (H, He, Li, etc.) /// - Case-insensitive Suche für bessere Usability /// /// C# KONZEPTE: /// - String.IsNullOrWhiteSpace(): Robuste Null/Empty-Prüfung /// - StringComparison.OrdinalIgnoreCase: Ignoriert Groß-/Kleinschreibung /// - Early Return Pattern: Frühzeitiger Ausstieg bei ungültigen Eingaben /// - Guard Clauses: Validierung am Methodenstart /// /// PARAMETER: /// - symbol: Chemisches Symbol (z.B. "H", "he", "LI") /// /// RÜCKGABE: /// - Element-Objekt wenn gefunden, null bei ungültigem Symbol oder nicht gefunden /// /// FEHLERBEHANDLUNG: /// - Null/Empty/Whitespace-Eingaben werden sicher behandelt /// - Keine Exception bei ungültigen Eingaben /// public Element? GetElementBySymbol(string symbol) { // Guard Clause: Ungültige Eingaben frühzeitig abfangen if (string.IsNullOrWhiteSpace(symbol)) return null; // Case-insensitive Suche für bessere Benutzerfreundlichkeit return _elements.FirstOrDefault(e => string.Equals(e.Symbol, symbol, StringComparison.OrdinalIgnoreCase)); } /// /// Filtert alle Elemente einer bestimmten chemischen Serie /// /// ZWECK: /// - Gruppierung von Elementen nach chemischen Eigenschaften /// - Ermöglicht Analyse von Element-Familien (Metalle, Nichtmetalle, etc.) /// /// C# KONZEPTE: /// - LINQ Where(): Filtert Elemente basierend auf Bedingung /// - ToList(): Konvertiert IEnumerable zu List für weitere Operationen /// - Guard Clause: Schutz vor ungültigen Eingaben /// /// PARAMETER: /// - series: Name der chemischen Serie (z.B. "Alkali metal", "Noble gas") /// /// RÜCKGABE: /// - Liste aller Elemente der angegebenen Serie /// - Leere Liste bei ungültiger Serie oder wenn keine Elemente gefunden /// /// BEISPIEL: /// var alkaliMetals = controller.GetElementsBySeries("Alkali metal"); /// // Enthält: Li, Na, K, Rb, Cs, Fr /// public List GetElementsBySeries(string series) { // Guard Clause: Ungültige Eingaben behandeln if (string.IsNullOrWhiteSpace(series)) return new List(); // LINQ-Filterung mit case-insensitive Vergleich return _elements.Where(e => string.Equals(e.Series, series, StringComparison.OrdinalIgnoreCase)).ToList(); } // ===== DATEN-MANAGEMENT ===== /// /// Lädt alle Elementdaten neu aus dem Persistence-Layer /// /// ZWECK: /// - Aktualisierung bei geänderten Datenquellen /// - Recovery nach Datenfehlern /// - Synchronisation mit externen Datenänderungen /// /// ABLAUF: /// 1. Benutzer über Neuladen informieren /// 2. LoadElements() ruft gesamte Initialisierungslogik auf /// 3. Helper-Klassen werden mit neuen Daten reinitialisiert /// /// VERWENDUNG: /// - Nach Datenimport /// - Bei Corruption Recovery /// - Für Entwicklungs-/Debug-Zwecke /// public void RefreshData() { Logger.Log("Daten werden neu geladen..."); LoadElements(); // Vollständige Reinitialisierung } /// /// Gibt die aktuelle Anzahl geladener Elemente zurück /// /// ZWECK: /// - Schnelle Verfügbarkeitsprüfung /// - UI-Statusanzeigen /// - Validierung nach Datenoperationen /// /// C# KONZEPT: /// - Expression-bodied Member: => Syntax für einzeilige Properties /// - Count Property: Effiziente Größenabfrage für List<T> /// /// RÜCKGABE: /// - Anzahl der verfügbaren Elemente (0 wenn keine geladen) /// public int GetElementCount() => _elements.Count; // ===== NAVIGATION CONTROLLER METHODEN ===== /// /// Diese Methoden implementieren den Command Pattern für UI-Aktionen /// /// ARCHITEKTUR-PRINZIPIEN: /// - Separation of Concerns: UI-Logik getrennt von Datenlogik /// - Command Pattern: Jede Benutzeraktion wird als Method-Call gekapselt /// - Exception Safety: Alle Navigation-Aktionen sind exception-safe /// - Dependency Injection: NavigationService wird injiziert, nicht direkt instanziiert /// /// C# KONZEPTE: /// - Try-Catch Blocks: Robuste Fehlerbehandlung /// - Null-Conditional Operator (?.): Sichere Methodenaufrufe /// - Method Chaining: navigationService?.Method() /// - Consistent Error Handling: Alle Methoden folgen demselben Pattern /// /// LOGGING: /// - Alle Aktionen werden geloggt für Debugging /// - Exceptions werden mit Kontext geloggt /// - Einheitliche Log-Messages für bessere Nachverfolgung /// /// /// Navigiert zur Hauptansicht des Periodensystems /// /// ZWECK: /// - Wechsel zur interaktiven Periodensystem-Darstellung /// - Hauptfunktion der Anwendung /// /// FEHLERBEHANDLUNG: /// - Exception wird geloggt, aber nicht weitergegeben /// - Navigation Service kann null sein (optional dependency) /// - Graceful Degradation bei Navigationsfehlern /// public void HandleNavigateToPeriodicTable() { try { Logger.Log("Controller: Navigation zum Periodensystem angefordert"); _navigationService?.NavigateToPeriodicTable(); } catch (Exception ex) { Logger.LogException(ex, "HandleNavigateToPeriodicTable"); } } /// /// Navigiert zur Informationsseite über die Anwendung /// /// ZWECK: /// - Anzeige von Anwendungsinformationen /// - Credits und Versionsinformationen /// - Hilfe und Dokumentation /// public void HandleNavigateToAbout() { try { Logger.Log("Controller: Navigation zu About angefordert"); _navigationService?.NavigateToAbout(); } catch (Exception ex) { Logger.LogException(ex, "HandleNavigateToAbout"); } } /// /// Navigiert zurück zur Startseite/Landing Page /// /// ZWECK: /// - Rückkehr zum Hauptmenü /// - Reset der Anwendung zum Ausgangszustand /// - Home-Button Funktionalität /// public void HandleNavigateToLanding() { try { Logger.Log("Controller: Navigation zur Landing Page angefordert"); _navigationService?.NavigateToLanding(); } catch (Exception ex) { Logger.LogException(ex, "HandleNavigateToLanding"); } } /// /// Wechselt zwischen hellen und dunklen UI-Themes /// /// ZWECK: /// - Benutzerfreundlichkeit durch Theme-Auswahl /// - Accessibility (Dunkel-Modus für Augen-schonend) /// - Moderne UI-Standards erfüllen /// /// UI-PATTERN: /// - Toggle-Funktionalität (Hell ↔ Dunkel) /// - Persistierung des gewählten Themes /// public void HandleToggleTheme() { try { Logger.Log("Controller: Theme-Wechsel angefordert"); _navigationService?.ToggleTheme(); } catch (Exception ex) { Logger.LogException(ex, "HandleToggleTheme"); } } /// /// Startet den Datenexport-Prozess /// /// ZWECK: /// - Export der Elementdaten in verschiedene Formate /// - Datensicherung und -portabilität /// - Integration mit anderen Anwendungen /// /// UI-WORKFLOW: /// - Zeigt Bestätigungsdialog an /// - Benutzer wählt Export-Optionen /// - Export wird durchgeführt und bestätigt /// public void HandleExportData() { try { Logger.Log("Controller: Daten-Export angefordert"); _navigationService?.ShowExportConfirmation(); } catch (Exception ex) { Logger.LogException(ex, "HandleExportData"); } } } }