328 lines
13 KiB
C#
328 lines
13 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text.Json;
|
|
using Project_Periodensystem.Model;
|
|
|
|
namespace Project_Periodensystem.Persistence
|
|
{
|
|
/// <summary>
|
|
/// 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
|
|
/// </summary>
|
|
public static class DataManager
|
|
{
|
|
// ===== PFAD-KONFIGURATION =====
|
|
|
|
/// <summary>
|
|
/// 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
|
|
/// </summary>
|
|
private static readonly string DataDirectory = Path.Combine(
|
|
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
|
"Periodensystem");
|
|
|
|
/// <summary>
|
|
/// Vollständiger Pfad zur Element-Datenbasis (JSON)
|
|
/// Speichert alle chemischen Elemente mit ihren Eigenschaften
|
|
/// </summary>
|
|
private static readonly string ElementsFile = Path.Combine(DataDirectory, "elements.json");
|
|
|
|
/// <summary>
|
|
/// Vollständiger Pfad zu Benutzereinstellungen (JSON)
|
|
/// Speichert Präferenzen wie Theme, Sprache, letzte Nutzung
|
|
/// </summary>
|
|
private static readonly string SettingsFile = Path.Combine(DataDirectory, "settings.json");
|
|
|
|
// ===== ELEMENT-DATEN PERSISTENZ =====
|
|
|
|
/// <summary>
|
|
/// 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
|
|
/// </summary>
|
|
/// <param name="elements">Liste der zu speichernden Elemente</param>
|
|
public static void SaveElements(List<Element> 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
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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
|
|
/// </summary>
|
|
/// <returns>Liste aller verfügbaren chemischen Elemente</returns>
|
|
public static List<Element> LoadElements()
|
|
{
|
|
try
|
|
{
|
|
// Prüfung ob benutzerdefinierte Daten existieren
|
|
if (File.Exists(ElementsFile))
|
|
{
|
|
var json = File.ReadAllText(ElementsFile);
|
|
var elements = JsonSerializer.Deserialize<List<Element>>(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 =====
|
|
|
|
/// <summary>
|
|
/// 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
|
|
/// </summary>
|
|
/// <param name="settings">AppSettings-Objekt mit Benutzer-Präferenzen</param>
|
|
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
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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
|
|
/// </summary>
|
|
/// <returns>AppSettings-Objekt (entweder geladen oder mit Defaults)</returns>
|
|
public static AppSettings LoadSettings()
|
|
{
|
|
try
|
|
{
|
|
if (File.Exists(SettingsFile))
|
|
{
|
|
var json = File.ReadAllText(SettingsFile);
|
|
var settings = JsonSerializer.Deserialize<AppSettings>(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();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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
|
|
/// </summary>
|
|
public class AppSettings
|
|
{
|
|
/// <summary>
|
|
/// 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
|
|
/// </summary>
|
|
public string LastTheme { get; set; } = "Dark";
|
|
|
|
/// <summary>
|
|
/// Zeitstempel der letzten Anwendungsnutzung
|
|
///
|
|
/// ZWECK:
|
|
/// - Nutzungsstatistiken
|
|
/// - "Willkommen zurück"-Funktionen
|
|
/// - Data Analytics für Verbesserungen
|
|
///
|
|
/// DEFAULT: DateTime.Now - Aktueller Zeitpunkt bei Erstellung
|
|
/// </summary>
|
|
public DateTime LastUsed { get; set; } = DateTime.Now;
|
|
|
|
/// <summary>
|
|
/// 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
|
|
/// </summary>
|
|
public string PreferredLanguage { get; set; } = "German";
|
|
}
|
|
} |