using System; using System.Collections.Generic; using System.IO; using System.Text.Json; using Project_Periodensystem.Model; namespace Project_Periodensystem.Persistence { /// /// Zentrale Persistenz-Schicht für JSON-basierte Datenspeicherung /// /// ZWECK UND ARCHITEKTUR: /// - Abstrahiert Datei-I/O von der Geschäftslogik (Separation of Concerns) /// - Implementiert Repository Pattern für Element- und Settings-Daten /// - Bietet Fallback-Mechanismus für robuste Datenversorgung /// - Demonstriert moderne .NET JSON-Serialisierung /// /// DESIGN PATTERNS: /// - Repository Pattern: Zentrale Datenquelle mit einheitlicher API /// - Static Class: Globaler Zugriff ohne Instanziierung /// - Fallback Strategy: Graceful Degradation bei fehlenden Dateien /// - Factory Pattern: Erstellt Default-Objekte wenn nötig /// /// C# KONZEPTE: /// - System.Text.Json: Modernes JSON-Framework (.NET Core/5+) /// - JsonSerializerOptions: Konfiguration der JSON-Ausgabe /// - Generic Methods: Wiederverwendbare Serialisierung für verschiedene Typen /// - Exception Handling: Robuste Fehlerbehandlung bei I/O-Operationen /// - Null-Coalescing (??): Fallback-Werte bei null-Objekten /// /// DATENSPEICHERUNG: /// - LocalApplicationData: Benutzer-spezifische, nicht-roaming Daten /// - JSON Format: Menschenlesbar, plattformunabhängig, einfach zu debuggen /// - Strukturierte Verzeichnisse: Organisierte Dateiablage /// public static class DataManager { // ===== PFAD-KONFIGURATION ===== /// /// Basis-Verzeichnis für alle Anwendungsdaten /// /// PFAD-STRATEGIEN: /// - LocalApplicationData: Benutzer-spezifisch, lokal (nicht synchronisiert) /// - Windows: C:\Users\[Username]\AppData\Local\Periodensystem\ /// - Cross-Platform: Funktioniert auf Windows, Linux, macOS /// /// VORTEILE: /// - Keine Admin-Rechte erforderlich /// - Benutzer-spezifische Isolation /// - Standard-Konformität mit OS-Richtlinien /// private static readonly string DataDirectory = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Periodensystem"); /// /// Vollständiger Pfad zur Element-Datenbasis (JSON) /// Speichert alle chemischen Elemente mit ihren Eigenschaften /// private static readonly string ElementsFile = Path.Combine(DataDirectory, "elements.json"); /// /// Vollständiger Pfad zu Benutzereinstellungen (JSON) /// Speichert Präferenzen wie Theme, Sprache, letzte Nutzung /// private static readonly string SettingsFile = Path.Combine(DataDirectory, "settings.json"); // ===== ELEMENT-DATEN PERSISTENZ ===== /// /// Speichert eine Element-Liste als JSON-Datei /// /// ZWECK: /// - Persistierung von benutzerdefinierten oder bearbeiteten Elementen /// - Backup von Element-Daten für Wiederherstellung /// - Export-Funktionalität für Datenübertragung /// /// C# KONZEPTE: /// - JsonSerializer.Serialize(): Moderne .NET JSON-Serialisierung /// - JsonSerializerOptions: Konfiguration der JSON-Ausgabe /// - WriteIndented: Menschenlesbare Formatierung (Pretty-Print) /// - Directory.CreateDirectory(): Erstellt Verzeichnis-Hierarchie falls nötig /// - File.WriteAllText(): Atomare Datei-Schreiboperation /// /// FEHLERBEHANDLUNG: /// - Try-Catch um gesamte Operation /// - Logging aller Erfolgs- und Fehlerfälle /// - Graceful Degradation: Anwendung funktioniert ohne Persistenz /// /// JSON-AUSGABE: /// - Eingerückt und formatiert für manuelle Bearbeitung /// - UTF-8 Encoding für internationale Zeichen /// - Standard JSON-Format für Interoperabilität /// /// Liste der zu speichernden Elemente public static void SaveElements(List elements) { try { // Verzeichnis erstellen falls nicht vorhanden Directory.CreateDirectory(DataDirectory); // JSON-Serialisierung mit lesbarer Formatierung var json = JsonSerializer.Serialize(elements, new JsonSerializerOptions { WriteIndented = true }); // Atomare Datei-Operation (ersetzt bestehende Datei) File.WriteAllText(ElementsFile, json); Logger.Log($"Elemente erfolgreich gespeichert: {elements.Count} Einträge in {ElementsFile}"); } catch (Exception ex) { Logger.LogException(ex, "SaveElements"); // Keine Weiterleitung der Exception - Speichern ist optional } } /// /// Lädt Elemente aus JSON-Datei mit Fallback zu eingebauten Daten /// /// ZWECK: /// - Primäre Datenquelle für alle Element-Informationen /// - Robuste Datenversorgung durch Fallback-Mechanismus /// - Unterstützung für persistierte Benutzeränderungen /// /// FALLBACK-STRATEGIE: /// 1. Versuche JSON-Datei zu laden (benutzerdefinierte Daten) /// 2. Bei Fehlern: Fallback zu PeriodicTableData.Elements (eingebaute Daten) /// 3. Garantiert immer eine funktionsfähige Element-Liste /// /// C# KONZEPTE: /// - JsonSerializer.Deserialize<T>(): Generische Deserialisierung /// - File.Exists(): Existenz-Prüfung vor Dateizugriff /// - Null-Conditional Check: elements != null && elements.Count > 0 /// - Multiple Return Points: Verschiedene Ausstiegspunkte je nach Szenario /// /// FEHLERBEHANDLUNG: /// - Alle I/O-Operationen in try-catch /// - Validierung der deserialisierten Daten /// - Logging aller Ladeschritte für Debugging /// - Graceful Fallback ohne Exception-Weiterleitung /// /// Liste aller verfügbaren chemischen Elemente public static List LoadElements() { try { // Prüfung ob benutzerdefinierte Daten existieren if (File.Exists(ElementsFile)) { var json = File.ReadAllText(ElementsFile); var elements = JsonSerializer.Deserialize>(json); // Validierung der deserialisierten Daten if (elements != null && elements.Count > 0) { Logger.Log($"Elemente aus benutzerdefinierter Datei geladen: {elements.Count} Einträge"); return elements; } } } catch (Exception ex) { Logger.LogException(ex, "LoadElements - JSON Loading"); // Kein Re-throw - Fallback folgt } // Fallback zu eingebauten, statischen Daten Logger.Log("Fallback zu eingebauten Element-Daten (PeriodicTableData)"); return PeriodicTableData.Elements; } // ===== BENUTZEREINSTELLUNGEN PERSISTENZ ===== /// /// Speichert Benutzereinstellungen als JSON-Datei /// /// ZWECK: /// - Persistierung von Benutzer-Präferenzen zwischen App-Sessions /// - Theme-Einstellungen, Sprach-Präferenzen, etc. speichern /// - Personalisierte Benutzererfahrung ermöglichen /// /// C# KONZEPTE: /// - Gleiche JSON-Serialisierung wie bei Elementen /// - Konsistente Fehlerbehandlung und Logging /// - Atomare Datei-Operationen für Datenintegrität /// /// SETTINGS-BEISPIELE: /// - UI Theme (Light/Dark) /// - Bevorzugte Sprache /// - Letzte Nutzung (für Statistiken) /// - Personalisierte Element-Ansichten /// /// AppSettings-Objekt mit Benutzer-Präferenzen public static void SaveSettings(AppSettings settings) { try { // Verzeichnis sicherstellen (gleich wie bei Elementen) Directory.CreateDirectory(DataDirectory); // JSON-Serialisierung mit Pretty-Print var json = JsonSerializer.Serialize(settings, new JsonSerializerOptions { WriteIndented = true }); // Atomare Speicherung File.WriteAllText(SettingsFile, json); Logger.Log($"Benutzereinstellungen gespeichert: Theme={settings.LastTheme}, Sprache={settings.PreferredLanguage}"); } catch (Exception ex) { Logger.LogException(ex, "SaveSettings"); // Keine Exception-Weiterleitung - Settings sind optional } } /// /// Lädt Benutzereinstellungen aus JSON-Datei /// /// ZWECK: /// - Wiederherstellung der Benutzer-Präferenzen beim App-Start /// - Fallback zu Default-Settings bei fehlender oder korrupter Datei /// - Konsistente Benutzererfahrung über Sessions hinweg /// /// FALLBACK-VERHALTEN: /// - Bei fehlender Datei: Neue AppSettings() mit Defaults /// - Bei JSON-Fehlern: Neue AppSettings() mit Defaults /// - Garantiert immer gültige Settings-Objekt /// /// C# KONZEPTE: /// - Null-Coalescing Operator (??): settings ?? new AppSettings() /// - Constructor mit Default-Werten in AppSettings /// - Robuste Deserialisierung mit Fallback /// /// AppSettings-Objekt (entweder geladen oder mit Defaults) public static AppSettings LoadSettings() { try { if (File.Exists(SettingsFile)) { var json = File.ReadAllText(SettingsFile); var settings = JsonSerializer.Deserialize(json); // Null-Coalescing für sichere Rückgabe var result = settings ?? new AppSettings(); Logger.Log($"Benutzereinstellungen geladen: Theme={result.LastTheme}"); return result; } } catch (Exception ex) { Logger.LogException(ex, "LoadSettings"); // Kein Re-throw - Fallback zu Defaults } // Fallback zu Default-Settings Logger.Log("Fallback zu Standard-Benutzereinstellungen"); return new AppSettings(); } } /// /// Datenmodell für persistierte Benutzereinstellungen /// /// ZWECK UND STRUKTUR: /// - Kapselt alle persistierbaren Benutzer-Präferenzen /// - Einfache Erweiterung um neue Settings möglich /// - JSON-serialisierbar durch Auto-Properties /// - Default-Werte für robuste Initialisierung /// /// DESIGN PRINCIPLES: /// - Data Transfer Object (DTO): Reine Datenklasse /// - Default Values: Sinnvolle Startwerte für neue Installationen /// - Extensibility: Einfache Erweiterung um neue Properties /// - Immutable nach Konstruktion: Properties könnten readonly sein /// /// C# KONZEPTE: /// - Auto-Properties mit Default-Initialisierung /// - DateTime für Zeitstempel /// - String-Properties für einfache Serialisierung /// - Parameterloser Constructor (implizit für JSON-Deserialisierung) /// /// JSON-SERIALISIERUNG: /// - Alle Properties werden automatisch serialisiert /// - Property-Namen werden als JSON-Keys verwendet /// - Default-Werte sorgen für robuste Deserialisierung /// public class AppSettings { /// /// Zuletzt verwendetes UI-Theme /// /// WERTE: /// - "Light": Helles Theme für Tag-Nutzung /// - "Dark": Dunkles Theme für augen-schonende Nutzung /// - "Auto": System-Theme folgen (Windows/macOS) /// /// DEFAULT: "Dark" - Moderner Standard für Entwicklungs-Tools /// public string LastTheme { get; set; } = "Dark"; /// /// Zeitstempel der letzten Anwendungsnutzung /// /// ZWECK: /// - Nutzungsstatistiken /// - "Willkommen zurück"-Funktionen /// - Data Analytics für Verbesserungen /// /// DEFAULT: DateTime.Now - Aktueller Zeitpunkt bei Erstellung /// public DateTime LastUsed { get; set; } = DateTime.Now; /// /// Bevorzugte Sprache der Benutzeroberfläche /// /// WERTE: /// - "German": Deutsche Lokalisierung /// - "English": Englische Lokalisierung /// - "French": Französische Lokalisierung (wenn implementiert) /// /// DEFAULT: "German" - Da es ein deutsches Lernprojekt ist /// public string PreferredLanguage { get; set; } = "German"; } }