Projekt_SS25/Project_Periodensystem.Controller/ElementValidator.cs

158 lines
6.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using Project_Periodensystem.Model;
namespace Project_Periodensystem.Controller
{
/// <summary>
/// ElementValidator - Spezialisierte Klasse für Datenvalidierung
///
/// Diese Klasse wurde aus dem PeriodensystemController ausgelagert, um das
/// Single Responsibility Principle (SRP) zu befolgen. Sie ist ausschließlich
/// für die Validierung von Element-Daten zuständig.
///
/// Vorteile der Auslagerung:
/// - Bessere Testbarkeit (kann isoliert getestet werden)
/// - Klarere Verantwortlichkeiten
/// - Wiederverwendbarkeit in anderen Controllern
/// - Einfachere Wartung und Erweiterung
/// </summary>
public class ElementValidator
{
// Private readonly Liste der zu validierenden Elemente
// readonly = kann nach Initialisierung nicht mehr geändert werden
private readonly List<Element> _elements;
/// <summary>
/// Konstruktor - Initialisiert den Validator mit einer Element-Liste
/// </summary>
/// <param name="elements">Liste der zu validierenden Elemente</param>
public ElementValidator(List<Element> elements)
{
// Null-Check mit Fallback zu leerer Liste - verhindert NullReferenceExceptions
_elements = elements ?? new List<Element>();
}
/// <summary>
/// Führt eine umfassende Validierung der Element-Daten durch.
///
/// Diese Methode prüft verschiedene Datenintegritäts-Aspekte:
/// 1. Existenz von Elementen (leere Liste = Problem)
/// 2. Eindeutigkeit der Atomnummern (jede darf nur einmal vorkommen)
/// 3. Vollständigkeit der Element-Symbole (keine leeren/null Werte)
///
/// Verwendet moderne C# LINQ-Syntax für effiziente Datenabfragen:
/// - GroupBy() für Gruppierung nach Atomnummer
/// - Where() für Filterung
/// - Any() für Existenzprüfung
/// - Count() für Anzahl-Ermittlung
/// </summary>
/// <returns>true = alle Validierungen bestanden, false = Fehler gefunden</returns>
public bool ValidateData()
{
// Erste Prüfung: Sind überhaupt Elemente vorhanden?
// Any() ist effizienter als Count() > 0, da es beim ersten Element stoppt
if (!_elements.Any())
{
Logger.Log("Keine Elemente zum Validieren");
return false;
}
// Zweite Prüfung: Doppelte Atomnummern aufspüren
// LINQ-Chain: GroupBy sammelt Elemente mit gleicher Atomnummer
// Where filtert Gruppen mit mehr als einem Element (= Duplikate)
// Select extrahiert nur die Atomnummer (Key) für Logging
var duplicateNumbers = _elements.GroupBy(e => e.AtomicNumber)
.Where(g => g.Count() > 1)
.Select(g => g.Key);
if (duplicateNumbers.Any())
{
// string.Join() erstellt eine kommaseparierte Liste der doppelten Nummern
Logger.Log($"Doppelte Atomnummern gefunden: {string.Join(", ", duplicateNumbers)}");
return false;
}
// Dritte Prüfung: Leere oder ungültige Element-Symbole finden
// string.IsNullOrWhiteSpace() prüft auf null, leer oder nur Leerzeichen
var emptySymbols = _elements.Where(e => string.IsNullOrWhiteSpace(e.Symbol));
if (emptySymbols.Any())
{
Logger.Log($"Elemente mit leeren Symbolen gefunden: {emptySymbols.Count()}");
return false;
}
// Alle Validierungen bestanden
Logger.Log("Datenvalidierung erfolgreich");
return true;
}
/// <summary>
/// Validiert die Position eines Elements im Periodensystem.
///
/// Das Periodensystem hat feste Dimensionen:
/// - Zeilen (Perioden): 0-9 (insgesamt 10 Perioden)
/// - Spalten (Gruppen): 0-17 (insgesamt 18 Gruppen)
///
/// Diese Methode stellt sicher, dass Elemente nur an gültigen Positionen
/// platziert werden. Ungültige Positionen würden zu Layout-Fehlern oder
/// Abstürzen in der Benutzeroberfläche führen.
///
/// Verwendet nullable Reference Types (Element?) - moderne C# 8.0+ Syntax
/// </summary>
/// <param name="element">Das zu prüfende Element (kann null sein)</param>
/// <returns>true = Position ist gültig, false = Position ungültig oder Element ist null</returns>
public bool ValidateElementPosition(Element? element)
{
// Null-Check: Defensive Programmierung verhindert NullReferenceExceptions
if (element == null)
{
Logger.Log("Element ist null");
return false;
}
// Positionsgrenzen prüfen: Standard-Periodensystem Layout
// Row: 0-9 (Periode 1-10, aber 0-basiert indiziert)
// Column: 0-17 (Gruppe 1-18, aber 0-basiert indiziert)
if (element.Row < 0 || element.Row > 9 || element.Column < 0 || element.Column > 17)
{
Logger.Log($"Ungültige Position für {element.Symbol}: Row={element.Row}, Column={element.Column}");
return false;
}
return true;
}
/// <summary>
/// Führt eine vollständige Validierungsprüfung aller Elemente durch und protokolliert Fehler.
///
/// Diese Utility-Methode iteriert durch alle Elemente und prüft jedes einzeln.
/// Hauptzweck ist das Debugging und die Qualitätssicherung:
/// - Identifiziert problematische Elemente
/// - Protokolliert detaillierte Fehlermeldungen
/// - Hilfreich bei der Datenbereinigung
///
/// Besonderheiten:
/// - Verwendet null-conditional operator (?.) für sichere Navigation
/// - Null-coalescing operator (??) für Fallback-Werte
/// - Moderne C# Syntax für robuste Fehlerbehandlung
/// </summary>
public void LogValidationInfo()
{
// Iteriere durch alle Elemente und validiere jedes einzeln
foreach (var element in _elements)
{
// Prüfe Position für jedes Element
if (!ValidateElementPosition(element))
{
// element?.Symbol verwendet null-conditional operator
// Falls element null ist, wird Symbol nicht abgerufen -> kein Crash
// ?? "NULL" ist ein Fallback falls Symbol null/leer ist
Logger.Log($"VALIDIERUNGSFEHLER: {element?.Symbol ?? "NULL"}");
}
}
}
}
}