using System;
using System.IO;
using System.Linq;
namespace Project_Periodensystem.Model
{
///
/// Zentrale Logging-Klasse für Debug-Ausgaben und Fehlerprotokollierung
///
/// ZWECK UND ARCHITEKTUR:
/// - Einheitliche Logging-Infrastruktur für die gesamte Anwendung
/// - Dual-Output: Konsole (Development) und Datei (Production/Debugging)
/// - Verschiedene Log-Level für strukturierte Protokollierung
/// - Demonstration verschiedener C#-Konzepte und Datentypen
///
/// DESIGN PATTERNS:
/// - Static Class: Globaler Zugriff ohne Instanziierung
/// - Facade Pattern: Vereinfachte API für komplexe Logging-Operationen
/// - Strategy Pattern: Verschiedene Ausgabekanäle (Konsole, Datei)
///
/// C# KONZEPTE:
/// - Static Constructor: Einmalige Initialisierung beim ersten Zugriff
/// - Exception Handling: Try-Catch für robuste Datei-Operationen
/// - Method Overloading: Verschiedene LogArray-Varianten
/// - Conditional Compilation: [Conditional("DEBUG")] für LogDebug
/// - LINQ: Select() für Datenformatierung
/// - String Interpolation: $"Text {variable}" für lesbare Ausgaben
///
/// SICHERHEIT UND ROBUSTHEIT:
/// - Alle Datei-Operationen sind exception-safe
/// - Logging-Fehler bringen die Hauptanwendung nicht zum Absturz
/// - Graceful Degradation bei fehlenden Dateiberechtigungen
///
public static class Logger
{
///
/// Pfad zur Log-Datei im lokalen Anwendungsverzeichnis
///
/// PFAD-KONSTRUKTION:
/// - Environment.SpecialFolder.LocalApplicationData: Benutzer-spezifischer App-Ordner
/// - Windows: C:\Users\[Username]\AppData\Local\Periodensystem\app.log
/// - Cross-Platform: Funktioniert auf Windows, Linux, macOS
///
/// C# KONZEPTE:
/// - Path.Combine(): Sichere Pfad-Konstruktion (OS-unabhängig)
/// - Environment.SpecialFolder: Standard-Verzeichnisse des Betriebssystems
/// - Readonly Field: Kann nur bei Deklaration oder im static Constructor gesetzt werden
///
private static readonly string LogFilePath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"Periodensystem", "app.log");
///
/// Statischer Konstruktor - Einmalige Initialisierung der Logger-Infrastruktur
///
/// ZWECK:
/// - Erstellt das Log-Verzeichnis falls es nicht existiert
/// - Wird automatisch beim ersten Zugriff auf die Klasse aufgerufen
/// - Kann nicht explizit aufgerufen werden
///
/// C# KONZEPTE:
/// - Static Constructor: Automatische Initialisierung ohne Parameter
/// - Path.GetDirectoryName(): Extrahiert Verzeichnis aus vollständigem Pfad
/// - Directory.CreateDirectory(): Erstellt Verzeichnis-Hierarchie rekursiv
/// - Exception Handling: Fehler werden "geschluckt" für Robustheit
///
/// FEHLERBEHANDLUNG:
/// - Bei Problemen wird nur Konsolen-Logging verwendet
/// - Keine Exception nach außen, da Logging optional ist
///
static Logger()
{
try
{
var logDirectory = Path.GetDirectoryName(LogFilePath);
if (logDirectory != null && !Directory.Exists(logDirectory))
{
Directory.CreateDirectory(logDirectory);
}
}
catch
{
// Falls Log-Datei nicht erstellt werden kann, nur Konsole verwenden
// Graceful Degradation: Hauptfunktionalität nicht beeinträchtigen
}
}
// ===== HAUPTPROTOKOLLIERUNGS-METHODEN =====
///
/// Zentrale Logging-Methode - protokolliert Nachrichten dual (Konsole + Datei)
///
/// ZWECK:
/// - Universelle Protokollierung für alle Anwendungsereignisse
/// - Entwickler sehen Ausgaben in Konsole (sofortiges Feedback)
/// - Benutzer/Support kann Logs aus Datei analysieren
///
/// C# KONZEPTE:
/// - String.IsNullOrWhiteSpace(): Robuste Null/Empty/Whitespace-Prüfung
/// - DateTime.Now.ToString(): Formatierte Zeitstempel
/// - String Interpolation: $"[{timestamp}] {message}"
/// - File.AppendAllText(): Atomare Datei-Operation
/// - Environment.NewLine: OS-spezifische Zeilentrenner
///
/// FEHLERBEHANDLUNG:
/// - Guard Clause: Leere Nachrichten werden ignoriert
/// - Try-Catch um Datei-Operation: Konsole funktioniert immer
/// - Keine Exception nach außen: Logging darf nie Hauptanwendung stören
///
/// THREAD-SAFETY:
/// - File.AppendAllText ist thread-safe
/// - Console.WriteLine ist thread-safe
/// - Methode kann von mehreren Threads gleichzeitig aufgerufen werden
///
/// Zu protokollierende Nachricht (wird validiert)
public static void Log(string message)
{
// Guard Clause: Ungültige Eingaben frühzeitig abfangen
if (string.IsNullOrWhiteSpace(message))
return;
// Zeitstempel im ISO-ähnlichen Format für bessere Lesbarkeit
var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
var logEntry = $"[{timestamp}] {message}";
// Konsolen-Ausgabe (für Entwicklung und sofortiges Feedback)
Console.WriteLine(logEntry);
// Datei-Ausgabe (für Persistenz und spätere Analyse)
try
{
File.AppendAllText(LogFilePath, logEntry + Environment.NewLine);
}
catch
{
// Fehler beim Schreiben ignorieren um App nicht zum Absturz zu bringen
// Silent Fail: Logging ist nice-to-have, nicht essential
}
}
// ===== SPEZIALISIERTE LOGGING-METHODEN =====
///
/// Protokolliert Exceptions mit vollständigen Diagnose-Informationen
///
/// ZWECK:
/// - Strukturierte Fehlerprotokollierung für Debugging
/// - Vollständige Stack-Trace-Information für Fehleranalyse
/// - Kontextuelle Information für bessere Problemlösung
///
/// C# KONZEPTE:
/// - Exception Handling: ex.Message und ex.StackTrace Properties
/// - Null-Check: Schutz vor null-Exceptions
/// - String Interpolation: Eingebettete Variablen in Strings
/// - Conditional Operator: condition ? valueIfTrue : valueIfFalse
/// - Multi-Line Strings: \n für Zeilenumbrüche
///
/// PARAMETER:
/// - ex: Die zu protokollierende Exception (kann theoretisch null sein)
/// - context: Optional - zusätzlicher Kontext (Methodenname, Operation, etc.)
///
/// VERWENDUNG:
/// try { riskyOperation(); } catch (Exception ex) { Logger.LogException(ex, "DataLoad"); }
///
/// Exception die protokolliert werden soll
/// Zusätzlicher Kontext (Methodenname, Operation, etc.)
public static void LogException(Exception ex, string context = "")
{
// Null-Schutz: Auch ungültige Exception-Objekte handhaben
if (ex == null)
{
Log("Null-Exception übergeben - möglicher Programmierfehler");
return;
}
// Formatierung je nach verfügbarem Kontext
var message = string.IsNullOrWhiteSpace(context)
? $"EXCEPTION: {ex.Message}\nStack: {ex.StackTrace}"
: $"EXCEPTION in {context}: {ex.Message}\nStack: {ex.StackTrace}";
Log(message);
}
///
/// Protokolliert Warnungen - für nicht-kritische Probleme
///
/// ZWECK:
/// - Kennzeichnung von Problemen die behoben werden sollten
/// - Unterscheidung von Informationen und echten Fehlern
/// - Monitoring von potentiellen Problemen
///
/// BEISPIELE:
/// - Veraltete API-Aufrufe
/// - Performance-Probleme
/// - Unerwartete aber handhabbare Situationen
///
/// Warnung (wird mit WARNING: Präfix versehen)
public static void LogWarning(string message)
{
Log($"WARNING: {message}");
}
///
/// Protokolliert Fehler - für schwerwiegende Probleme
///
/// ZWECK:
/// - Kennzeichnung von Fehlern die Funktionalität beeinträchtigen
/// - Höhere Priorität als Warnings bei Log-Analyse
/// - Monitoring von kritischen Problemen
///
/// BEISPIELE:
/// - Datenverlust oder Corruption
/// - Netzwerk-/Datenbankfehler
/// - Konfigurationsprobleme
///
/// Fehlermeldung (wird mit ERROR: Präfix versehen)
public static void LogError(string message)
{
Log($"ERROR: {message}");
}
///
/// Protokolliert Debug-Informationen - nur in Debug-Builds kompiliert
///
/// ZWECK:
/// - Detaillierte Entwicklungs-Informationen
/// - Automatische Entfernung in Release-Builds
/// - Performance-Optimierung (keine Debug-Logs in Production)
///
/// C# KONZEPTE:
/// - Conditional Compilation: [Conditional("DEBUG")]
/// - Attribute-based Programming: Verhalten durch Metadaten steuern
/// - Build Configuration: Unterschiedliches Verhalten je nach Build-Typ
///
/// COMPILER-VERHALTEN:
/// - Debug Build: Methode wird normal ausgeführt
/// - Release Build: Methoden-Aufrufe werden vollständig entfernt
/// - Zero Performance Impact in Production
///
/// Debug-Nachricht (wird mit DEBUG: Präfix versehen)
[System.Diagnostics.Conditional("DEBUG")]
public static void LogDebug(string message)
{
Log($"DEBUG: {message}");
}
// ===== DATEI-MANAGEMENT UND UTILITY-METHODEN =====
///
/// Löscht die Log-Datei für Cleanup-Operationen
///
/// ZWECK:
/// - Speicherplatz freigeben bei großen Log-Dateien
/// - Fresh Start für neue Test-Sessions
/// - Maintenance-Operation für Anwendungs-Lifecycle
///
/// C# KONZEPTE:
/// - File.Exists(): Existenz-Prüfung vor Operation
/// - File.Delete(): Atomare Datei-Löschung
/// - Exception Handling: Robust gegen Berechtigungsprobleme
///
/// SICHERHEIT:
/// - Prüft Existenz vor Löschung (vermeidet FileNotFoundException)
/// - Catch für Berechtigungsfehler oder Datei-in-Verwendung
/// - Loggt eigene Operationen (self-documenting)
///
public static void ClearLog()
{
try
{
if (File.Exists(LogFilePath))
{
File.Delete(LogFilePath);
Log("Log-Datei gelöscht und neu initialisiert");
}
}
catch (Exception ex)
{
Log($"Fehler beim Löschen der Log-Datei: {ex.Message}");
}
}
///
/// Gibt den vollständigen Pfad zur Log-Datei zurück
///
/// ZWECK:
/// - Ermöglicht externen Tools Zugriff auf Log-Datei
/// - Debugging: Entwickler kann Log-Datei manuell öffnen
/// - Integration: Andere Komponenten können Logs lesen
///
/// KAPSELUNG:
/// - Kontrollierter Zugriff auf private LogFilePath
/// - Readonly-Zugriff: Externe Komponenten können Pfad nicht ändern
/// - Information Hiding: Implementation Details bleiben verborgen
///
/// Vollständiger Pfad zur Log-Datei (absoluter Pfad)
public static string GetLogFilePath()
{
return LogFilePath;
}
// ===== SPEZIALISIERTE DATENTYP-LOGGING (C# LERNZWECK) =====
///
/// Loggt String-Arrays - demonstriert Array-Verarbeitung
///
/// ZWECK:
/// - Zeigt Array-Inhalte in lesbarer Form
/// - Demonstriert string.Join() für Array-zu-String-Konvertierung
/// - Nützlich für Listen von Elementsymbolen, Namen, etc.
///
/// C# KONZEPTE:
/// - Method Overloading: Mehrere LogArray-Methoden für verschiedene Typen
/// - string.Join(): Elegante Array-zu-String-Konvertierung
/// - Array-Parameter: string[] als Eingabe
///
/// BEISPIEL-AUSGABE:
/// "Element-Symbole: [H, He, Li, Be, B, C, N, O, F, Ne]"
///
/// Beschreibender Titel für das Array
/// Array von Strings zur Anzeige
public static void LogArray(string title, string[] items)
{
Log($"{title}: [{string.Join(", ", items)}]");
}
///
/// Loggt Double-Arrays - demonstriert numerische Array-Verarbeitung
///
/// ZWECK:
/// - Zeigt numerische Daten in formatierter Form
/// - Demonstriert LINQ Select() für Datenformatierung
/// - Nützlich für Atomgewichte, Dichten, Elektronegativitäten
///
/// C# KONZEPTE:
/// - LINQ Select(): Funktionale Programmierung für Datentransformation
/// - Lambda Expression: n => n.ToString("F2") für Formatierung
/// - ToString() mit Format-String: "F2" für 2 Dezimalstellen
/// - Method Overloading: Verschiedene Typen, gleicher Methodenname
///
/// BEISPIEL-AUSGABE:
/// "Atomgewichte: [1.01, 4.00, 6.94, 9.01, 10.81]"
///
/// Beschreibender Titel für das Array
/// Array von Double-Werten zur Anzeige
public static void LogArray(string title, double[] numbers)
{
// LINQ Select() wandelt jede Zahl in formatierten String um
var formattedNumbers = numbers.Select(n => n.ToString("F2")).ToArray();
Log($"{title}: [{string.Join(", ", formattedNumbers)}]");
}
///
/// Loggt Tuple-Informationen - demonstriert strukturierte Datenausgabe
///
/// ZWECK:
/// - Zeigt Tuple-Inhalte in lesbarer Form
/// - Demonstriert strukturierte Datenprotokollierung
/// - Nützlich für Element-Statistiken und zusammengehörige Werte
///
/// C# KONZEPTE:
/// - Tuple: Strukturierte Datencontainer
/// - String als Parameter: Bereits formatierte Tuple-Darstellung
/// - Delegation: Ruft zentrale Log()-Methode auf
///
/// VERWENDUNG:
/// var stats = GetStatistics(); // returns (int, int, double)
/// Logger.LogTuple("Statistiken", $"Elemente: {stats.Item1}, Serien: {stats.Item2}");
///
/// BEISPIEL-AUSGABE:
/// "Element-Info: Symbol: H, Name: Hydrogen, Gewicht: 1.01"
///
/// Beschreibender Titel für das Tuple
/// Bereits formatierte Tuple-Darstellung als String
public static void LogTuple(string title, string tupleInfo)
{
Log($"{title}: {tupleInfo}");
}
}
}