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)
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);
}
}
}