using Avalonia.Controls; using Nonemm.Contests; using Nonemm.Core; namespace Nonemm.App.Windows; /// Contacts, points and multipliers band by band. public sealed partial class ScoreWindow : RefreshableWindow { private readonly AppSession session; private int columnCount = 4; public ScoreWindow(AppSession session) { this.session = session; InitializeComponent(); Refresh(); } public override void Refresh() { Table.Children.Clear(); Table.ColumnDefinitions.Clear(); Table.RowDefinitions.Clear(); if (session.Logging is null) { TotalText.Text = "no contest is open"; return; } // the log keeps the same split N1MM's score window shows, so the band // rows carry the weighted multipliers and leave out what is not in the // claimed score List> lines = session.Logging.Log.Rows .OrderBy(r => Bands.Named(r.Key.Band)?.MegahertzLabel ?? double.MaxValue) .ThenBy(r => r.Key.Kind, StringComparer.Ordinal) .ToList(); bool hasKinds = session.Logging.Contest.HasQtcTraffic; columnCount = hasKinds ? 5 : 4; for (int column = 0; column < columnCount; column++) { Table.ColumnDefinitions.Add(new ColumnDefinition(GridLength.Star)); } AddRow(0, "Band", "Q/QTC", "QSOs", "Points", "Mults", header: true); int row = 1; foreach ((ScoreKey key, ScoreTally line) in lines) { AddRow( row++, key.Band, key.Kind, line.Qsos.ToString(), line.Points.ToString(), line.TotalMultipliers.ToString()); } AddRow( row, "Total", hasKinds ? "All" : "", session.Logging.Log.Tally.Qsos.ToString(), session.Logging.Log.Tally.Points.ToString(), session.Logging.Log.Tally.TotalMultipliers.ToString(), header: true); TimeSpan on = OperatingTime.On( session.Logging.Log.Qsos, session.Logging.Contest.MinimumOffTime); TimeSpan off = OperatingTime.Off( session.Logging.Log.Qsos, session.Logging.Contest.MinimumOffTime); TotalText.Text = $"Claimed score {session.Logging.Log.TotalScore:N0}" + $" on {Hours(on)} off {Hours(off)}" + BandChanges(); } /// The band changes made and the allowance, for a contest that limits /// them, and nothing at all for the contests that do not. private string BandChanges() { BandChangeRules rules = session.Logging!.Contest.BandChangesFor(session.Logging.Log.Entry); return rules.IsCounted ? $" band changes {rules.CountedIn(session.Logging.Log.Qsos, DateTime.UtcNow)}/{rules.Max}" : ""; } /// Hours and minutes, which is how a sponsor asks for operating time. private static string Hours(TimeSpan time) => $"{(int)time.TotalHours}:{time.Minutes:00}"; private void AddRow( int row, string band, string kind, string qsos, string points, string mults, bool header = false) { Table.RowDefinitions.Add(new RowDefinition(GridLength.Auto)); string[] cells = columnCount == 5 ? [band, kind, qsos, points, mults] : [band, qsos, points, mults]; for (int column = 0; column < cells.Length; column++) { TextBlock text = new() { Text = cells[column], FontFamily = new Avalonia.Media.FontFamily("monospace"), FontSize = 13, Opacity = header ? 1.0 : 0.85, Margin = new Avalonia.Thickness(0, 2, 8, 2), }; Grid.SetRow(text, row); Grid.SetColumn(text, column); Table.Children.Add(text); } } }