using System; using System.Collections.Generic; using System.Linq; using Project_Periodensystem.Model; using Project_Periodensystem.Persistence; namespace Project_Periodensystem.Controller { /// /// Controller für das Periodensystem - verwaltet die Geschäftslogik /// und trennt View von Model gemäß MVC-Pattern /// public class PeriodensystemController { // Nullable Field um Warning zu vermeiden private List _elements = new List(); /// /// Konstruktor - initialisiert den Controller /// public PeriodensystemController() { LoadElements(); } /// /// Lädt alle Elemente über den Persistence-Layer (JETZT MIT DATAMANAGER!) /// private void LoadElements() { try { // NEUE METHODE: DataManager statt direkt PeriodicTableData _elements = DataManager.LoadElements(); Logger.Log($"Controller: {_elements.Count} Elemente erfolgreich geladen (via DataManager)"); // NEUE FEATURES demonstrieren: // Array-Operationen testen var symbols = GetAllSymbols(); Logger.LogArray("Element-Symbole (erste 10)", symbols.Take(10).ToArray()); // Tuple-Operationen testen var (totalElements, uniqueSeries, avgWeight) = GetStatistics(); Logger.LogTuple("Statistiken", $"Elemente: {totalElements}, Serien: {uniqueSeries}, Ø-Gewicht: {avgWeight:F2}"); // Extremwerte finden var (lightest, heaviest) = GetWeightExtremes(); if (lightest != null && heaviest != null) { Logger.LogTuple("Gewichts-Extreme", $"Leichtestes: {lightest.Symbol} ({lightest.AtomicWeight}), Schwerstes: {heaviest.Symbol} ({heaviest.AtomicWeight})"); } } catch (Exception ex) { Logger.Log($"EXCEPTION in LoadElements: {ex.Message}"); _elements = new List(); } } /// /// Gibt alle verfügbaren Elemente zurück /// /// Liste aller Elemente public List GetAllElements() { return _elements; } /// /// Gibt Elemente als Array zurück (für Array-Operationen) /// /// Array aller Elemente public Element[] GetAllElementsAsArray() { return _elements.ToArray(); } /// /// Gibt nur die Symbole als String-Array zurück /// /// Array mit allen Element-Symbolen public string[] GetAllSymbols() { string[] symbols = new string[_elements.Count]; for (int i = 0; i < _elements.Count; i++) { symbols[i] = _elements[i].Symbol; } return symbols; } /// /// Gibt Atomgewichte als Array zurück /// /// Array mit allen Atomgewichten 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 Durchschnittsgewicht aus Array /// /// Durchschnittliches Atomgewicht public double GetAverageAtomicWeight() { double[] weights = GetAtomicWeights(); if (weights.Length == 0) return 0; double sum = 0; for (int i = 0; i < weights.Length; i++) { sum += weights[i]; } return sum / weights.Length; } /// /// Speichert Elemente persistent (NEUE FUNKTION) /// public void SaveElements() { try { DataManager.SaveElements(_elements); Logger.Log("Elemente erfolgreich gespeichert"); } catch (Exception ex) { Logger.LogException(ex, "SaveElements"); } } /// /// Sucht ein Element nach Atomnummer /// /// Atomnummer des gesuchten Elements /// Element oder null wenn nicht gefunden public Element? GetElementByAtomicNumber(int atomicNumber) { if (atomicNumber <= 0) { Logger.Log($"Ungültige Atomnummer: {atomicNumber}"); return null; } return _elements.FirstOrDefault(e => e.AtomicNumber == atomicNumber); } /// /// Sucht ein Element nach Symbol /// /// Symbol des gesuchten Elements /// Element oder null wenn nicht gefunden public Element? GetElementBySymbol(string symbol) { if (string.IsNullOrWhiteSpace(symbol)) { Logger.Log("Leeres Symbol übergeben"); return null; } return _elements.FirstOrDefault(e => string.Equals(e.Symbol, symbol, StringComparison.OrdinalIgnoreCase)); } /// /// Filtert Elemente nach Serie /// /// Gewünschte Elementserie /// Liste der Elemente der angegebenen Serie public List GetElementsBySeries(string series) { if (string.IsNullOrWhiteSpace(series)) { return new List(); } return _elements.Where(e => string.Equals(e.Series, series, StringComparison.OrdinalIgnoreCase)) .ToList(); } /// /// Validiert Grid-Position eines Elements /// /// Zu validierendes Element /// True wenn Position gültig ist public bool ValidateElementPosition(Element element) { if (element == null) { Logger.Log("Null-Element kann nicht validiert werden"); return false; } // Periodensystem hat 7 Perioden (0-6) und 18 Gruppen (0-17) // Plus Lanthanoid/Actinoid-Reihen bei Zeile 8 und 9 bool validRow = element.Row >= 0 && element.Row <= 9; bool validColumn = element.Column >= 0 && element.Column <= 17; if (!validRow || !validColumn) { Logger.Log($"Ungültige Position für {element.Symbol}: ({element.Row},{element.Column})"); return false; } return true; } /// /// Gibt alle verfügbaren Element-Serien zurück /// /// Liste aller Serien public List GetAllSeries() { return _elements.Select(e => e.Series) .Distinct() .Where(s => !string.IsNullOrWhiteSpace(s)) .OrderBy(s => s) .ToList(); } /// /// Überprüft ob alle Elemente korrekt geladen wurden /// /// True wenn Daten vollständig sind public bool ValidateData() { if (_elements.Count == 0) { Logger.Log("Keine Elemente geladen"); return false; } // Überprüfe auf Duplikate bei Atomnummern var duplicateNumbers = _elements.GroupBy(e => e.AtomicNumber) .Where(g => g.Count() > 1) .Select(g => g.Key); if (duplicateNumbers.Any()) { Logger.Log($"Doppelte Atomnummern gefunden: {string.Join(", ", duplicateNumbers)}"); return false; } // Überprüfe auf leere Symbole var emptySymbols = _elements.Where(e => string.IsNullOrWhiteSpace(e.Symbol)); if (emptySymbols.Any()) { Logger.Log("Elemente mit leeren Symbolen gefunden"); return false; } Logger.Log($"Datenvalidierung erfolgreich - {_elements.Count} Elemente validiert"); return true; } /// /// Lädt Daten neu (für Refresh-Funktionalität) /// public void RefreshData() { Logger.Log("Daten werden neu geladen..."); LoadElements(); } /// /// Gibt die Anzahl der geladenen Elemente zurück /// /// Anzahl der Elemente public int GetElementCount() { return _elements.Count; } /// /// Gibt Element-Position als Tuple zurück /// /// Atomnummer des Elements /// Tuple mit (Row, Column) oder (-1, -1) wenn nicht gefunden public (int row, int column) GetElementPosition(int atomicNumber) { var element = GetElementByAtomicNumber(atomicNumber); if (element != null) { return (element.Row, element.Column); } return (-1, -1); } /// /// Gibt Grundinfos eines Elements als Tuple zurück /// /// Atomnummer /// Tuple mit (Symbol, Name, Gewicht) public (string symbol, string name, double weight) GetElementInfo(int atomicNumber) { var element = GetElementByAtomicNumber(atomicNumber); if (element != null) { return (element.Symbol, element.ElementName, element.AtomicWeight); } return ("", "Unbekannt", 0.0); } /// /// Gibt Statistiken als Tuple zurück /// /// 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 leichtestes und schwerstes Element /// /// Tuple mit (leichtestes Element, schwerstes Element) oder null-Werte wenn keine Elemente public (Element? lightest, Element? heaviest) GetWeightExtremes() { if (!_elements.Any()) { return (null, null); } var lightest = _elements[0]; var heaviest = _elements[0]; foreach (var element in _elements) { if (element.AtomicWeight < lightest.AtomicWeight) lightest = element; if (element.AtomicWeight > heaviest.AtomicWeight) heaviest = element; } return (lightest, heaviest); } } }