Files
BCSH1-TournamentApp/TournamentOrganizer/ViewModels/TeamsViewModel.cs
T

564 lines
15 KiB
C#

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.EntityFrameworkCore;
using TournamentOrganizer.Models;
namespace TournamentOrganizer.ViewModels;
public partial class TeamsViewModel : ViewModelBase
{
private readonly TournamentContext _context;
[ObservableProperty]
private ObservableCollection<TeamDisplay> _teams = [];
[ObservableProperty]
private TeamDisplay? _selectedTeam;
[ObservableProperty]
private string _teamName = string.Empty;
[ObservableProperty]
private ObservableCollection<PlayerEntry> _players = [];
[ObservableProperty]
private PlayerEntry? _selectedPlayer;
[ObservableProperty]
private PlayerEntry? _selectedLeader;
[ObservableProperty]
private string _newPlayerName = string.Empty;
[ObservableProperty]
private string _newPlayerContact = string.Empty;
[ObservableProperty]
private string _filterMemberName = string.Empty;
[ObservableProperty]
private string? _selectedEventFilter;
[ObservableProperty]
private string? _selectedTournamentFilter;
[ObservableProperty]
private ObservableCollection<string> _availableEvents = [];
[ObservableProperty]
private ObservableCollection<string> _availableTournaments = [];
[ObservableProperty]
private string _eventFilterSearch = string.Empty;
[ObservableProperty]
private string _tournamentFilterSearch = string.Empty;
[ObservableProperty]
private bool _isEventDropdownOpen;
[ObservableProperty]
private bool _isTournamentDropdownOpen;
[ObservableProperty]
private bool _isEditing;
[ObservableProperty]
private string _statusMessage = string.Empty;
private readonly ObservableCollection<string> _filteredEvents = [];
public ObservableCollection<string> FilteredEvents => _filteredEvents;
private readonly ObservableCollection<string> _filteredTournaments = [];
public ObservableCollection<string> FilteredTournaments => _filteredTournaments;
partial void OnEventFilterSearchChanged(string value) => UpdateFilteredEvents();
partial void OnTournamentFilterSearchChanged(string value) => UpdateFilteredTournaments();
private void UpdateFilteredEvents()
{
_filteredEvents.Clear();
foreach (var e in AvailableEvents.Where(e => string.IsNullOrWhiteSpace(EventFilterSearch) || e.ToLower().Contains(EventFilterSearch.ToLower())))
{
_filteredEvents.Add(e);
}
}
private void UpdateFilteredTournaments()
{
_filteredTournaments.Clear();
foreach (var t in AvailableTournaments.Where(t => string.IsNullOrWhiteSpace(TournamentFilterSearch) || t.ToLower().Contains(TournamentFilterSearch.ToLower())))
{
_filteredTournaments.Add(t);
}
}
public TeamsViewModel()
{
_context = new TournamentContext();
}
public async Task LoadTeams()
{
var events = await _context.Events.ToListAsync();
AvailableEvents.Clear();
foreach (var e in events)
{
AvailableEvents.Add(e.Name);
}
UpdateFilteredEvents();
var games = await _context.Games.ToListAsync();
AvailableTournaments.Clear();
foreach (var g in games)
{
foreach (var e in events)
{
AvailableTournaments.Add($"{g.Name} @ {e.Name}");
}
}
UpdateFilteredTournaments();
var query = _context.Teams
.Include(t => t.Players)
.Include(t => t.Leader)
.Include(t => t.Matches)
.ThenInclude(tp => tp.Round)
.ThenInclude(m => m.Tournament)
.ThenInclude(t => t.Event)
.AsSplitQuery();
var allTeams = await query.ToListAsync();
var filtered = allTeams.AsEnumerable();
if (!string.IsNullOrWhiteSpace(FilterMemberName))
{
var filter = FilterMemberName.ToLower();
filtered = filtered.Where(t => t.Players.Any(p => p.Name.ToLower().Contains(filter)));
}
if (!string.IsNullOrWhiteSpace(SelectedEventFilter))
{
var filter = SelectedEventFilter.ToLower();
filtered = filtered.Where(t => GetAssociatedEvents(t).Any(e => e.ToLower().Contains(filter)));
}
if (!string.IsNullOrWhiteSpace(SelectedTournamentFilter))
{
var filter = SelectedTournamentFilter.ToLower();
filtered = filtered.Where(t => GetAssociatedTournaments(t).Any(tn => tn.ToLower().Contains(filter)));
}
Teams.Clear();
foreach (var team in filtered)
{
Teams.Add(new TeamDisplay(team));
}
SelectedTeam = null;
IsEditing = false;
}
public void SelectEventFilter(string eventName)
{
SelectedEventFilter = eventName;
IsEventDropdownOpen = false;
EventFilterSearch = string.Empty;
_ = LoadTeams();
}
public void ClearEventFilter()
{
SelectedEventFilter = null;
EventFilterSearch = string.Empty;
_ = LoadTeams();
}
public void SelectTournamentFilter(string tournamentName)
{
SelectedTournamentFilter = tournamentName;
IsTournamentDropdownOpen = false;
TournamentFilterSearch = string.Empty;
_ = LoadTeams();
}
public void ClearTournamentFilter()
{
SelectedTournamentFilter = null;
TournamentFilterSearch = string.Empty;
_ = LoadTeams();
}
[RelayCommand]
private async Task RefreshTeams()
{
await LoadTeams();
}
[RelayCommand]
private void CreateNewTeam()
{
TeamName = "New Team";
Players.Clear();
SelectedLeader = null;
SelectedPlayer = null;
IsEditing = true;
SelectedTeam = null;
NewPlayerName = string.Empty;
NewPlayerContact = string.Empty;
StatusMessage = "Creating new team";
}
[RelayCommand]
private async Task SaveTeam()
{
if (string.IsNullOrWhiteSpace(TeamName))
{
StatusMessage = "Team name is required";
return;
}
if (Players.Count == 0)
{
StatusMessage = "Team must have at least one member";
return;
}
Team? team;
if (SelectedTeam != null && SelectedTeam.Id > 0)
{
team = await _context.Teams
.Include(t => t.Players)
.FirstOrDefaultAsync(t => t.Id == SelectedTeam.Id);
if (team == null)
{
StatusMessage = "Team not found";
return;
}
team.Name = TeamName;
var existingPlayerIds = team.Players.Select(p => p.Id).ToHashSet();
var currentPlayerIds = Players.Where(p => p.Id > 0).Select(p => p.Id).ToHashSet();
var playersToRemove = team.Players.Where(p => !currentPlayerIds.Contains(p.Id)).ToList();
foreach (var player in playersToRemove)
{
team.Players.Remove(player);
_context.Players.Remove(player);
}
foreach (var entry in Players)
{
if (entry.Id > 0)
{
var existing = team.Players.FirstOrDefault(p => p.Id == entry.Id);
if (existing != null)
{
existing.Name = entry.Name;
existing.Contact = entry.Contact;
}
}
else
{
var newPlayer = new Player
{
Name = entry.Name,
Contact = entry.Contact,
Team = team
};
team.Players.Add(newPlayer);
entry.Id = newPlayer.Id;
}
}
if (SelectedLeader != null)
{
var leader = team.Players.FirstOrDefault(p =>
(SelectedLeader.Id > 0 && p.Id == SelectedLeader.Id) ||
(SelectedLeader.Id == 0 && p.Name == SelectedLeader.Name && p.Contact == SelectedLeader.Contact));
team.Leader = leader;
}
else
{
team.Leader = null;
}
}
else
{
team = new Team
{
Name = TeamName,
Players = [],
Matches = []
};
var playerEntries = new List<(PlayerEntry Entry, Player Player)>();
foreach (var entry in Players)
{
var player = new Player
{
Name = entry.Name,
Contact = entry.Contact,
Team = team
};
team.Players.Add(player);
playerEntries.Add((entry, player));
}
_context.Teams.Add(team);
await _context.SaveChangesAsync();
if (team.Players.Count > 0)
{
int leaderIndex = 0;
if (SelectedLeader != null)
{
var idx = Players.IndexOf(SelectedLeader);
if (idx >= 0) leaderIndex = idx;
}
team.LeaderId = playerEntries[leaderIndex].Player.Id;
await _context.SaveChangesAsync();
}
}
await _context.SaveChangesAsync();
StatusMessage = $"Team '{TeamName}' saved successfully";
await LoadTeams();
}
[RelayCommand]
private async Task DeleteTeam()
{
if (SelectedTeam == null || SelectedTeam.Id == 0)
{
StatusMessage = "Select a team to delete";
return;
}
var team = await _context.Teams
.Include(t => t.Players)
.FirstOrDefaultAsync(t => t.Id == SelectedTeam.Id);
if (team == null)
{
StatusMessage = "Team not found";
return;
}
_context.Teams.Remove(team);
await _context.SaveChangesAsync();
StatusMessage = $"Team '{team.Name}' deleted";
await LoadTeams();
}
[RelayCommand]
private void AddPlayer()
{
if (string.IsNullOrWhiteSpace(NewPlayerName))
{
StatusMessage = "Player name is required";
return;
}
var entry = new PlayerEntry
{
Name = NewPlayerName,
Contact = NewPlayerContact
};
Players.Add(entry);
if (SelectedLeader == null)
{
SelectedLeader = entry;
}
NewPlayerName = string.Empty;
NewPlayerContact = string.Empty;
StatusMessage = $"Player '{entry.Name}' added";
}
[RelayCommand]
private void RemovePlayer()
{
if (SelectedPlayer == null)
{
StatusMessage = "Select a player to remove";
return;
}
var wasLeader = SelectedLeader == SelectedPlayer;
Players.Remove(SelectedPlayer);
if (wasLeader)
{
SelectedLeader = Players.FirstOrDefault();
}
SelectedPlayer = null;
StatusMessage = "Player removed";
}
[RelayCommand]
private void SetLeader()
{
if (SelectedPlayer == null)
{
StatusMessage = "Select a player to make leader";
return;
}
SelectedLeader = SelectedPlayer;
StatusMessage = $"{SelectedPlayer.Name} is now the leader";
}
partial void OnSelectedTeamChanged(TeamDisplay? value)
{
if (value == null)
{
IsEditing = false;
return;
}
TeamName = value.Name;
Players.Clear();
foreach (var player in value.Players)
{
Players.Add(player);
}
SelectedLeader = Players.FirstOrDefault(p => p.Id == value.LeaderId);
SelectedPlayer = null;
IsEditing = true;
NewPlayerName = string.Empty;
NewPlayerContact = string.Empty;
StatusMessage = $"Editing team '{value.Name}'";
}
partial void OnFilterMemberNameChanged(string value) => ApplyFilters();
private async void ApplyFilters()
{
await LoadTeams();
}
private static List<string> GetAssociatedEvents(Team team)
{
var events = new List<string>();
if (team.Matches != null)
{
foreach (var tp in team.Matches)
{
if (tp.Round?.Tournament?.Event != null)
{
var eventName = tp.Round.Tournament.Event.Name;
if (!events.Contains(eventName))
{
events.Add(eventName);
}
}
}
}
return events;
}
private static List<string> GetAssociatedTournaments(Team team)
{
var tournaments = new List<string>();
if (team.Matches != null)
{
foreach (var tp in team.Matches)
{
if (tp.Round?.Tournament != null)
{
var tournamentName = GetTournamentDisplayName(tp.Round.Tournament);
if (!tournaments.Contains(tournamentName))
{
tournaments.Add(tournamentName);
}
}
}
}
return tournaments;
}
public static string GetTournamentDisplayName(Tournament tournament)
{
return $"{tournament.Game.Name} @ {tournament.Event.Name}";
}
}
public class TeamDisplay
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public int? LeaderId { get; set; }
public string? LeaderName { get; set; }
public List<PlayerEntry> Players { get; set; } = [];
public List<string> AssociatedEvents { get; set; } = [];
public List<string> AssociatedTournaments { get; set; } = [];
public TeamDisplay() { }
public TeamDisplay(Team team)
{
Id = team.Id;
Name = team.Name;
LeaderId = team.LeaderId;
LeaderName = team.Leader?.Name;
Players = team.Players?.Select(p => new PlayerEntry(p)).ToList() ?? [];
var events = new HashSet<string>();
var tournaments = new HashSet<string>();
if (team.Matches != null)
{
foreach (var tp in team.Matches)
{
if (tp.Round?.Tournament != null)
{
tournaments.Add(TeamsViewModel.GetTournamentDisplayName(tp.Round.Tournament));
if (tp.Round.Tournament.Event != null)
{
events.Add(tp.Round.Tournament.Event.Name);
}
}
}
}
AssociatedEvents = events.ToList();
AssociatedTournaments = tournaments.ToList();
}
}
public partial class PlayerEntry : ObservableObject
{
[ObservableProperty]
private int _id;
[ObservableProperty]
private string _name = string.Empty;
[ObservableProperty]
private string _contact = string.Empty;
public PlayerEntry() { }
public PlayerEntry(Player player)
{
Id = player.Id;
Name = player.Name;
Contact = player.Contact;
}
}