using System;
using System.Collections.Generic;
using System.Linq;
using Project_Periodensystem.Model;
namespace Project_Periodensystem.Controller
{
///
/// ElementStatistics - Spezialisierte Klasse für statistische Berechnungen und Datenanalyse
///
/// Diese Klasse wurde aus dem Haupt-Controller ausgelagert, um das Single Responsibility
/// Principle zu befolgen. Sie konzentriert sich ausschließlich auf:
///
/// - Mathematische Berechnungen (Durchschnitte, Extreme)
/// - Datengruppierung und -analyse (Serien, Kategorien)
/// - Informationsextraktion (Tuple-basierte Abfragen)
/// - Performance-optimierte LINQ-Operationen
///
/// Vorteile der Auslagerung:
/// - Bessere Testbarkeit einzelner Berechnungen
/// - Wiederverwendbarkeit der Statistik-Funktionen
/// - Klare Trennung von UI-Logik und Datenverarbeitung
/// - Einfache Erweiterung um neue Statistiken
///
public class ElementStatistics
{
///
/// Private, schreibgeschützte Liste aller Elemente für statistische Berechnungen.
/// Wird im Konstruktor gesetzt und bleibt danach unveränderlich (readonly).
/// Garantiert Datenintegrität während der gesamten Lebensdauer des Objekts.
///
private readonly List _elements;
///
/// Konstruktor der ElementStatistics-Klasse.
/// Initialisiert die Statistik-Engine mit einer Element-Sammlung.
///
/// Design-Prinzipien:
/// - Dependency Injection: Element-Liste wird von außen bereitgestellt
/// - Defensive Programmierung: Null-Safety durch Fallback
/// - Unveränderlichkeit: readonly field für Datensicherheit
///
/// Liste der Elemente für statistische Auswertungen (kann null sein)
public ElementStatistics(List elements)
{
// Null-Safety: Falls null übergeben wird, erstelle eine leere Liste
// Verhindert NullReferenceExceptions in allen nachfolgenden Methoden
_elements = elements ?? new List();
}
///
/// Extrahiert alle Atomgewichte als Array - demonstriert klassische Array-Erstellung
///
/// C# KONZEPTE:
/// - Array-Initialisierung: new double[size]
/// - For-Schleife: Imperative Programmierung
/// - Property-Zugriff: element.AtomicWeight
///
/// ALTERNATIVE (LINQ): return _elements.Select(e => e.AtomicWeight).ToArray();
/// Zeigt Unterschied zwischen imperativem und funktionalem Stil
///
/// Array aller Atomgewichte in g/mol
public double[] GetAtomicWeights()
{
double[] weights = new double[_elements.Count];
for (int i = 0; i < _elements.Count; i++)
{
weights[i] = _elements[i].AtomicWeight;
}
return weights;
}
///
/// Berechnet das durchschnittliche Atomgewicht aller Elemente
///
/// C# KONZEPTE:
/// - Early Return Pattern: if (!_elements.Any()) return 0.0;
/// - Method Reuse: Nutzt GetAtomicWeights()
/// - Klassische Iteration: for-Schleife für Summe
///
/// MATHEMATIK: Arithmetisches Mittel = Summe / Anzahl
///
/// Durchschnittliches Atomgewicht oder 0.0 bei leerer Liste
public double GetAverageAtomicWeight()
{
if (!_elements.Any()) return 0.0;
double[] weights = GetAtomicWeights();
double sum = 0;
for (int i = 0; i < weights.Length; i++)
{
sum += weights[i];
}
return sum / weights.Length;
}
///
/// Sammelt alle einzigartigen Element-Serien - demonstriert LINQ-Pipeline
///
/// C# KONZEPTE:
/// - LINQ Select(): Projektion (e => e.Series)
/// - LINQ Distinct(): Entfernt Duplikate
/// - LINQ Where(): Filtert leere/null Werte
/// - LINQ OrderBy(): Alphabetische Sortierung
/// - Method Chaining: Verkettung mehrerer Operationen
///
/// RÜCKGABE: Sortierte Liste aller chemischen Serien
///
/// Liste aller Element-Serien (Alkalimetall, Edelgas, etc.)
public List GetAllSeries()
{
return _elements.Select(e => e.Series) // Projektion
.Distinct() // Duplikate entfernen
.Where(s => !string.IsNullOrWhiteSpace(s)) // Null/Empty filtern
.OrderBy(s => s) // Alphabetisch sortieren
.ToList(); // Zu Liste konvertieren
}
///
/// Sammelt wichtige Statistiken in einem Tuple - demonstriert strukturierte Rückgaben
///
/// C# KONZEPTE:
/// - Tuple Return Type: (int, int, double)
/// - Method Delegation: Ruft andere Methoden auf
/// - Tuple Creation: (value1, value2, value3)
///
/// VERWENDUNG: var (total, series, avg) = statistics.GetStatistics();
///
/// Tuple mit (Anzahl Elemente, Anzahl Serien, Durchschnittsgewicht)
public (int totalElements, int uniqueSeries, double avgWeight) GetStatistics()
{
var seriesCount = GetAllSeries().Count;
var avgWeight = GetAverageAtomicWeight();
return (_elements.Count, seriesCount, avgWeight);
}
///
/// Findet das leichteste und schwerste Element - demonstriert LINQ Ordering
///
/// C# KONZEPTE:
/// - LINQ OrderBy() / OrderByDescending(): Sortierung
/// - LINQ First(): Erstes Element nach Sortierung
/// - Tuple mit nullable Types: (Element?, Element?)
/// - Guard Clause: Early return bei leerer Liste
///
/// CHEMIE: Wasserstoff ist leichtestes (1.008), schwerste variieren
///
/// Tuple mit (leichtestes Element, schwerstes Element) oder (null, null)
public (Element? lightest, Element? heaviest) GetWeightExtremes()
{
if (!_elements.Any()) return (null, null);
var lightest = _elements.OrderBy(e => e.AtomicWeight).First();
var heaviest = _elements.OrderByDescending(e => e.AtomicWeight).First();
return (lightest, heaviest);
}
///
/// Extrahiert Element-Informationen nach Ordnungszahl - demonstriert Tuple-basierte APIs
///
/// C# KONZEPTE:
/// - LINQ FirstOrDefault(): Sichere Suche (kann null zurückgeben)
/// - Conditional Operator: condition ? trueValue : falseValue
/// - Tuple mit Mixed Types: (string, string, double)
///
/// FALLBACK: Bei nicht gefundenem Element ("?", "Unknown", 0.0)
///
/// Ordnungszahl des gesuchten Elements (1-118)
/// Tuple mit (Symbol, Name, Atomgewicht)
public (string symbol, string name, double weight) GetElementInfo(int atomicNumber)
{
var element = _elements.FirstOrDefault(e => e.AtomicNumber == atomicNumber);
return element != null
? (element.Symbol, element.ElementName, element.AtomicWeight)
: ("?", "Unknown", 0.0);
}
///
/// Ermittelt die Position eines Elements im Periodensystem-Grid
///
/// C# KONZEPTE:
/// - Konsistente API: Gleiche Suchmuster wie GetElementInfo()
/// - Tuple für Koordinaten: (int row, int column)
/// - Fallback-Werte: (-1, -1) für "nicht gefunden"
///
/// VERWENDUNG: var (row, col) = statistics.GetElementPosition(1); // Wasserstoff
///
/// Ordnungszahl des gesuchten Elements
/// Tuple mit (Zeile, Spalte) oder (-1, -1) wenn nicht gefunden
public (int row, int column) GetElementPosition(int atomicNumber)
{
var element = _elements.FirstOrDefault(e => e.AtomicNumber == atomicNumber);
return element != null ? (element.Row, element.Column) : (-1, -1);
}
}
}