using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using PolyTrader.Core.Modularity;
namespace PolyTraderSharp.Ui
{
///
/// Verwaltet die registrierten Fenster-Views: öffnet sie als eigenständige Forms,
/// hält je View höchstens eine Instanz offen und holt ein bereits offenes Fenster
/// wieder in den Vordergrund. Meldet Änderungen am Offen-Status (für die
/// Button-Markierung im Launcher).
///
public class ShellUiHost : IModuleUiHost
{
private readonly List _views = new();
private readonly Dictionary _open = new();
private Form? _mainWindow;
private bool _shutdownDialogOpen;
///
/// True, sobald das Herunterfahren über die Sicherheitsabfrage bestätigt wurde. Der Launcher
/// wertet das in FormClosing aus, um beim Schließen-X denselben Dialog zu erzwingen.
///
public bool ShutdownConfirmed { get; private set; }
/// Wird ausgelöst, wenn sich der Offen-Status irgendeiner View ändert.
public event Action? OpenStateChanged;
public IReadOnlyList Views => _views;
public void RegisterView(ModuleView view) => _views.Add(view);
/// Setzt das Hauptfenster (Launcher) – Ziel für .
public void SetMainWindow(Form main) => _mainWindow = main;
///
/// Fügt einem Fenster die gemeinsame Fenster-Menüleiste hinzu (oberste Leiste, alle Fenster
/// nebeneinander mit Icon). Als letztes hinzugefügtes Top-Control belegt der MenuStrip die
/// oberste Zeile über etwaigen ToolStrips.
///
private void AttachWindowMenu(Form form, string currentViewId)
{
var menu = new MenuStrip { Dock = DockStyle.Top, ImageScalingSize = new System.Drawing.Size(24, 24) };
WindowMenu.Wire(menu, this, currentViewId);
form.Controls.Add(menu);
form.MainMenuStrip = menu;
}
public void ActivateMain()
{
if (_mainWindow == null || _mainWindow.IsDisposed) return;
if (_mainWindow.WindowState == FormWindowState.Minimized)
_mainWindow.WindowState = FormWindowState.Maximized;
_mainWindow.BringToFront();
_mainWindow.Activate();
}
public bool IsOpen(string viewId) =>
_open.TryGetValue(viewId, out var form) && !form.IsDisposed;
///
/// Zeigt die Sicherheitsabfrage (Timer-gesperrter Beenden-Button, Abbrechen jederzeit). Bei
/// Bestätigung wird die Message-Loop beendet – das geordnete Herunterfahren der Module läuft
/// anschließend in Program.Main über AppHost.StopAsync() (nach Application.Run).
/// Aus jedem Fenster aufrufbar; der Dialog erscheint zentriert über dem Hauptfenster.
///
public void RequestShutdown()
{
if (ShutdownConfirmed || _shutdownDialogOpen) return;
_shutdownDialogOpen = true;
try
{
using var dlg = new ShutdownConfirmDialog();
var owner = _mainWindow != null && !_mainWindow.IsDisposed ? _mainWindow : null;
var result = owner != null ? dlg.ShowDialog(owner) : dlg.ShowDialog();
if (result != DialogResult.OK) return;
ShutdownConfirmed = true;
Application.Exit(); // beendet die Message-Loop; StopAsync() fährt Module danach sauber herunter
}
finally
{
_shutdownDialogOpen = false;
}
}
public void OpenView(string viewId)
{
var view = _views.FirstOrDefault(v => v.Id == viewId);
if (view != null) OpenView(view);
}
public void OpenView(ModuleView view)
{
if (_open.TryGetValue(view.Id, out var existing) && !existing.IsDisposed)
{
if (existing.WindowState == FormWindowState.Minimized)
existing.WindowState = FormWindowState.Normal;
existing.BringToFront();
existing.Activate();
return;
}
// CreateView liefert bewusst object (toolkit-neutraler Core-Contract). Die WinForms-Shell
// kennt ihr Toolkit und castet hier; ein falscher Typ ist ein Programmierfehler und soll
// laut knallen, nicht still ein leeres Fenster erzeugen.
var form = (Form)view.CreateView();
if (string.IsNullOrEmpty(form.Text) || form.Text == form.Name)
form.Text = view.Title;
// Gemeinsames „Fenster"-Menü zentral in jedes Fenster injizieren (identische Shell-Chrome
// auf allen Fenstern; die inhaltlichen Controls bleiben designerbasiert). Nur, wenn das
// Fenster nicht bereits ein eigenes Menü mitbringt (z. B. der Launcher).
if (form.MainMenuStrip == null)
AttachWindowMenu(form, view.Id);
// Alle Fenster maximiert (Vorgabe): Full-HD-Ziel, skaliert auf größere Auflösungen.
form.StartPosition = FormStartPosition.CenterScreen;
form.WindowState = FormWindowState.Maximized;
_open[view.Id] = form;
form.FormClosed += (_, _) =>
{
_open.Remove(view.Id);
OpenStateChanged?.Invoke();
};
form.Show();
OpenStateChanged?.Invoke();
}
}
}