import {Component, inject, Input, OnDestroy, OnInit} from '@angular/core'; import { MatAccordion, MatExpansionPanel, MatExpansionPanelHeader, MatExpansionPanelTitle } from "@angular/material/expansion"; import {MatCard, MatCardContent, MatCardHeader} from "@angular/material/card"; import {CurrencyPipe, DatePipe, DecimalPipe, NgClass} from "@angular/common"; import {TeamPipe} from "../../pipes/team-pipe"; import {TournamentService} from "../../service/tournament.service"; import {ActivatedRoute, Router} from "@angular/router"; import {Tournament} from "../../model/tournament"; import {FullNamePipe} from "../../pipes/fullname-pipe"; import {MatButton, MatIconButton} from "@angular/material/button"; import {MatIcon} from "@angular/material/icon"; import {Group} from "../../model/group"; import {Round} from "../../model/round"; import {MatMenu, MatMenuContent, MatMenuItem, MatMenuTrigger} from "@angular/material/menu"; import {Match} from "../../model/match"; import {FormsModule} from "@angular/forms"; import {MatTab, MatTabChangeEvent, MatTabGroup, MatTabLabel} from "@angular/material/tabs"; import {MatchResultComponent} from "../match-result/match-result.component"; import {MatDialog} from "@angular/material/dialog"; import {MatchResultPipe} from "../../pipes/match-result-pipe"; import {Event} from "../../model/event"; import {TournamentValidateComponent} from "../tournament-validate/tournament-validate.component"; import {Strength} from "../../model/player"; import {MatSlideToggle, MatSlideToggleChange} from "@angular/material/slide-toggle"; import {MatSnackBar} from "@angular/material/snack-bar"; import {CourtSelectionComponent} from "../court-selection/court-selection.component"; import {Standings} from "../../model/standings"; import {Title} from '@angular/platform-browser'; import {HeaderService} from "../../service/header.service"; @Component({ selector: 'app-tournament-manage', imports: [ FullNamePipe, MatAccordion, MatCard, MatCardContent, MatCardHeader, MatExpansionPanel, MatExpansionPanelHeader, MatExpansionPanelTitle, TeamPipe, MatIcon, NgClass, MatMenu, MatMenuItem, MatMenuTrigger, FormsModule, DatePipe, MatTabGroup, MatTab, MatTabLabel, MatButton, MatIconButton, DecimalPipe, TournamentValidateComponent, MatSlideToggle, CurrencyPipe, MatMenuContent ], providers: [ FullNamePipe, TeamPipe, MatchResultPipe ], templateUrl: './tournament-manage.component.html', styleUrl: './tournament-manage.component.scss' }) export class TournamentManageComponent implements OnInit, OnDestroy { @Input() tournament: Tournament; activeRoundTab: number = 0; constructor( private tournamentService: TournamentService, private _snackBar: MatSnackBar, private route: ActivatedRoute, private router: Router, private headerService: HeaderService, ) { } ngOnInit() { const id = this.route.snapshot.paramMap.get('id'); this.route.queryParams.subscribe(params => { if (params['tab']) { this.activeRoundTab = params['tab']; } }) this.tournamentService.getById(Number(id)).subscribe(data => { this.tournament = data; this.headerService.setTitle(this.tournament.name); }); } ngOnDestroy() { this.headerService.clearTitle(); } onRoundTabChange(event: MatTabChangeEvent) { const index = event.index; this.router.navigate( ['tournaments/' + this.tournament.id + '/manage'], { relativeTo: null, queryParams: {tab: index} }); } getRoundIcon(status: String) { if (status == "FINISHED") { return "check"; } else if (status == "IN_PROGRESS") { return "play_arrow"; } else if (status == "NOT_STARTED") { return "hourglass_top"; } else { return "warning"; } } getStandingsForRound(round: Round, group: Group): Standings { if (round.status == 'FINISHED') { return round.standings; } else { return group.standings; } } groupIsDoublesType(group: Group) { return group.type == 'HD' || group.type == 'DD' || group.type == 'GD'; } startRound(round: Round) { this.tournamentService.startRound(this.tournament.id, round.id).subscribe(data => { this.tournament = data; }); } finishRound(round: Round) { this.tournamentService.finishRound(this.tournament.id, round.id).subscribe(data => { this.tournament = data; }); } finishGroup(group: Group) { this.tournamentService.finishGroup(this.tournament.id, group.id).subscribe(data => { this.tournament = data; }); } reopenGroup(group: Group) { this.tournamentService.reopenGroup(this.tournament.id, group.id).subscribe(data => { this.tournament = data; }); } divideTournament() { this.tournamentService.divide(this.tournament.id).subscribe(data => { this.tournament = data; }); } clearDivision() { this.tournamentService.clearDivision(this.tournament.id).subscribe(data => { this.tournament = data; }); } drawTournament() { this.tournamentService.draw(this.tournament.id).subscribe(data => { this.tournament = data; }); } startMatch(match: Match) { const availableCourts = this.getAvailableCourts(); if (availableCourts.length == 0) { alert('Geen banen beschikbaar!'); } else if (this.matchContainsPlayersThatArePlaying(match)) { alert('Deze wedstrijd bevat spelers die al aan het spelen zijn!'); } else { this.courtSelectionDialog.open(CourtSelectionComponent, { data: { match: match, availableCourts: this.getAvailableCourts(), totalCourts: this.tournament.courts }, minWidth: '800px', minHeight: '250px' }).afterClosed().subscribe(result => { if (result != undefined) { this.tournamentService.startMatch(this.tournament.id, match.id, result).subscribe(data => { this.tournament = data; }) } }); } } matchContainsPlayersThatArePlaying(match: Match): boolean { let activePlayers: number[] = []; for (let activeMatch of this.activeMatches()) { activePlayers.push(activeMatch.match.team1.player1.id); if (activeMatch.match.team1.player2) activePlayers.push(activeMatch.match.team1.player2.id); activePlayers.push(activeMatch.match.team2.player1.id); if (activeMatch.match.team2.player2) activePlayers.push(activeMatch.match.team2.player2.id); } let matchPlayers: number[] = []; matchPlayers.push(match.team1.player1.id); if (match.team1.player2) matchPlayers.push(match.team1.player2.id); matchPlayers.push(match.team2.player1.id); if (match.team2.player2) matchPlayers.push(match.team2.player2.id); let playersThatArePlaying = activePlayers.filter(Set.prototype.has, new Set(matchPlayers)); return playersThatArePlaying.length > 0; } getAvailableCourts(): number[] { const maxCourts = this.tournament.courts; const activeCourts = this.activeMatches().map(activeMatch => activeMatch.match.court); let i = 0, courts = Array(maxCourts); while (i < maxCourts) courts[i++] = i; return courts.filter(court => activeCourts.indexOf(court) < 0); } stopMatch(match: Match) { this.tournamentService.stopMatch(this.tournament.id, match.id).subscribe(data => { this.tournament = data; }) } newRound(group: Group) { this.tournamentService.newRound(this.tournament.id, group.id).subscribe(data => { this.tournament = data; }) } playerPaid($event: MatSlideToggleChange, playerId: number) { this.tournamentService.playerPaid(this.tournament.id, playerId, $event.checked).subscribe(() => { this._snackBar.open('Opgeslagen.'); }); } playerPresent($event: MatSlideToggleChange, playerId: number) { this.tournamentService.playerPresent(this.tournament.id, playerId, $event.checked).subscribe(() => { this._snackBar.open('Opgeslagen.'); }); } getStrength(strength: string | undefined) { if (strength == undefined) return ""; for (let [key, value] of Object.entries(Strength)) { if (key == strength) return value; } return ""; } printMatchSheets(round: Round) { window.open(`tournaments/${this.tournament.id}/rounds/${round.id}/matchsheets`, "_blank"); } printRoundOverview(round: Round) { window.open(`tournaments/${this.tournament.id}/rounds/${round.id}/overview`, "_blank"); } activeMatches(): ActiveMatch[] { let matches: ActiveMatch[] = []; for (const event of this.tournament.events) { for (const group of event.groups) { for (const round of group.rounds) { for (const match of round.matches) { if (match.status == 'IN_PROGRESS') { matches.push(new ActiveMatch(match, round, group)); } } } } } return matches; } getActiveMatchCountForGroup(group: Group): number { let active = 0; for (const round of group.rounds) { for (const match of round.matches) { if (match.status == 'IN_PROGRESS') { active++; } } } return active; } groupOnlyHasFinishedRounds(group: Group): boolean { let allFinished = true; for (const round of group.rounds) { allFinished &&= round.status == 'FINISHED'; } return allFinished; } matchResultDialog = inject(MatDialog); courtSelectionDialog = inject(MatDialog); editResult(match: Match, group: Group, round: Round) { this.matchResultDialog.open(MatchResultComponent, { data: {match: match, group: group, round: round}, minWidth: '800px' }).afterClosed().subscribe(result => { if (result != undefined) { this.tournamentService.saveResult(this.tournament.id, result.matchId, result).subscribe(data => { this.tournament = data; }) } }); } checkWinner(match: Match): number { if (match.games.length == 0) return 0; if (match.games.length == 3) { if (match.games[2].score1 > match.games[2].score2) { return 1; } else { return 2; } } if (match.games[1].score1 > match.games[1].score2) { return 1; } else { return 2; } } checkRoundComplete(round: Round) { let complete: boolean = true; for (let match of round.matches) { complete &&= match.status == 'FINISHED'; } return complete; } protected readonly TournamentEvent = Event; getEventMatchCount(event: Event) { let count = 0; for (let group of event.groups) { let numTeams = group.teams.length; let rounds = numTeams <= 4 ? 3 : 4; let matchesPerRound = Math.trunc(numTeams / 2); count += (rounds * matchesPerRound); } return count; } getTournamentMatchCount(tournament: Tournament) { let count = 0; for (let event of tournament.events) { count += this.getEventMatchCount(event); } return count; } } class ActiveMatch { constructor(match: Match, round: Round, group: Group) { this.match = match; this.round = round; this.group = group; } match: Match; round: Round; group: Group; }