You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
693 lines
24 KiB
693 lines
24 KiB
//
|
|
// TeamRegistration.swift
|
|
// Padel Tournament
|
|
//
|
|
// Created by razmig on 10/03/2024.
|
|
//
|
|
|
|
import Foundation
|
|
import LeStorage
|
|
import SwiftUI
|
|
|
|
@Observable
|
|
final public class TeamRegistration: BaseTeamRegistration, SideStorable {
|
|
@ObservationIgnored
|
|
var _cachedRestingTime: (Bool, Date?)?
|
|
|
|
// public init(
|
|
// tournament: String, groupStage: String? = nil, registrationDate: Date? = nil,
|
|
// callDate: Date? = nil, bracketPosition: Int? = nil, groupStagePosition: Int? = nil,
|
|
// comment: String? = nil, source: String? = nil, sourceValue: String? = nil,
|
|
// logo: String? = nil, name: String? = nil, walkOut: Bool = false,
|
|
// wildCardBracket: Bool = false, wildCardGroupStage: Bool = false, weight: Int = 0,
|
|
// lockedWeight: Int? = nil, confirmationDate: Date? = nil, qualified: Bool = false
|
|
// ) {
|
|
//
|
|
// super.init()
|
|
//
|
|
// // self.storeId = tournament
|
|
// self.tournament = tournament
|
|
// self.groupStage = groupStage
|
|
// self.registrationDate = registrationDate ?? Date()
|
|
// self.callDate = callDate
|
|
// self.bracketPosition = bracketPosition
|
|
// self.groupStagePosition = groupStagePosition
|
|
// self.comment = comment
|
|
// self.source = source
|
|
// self.sourceValue = sourceValue
|
|
// self.logo = logo
|
|
// self.name = name
|
|
// self.walkOut = walkOut
|
|
// self.wildCardBracket = wildCardBracket
|
|
// self.wildCardGroupStage = wildCardGroupStage
|
|
// self.weight = weight
|
|
// self.lockedWeight = lockedWeight
|
|
// self.confirmationDate = confirmationDate
|
|
// self.qualified = qualified
|
|
// }
|
|
//
|
|
public func hasRegisteredOnline() -> Bool {
|
|
players().anySatisfy({ $0.registeredOnline })
|
|
}
|
|
|
|
public func hasPaidOnline() -> Bool {
|
|
players().anySatisfy({ $0.hasPaidOnline() })
|
|
}
|
|
|
|
public func hasConfirmed() -> Bool {
|
|
players().allSatisfy({ $0.hasConfirmed() })
|
|
}
|
|
|
|
public func confirmRegistration() {
|
|
let players = players()
|
|
players.forEach({ $0.confirmRegistration() })
|
|
tournamentStore?.playerRegistrations.addOrUpdate(contentOfs: players)
|
|
}
|
|
|
|
public func unrankedOrUnknown() -> Bool {
|
|
players().anySatisfy({ $0.source == nil })
|
|
}
|
|
|
|
public func isOutOfTournament() -> Bool {
|
|
walkOut
|
|
}
|
|
|
|
public var tournamentStore: TournamentStore? {
|
|
return TournamentLibrary.shared.store(tournamentId: self.tournament)
|
|
}
|
|
|
|
// MARK: - Computed dependencies
|
|
|
|
public func unsortedPlayers() -> [PlayerRegistration] {
|
|
guard let tournamentStore = self.tournamentStore else { return [] }
|
|
return tournamentStore.playerRegistrations.filter {
|
|
$0.teamRegistration == self.id && $0.coach == false
|
|
}
|
|
}
|
|
|
|
// MARK: -
|
|
|
|
public func deleteTeamScores() {
|
|
guard let tournamentStore = self.tournamentStore else { return }
|
|
let ts = tournamentStore.teamScores.filter({ $0.teamRegistration == id })
|
|
tournamentStore.teamScores.delete(contentOfs: ts)
|
|
}
|
|
|
|
public override func deleteDependencies(store: Store, shouldBeSynchronized: Bool) {
|
|
|
|
store.deleteDependencies(type: TeamScore.self, shouldBeSynchronized: shouldBeSynchronized) { $0.teamRegistration == self.id }
|
|
store.deleteDependencies(type: PlayerRegistration.self, shouldBeSynchronized: shouldBeSynchronized) { $0.teamRegistration == self.id }
|
|
|
|
// let unsortedPlayers = unsortedPlayers()
|
|
// for player in unsortedPlayers {
|
|
// player.deleteDependencies(store: store, shouldBeSynchronized: shouldBeSynchronized)
|
|
// }
|
|
// self.tournamentStore?.playerRegistrations.deleteDependencies(unsortedPlayers, shouldBeSynchronized: shouldBeSynchronized)
|
|
//
|
|
// let teamScores = teamScores()
|
|
// for teamScore in teamScores {
|
|
// teamScore.deleteDependencies(store: store, shouldBeSynchronized: shouldBeSynchronized)
|
|
// }
|
|
// self.tournamentStore?.teamScores.deleteDependencies(teamScores, shouldBeSynchronized: shouldBeSynchronized)
|
|
}
|
|
|
|
public func hasArrived(isHere: Bool = false) {
|
|
let unsortedPlayers = unsortedPlayers()
|
|
unsortedPlayers.forEach({ $0.hasArrived = !isHere })
|
|
self.tournamentStore?.playerRegistrations.addOrUpdate(contentOfs: unsortedPlayers)
|
|
}
|
|
|
|
public func isHere() -> Bool {
|
|
let unsortedPlayers = unsortedPlayers()
|
|
if unsortedPlayers.isEmpty { return false }
|
|
return unsortedPlayers.allSatisfy({ $0.hasArrived })
|
|
}
|
|
|
|
public func isSeedable() -> Bool {
|
|
bracketPosition == nil && groupStage == nil
|
|
}
|
|
|
|
public func setSeedPosition(inSpot match: Match, slot: TeamPosition?, opposingSeeding: Bool) {
|
|
var teamPosition: TeamPosition {
|
|
if let slot {
|
|
return slot
|
|
} else {
|
|
let matchIndex = match.index
|
|
let seedRound = RoundRule.roundIndex(fromMatchIndex: matchIndex)
|
|
let numberOfMatches = RoundRule.numberOfMatches(forRoundIndex: seedRound)
|
|
let isUpper =
|
|
RoundRule.matchIndexWithinRound(fromMatchIndex: matchIndex)
|
|
< (numberOfMatches / 2)
|
|
var teamPosition = slot ?? (isUpper ? .one : .two)
|
|
if opposingSeeding {
|
|
teamPosition = slot ?? (isUpper ? .two : .one)
|
|
}
|
|
return teamPosition
|
|
}
|
|
}
|
|
|
|
let seedPosition: Int = match.lockAndGetSeedPosition(atTeamPosition: teamPosition)
|
|
tournamentObject()?.resetTeamScores(in: bracketPosition)
|
|
self.bracketPosition = seedPosition
|
|
if groupStagePosition != nil && qualified == false {
|
|
qualified = true
|
|
}
|
|
if let tournament = tournamentObject() {
|
|
if let index = index(in: tournament.selectedSortedTeams()) {
|
|
let drawLog = DrawLog(
|
|
tournament: tournament.id, drawSeed: index, drawMatchIndex: match.index,
|
|
drawTeamPosition: teamPosition, drawType: .seed)
|
|
do {
|
|
try tournamentStore?.drawLogs.addOrUpdate(instance: drawLog)
|
|
} catch {
|
|
Logger.error(error)
|
|
}
|
|
}
|
|
tournament.updateTeamScores(in: bracketPosition)
|
|
}
|
|
}
|
|
|
|
public func expectedSummonDate() -> Date? {
|
|
if let groupStageStartDate = groupStageObject()?.startDate {
|
|
return groupStageStartDate
|
|
} else if let roundMatchStartDate = initialMatch()?.startDate {
|
|
return roundMatchStartDate
|
|
}
|
|
return nil
|
|
}
|
|
|
|
public var initialWeight: Int {
|
|
return lockedWeight ?? weight
|
|
}
|
|
|
|
public func called() -> Bool {
|
|
return callDate != nil
|
|
}
|
|
|
|
public func confirmed() -> Bool {
|
|
return confirmationDate != nil
|
|
}
|
|
|
|
public func getPhoneNumbers() -> [String] {
|
|
return players().compactMap { $0.phoneNumber }.filter({ $0.isEmpty == false })
|
|
}
|
|
|
|
public func getMail() -> [String] {
|
|
let mails = players().compactMap({ $0.email })
|
|
return mails
|
|
}
|
|
|
|
public func isImported() -> Bool {
|
|
let unsortedPlayers = unsortedPlayers()
|
|
if unsortedPlayers.isEmpty { return false }
|
|
|
|
return unsortedPlayers.allSatisfy({ $0.isImported() })
|
|
}
|
|
|
|
public func isWildCard() -> Bool {
|
|
return wildCardBracket || wildCardGroupStage
|
|
}
|
|
|
|
public func isPlaying() -> Bool {
|
|
return currentMatch() != nil
|
|
}
|
|
|
|
public func currentMatch() -> Match? {
|
|
return teamScores().compactMap { $0.matchObject() }.first(where: { $0.isRunning() })
|
|
}
|
|
|
|
public func teamScores() -> [TeamScore] {
|
|
guard let tournamentStore = self.tournamentStore else { return [] }
|
|
return tournamentStore.teamScores.filter({ $0.teamRegistration == id })
|
|
}
|
|
|
|
public func wins() -> [Match] {
|
|
guard let tournamentStore = self.tournamentStore else { return [] }
|
|
return tournamentStore.matches.filter({ $0.winningTeamId == id })
|
|
}
|
|
|
|
public func loses() -> [Match] {
|
|
guard let tournamentStore = self.tournamentStore else { return [] }
|
|
return tournamentStore.matches.filter({ $0.losingTeamId == id })
|
|
}
|
|
|
|
public func matches() -> [Match] {
|
|
guard let tournamentStore = self.tournamentStore else { return [] }
|
|
return tournamentStore.matches.filter({ $0.losingTeamId == id || $0.winningTeamId == id })
|
|
}
|
|
|
|
var tournamentCategory: TournamentCategory {
|
|
tournamentObject()?.tournamentCategory ?? .men
|
|
}
|
|
|
|
@objc
|
|
var canonicalName: String {
|
|
players().map { $0.canonicalName }.joined(separator: " ")
|
|
}
|
|
|
|
public func hasMemberOfClub(_ codeClubOrClubName: String?) -> Bool {
|
|
guard let codeClubOrClubName else { return true }
|
|
return unsortedPlayers().anySatisfy({
|
|
$0.clubName?.contains(codeClubOrClubName) == true
|
|
|| $0.clubName?.contains(codeClubOrClubName) == true
|
|
})
|
|
}
|
|
|
|
public func teamLabel(
|
|
_ displayStyle: DisplayStyle = .wide, twoLines: Bool = false, separator: String = "&"
|
|
) -> String {
|
|
if let name { return name }
|
|
return players().map { $0.playerLabel(displayStyle) }.joined(
|
|
separator: twoLines ? "\n" : " \(separator) ")
|
|
}
|
|
|
|
public func teamLabelRanked(displayRank: Bool, displayTeamName: Bool) -> String {
|
|
[
|
|
displayTeamName ? name : nil, displayRank ? seedIndex() : nil,
|
|
displayTeamName ? (name == nil ? teamLabel() : name) : teamLabel(),
|
|
].compactMap({ $0 }).joined(separator: " ")
|
|
}
|
|
|
|
public func seedIndex() -> String? {
|
|
guard let tournament = tournamentObject() else { return nil }
|
|
guard let index = index(in: tournament.selectedSortedTeams()) else { return nil }
|
|
return "(\(index + 1))"
|
|
}
|
|
|
|
public func index(in teams: [TeamRegistration]) -> Int? {
|
|
return teams.firstIndex(where: { $0.id == id })
|
|
}
|
|
|
|
public func formattedSeed(in teams: [TeamRegistration]? = nil) -> String {
|
|
let selectedSortedTeams = teams ?? tournamentObject()?.selectedSortedTeams() ?? []
|
|
if let index = index(in: selectedSortedTeams) {
|
|
return "#\(index + 1)"
|
|
} else {
|
|
return "###"
|
|
}
|
|
}
|
|
|
|
public func contains(_ searchField: String) -> Bool {
|
|
return unsortedPlayers().anySatisfy({ $0.contains(searchField) })
|
|
|| self.name?.localizedCaseInsensitiveContains(searchField) == true
|
|
}
|
|
|
|
public func containsExactlyPlayerLicenses(_ playerLicenses: [String?]) -> Bool {
|
|
let arrayOfIds: [String] = unsortedPlayers().compactMap({
|
|
$0.licenceId?.strippedLicense?.canonicalVersion
|
|
})
|
|
let ids: Set<String> = Set<String>(arrayOfIds.sorted())
|
|
let searchedIds = Set<String>(
|
|
playerLicenses.compactMap({ $0?.strippedLicense?.canonicalVersion }).sorted())
|
|
if ids.isEmpty || searchedIds.isEmpty { return false }
|
|
return ids.hashValue == searchedIds.hashValue
|
|
}
|
|
|
|
public func includes(players: [PlayerRegistration]) -> Bool {
|
|
let unsortedPlayers = unsortedPlayers()
|
|
guard players.count == unsortedPlayers.count else { return false }
|
|
return players.allSatisfy { player in
|
|
unsortedPlayers.anySatisfy { _player in
|
|
_player.isSameAs(player)
|
|
}
|
|
}
|
|
}
|
|
|
|
public func includes(player: PlayerRegistration) -> Bool {
|
|
return unsortedPlayers().anySatisfy { _player in
|
|
_player.isSameAs(player)
|
|
}
|
|
}
|
|
|
|
public func canPlay() -> Bool {
|
|
let unsortedPlayers = unsortedPlayers()
|
|
if unsortedPlayers.isEmpty { return false }
|
|
|
|
return matches().isEmpty == false
|
|
|| unsortedPlayers.allSatisfy({ $0.hasPaid() || $0.hasArrived })
|
|
}
|
|
|
|
public func availableForSeedPick() -> Bool {
|
|
return groupStage == nil && bracketPosition == nil
|
|
}
|
|
|
|
public func inGroupStage() -> Bool {
|
|
return groupStagePosition != nil
|
|
}
|
|
|
|
public func inRound() -> Bool {
|
|
return bracketPosition != nil
|
|
}
|
|
|
|
public func positionLabel() -> String? {
|
|
if groupStagePosition != nil { return "Poule" }
|
|
if let initialRound = initialRound() {
|
|
return initialRound.roundTitle()
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
public func resetGroupeStagePosition() {
|
|
guard let tournamentStore = self.tournamentStore else { return }
|
|
if let groupStage {
|
|
let matches = tournamentStore.matches.filter({ $0.groupStage == groupStage }).map {
|
|
$0.id
|
|
}
|
|
let teamScores = tournamentStore.teamScores.filter({
|
|
$0.teamRegistration == id && matches.contains($0.match)
|
|
})
|
|
tournamentStore.teamScores.delete(contentOfs: teamScores)
|
|
}
|
|
//groupStageObject()?._matches().forEach({ $0.updateTeamScores() })
|
|
groupStage = nil
|
|
groupStagePosition = nil
|
|
}
|
|
|
|
public func resetBracketPosition() {
|
|
guard let tournamentStore = self.tournamentStore else { return }
|
|
let matches = tournamentStore.matches.filter({ $0.groupStage == nil }).map { $0.id }
|
|
let teamScores = tournamentStore.teamScores.filter({
|
|
$0.teamRegistration == id && matches.contains($0.match)
|
|
})
|
|
tournamentStore.teamScores.delete(contentOfs: teamScores)
|
|
|
|
self.bracketPosition = nil
|
|
}
|
|
|
|
public func resetPositions() {
|
|
resetGroupeStagePosition()
|
|
resetBracketPosition()
|
|
}
|
|
|
|
public func pasteData(_ exportFormat: ExportFormat = .rawText, _ index: Int = 0) -> String {
|
|
switch exportFormat {
|
|
case .rawText:
|
|
return [playersPasteData(exportFormat), formattedInscriptionDate(exportFormat), name]
|
|
.compactMap({ $0 }).joined(separator: exportFormat.newLineSeparator())
|
|
case .csv:
|
|
return [
|
|
index.formatted(), playersPasteData(exportFormat),
|
|
isWildCard() ? "WC" : weight.formatted(),
|
|
].joined(separator: exportFormat.separator())
|
|
}
|
|
}
|
|
|
|
public func teamLastNames() -> [String] {
|
|
players().map { p in
|
|
p.lastName
|
|
}
|
|
}
|
|
|
|
public var computedRegistrationDate: Date {
|
|
return registrationDate ?? .distantFuture
|
|
}
|
|
|
|
public func formattedInscriptionDate(_ exportFormat: ExportFormat = .rawText) -> String? {
|
|
guard let registrationDate else { return nil }
|
|
|
|
let formattedDate = registrationDate.formatted(
|
|
.dateTime.weekday().day().month().hour().minute())
|
|
let onlineSuffix = hasRegisteredOnline() ? " en ligne" : ""
|
|
|
|
switch exportFormat {
|
|
case .rawText:
|
|
return "Inscrit\(onlineSuffix) le \(formattedDate)"
|
|
case .csv:
|
|
return formattedDate
|
|
}
|
|
}
|
|
|
|
public func formattedSummonDate(_ exportFormat: ExportFormat = .rawText) -> String? {
|
|
|
|
switch exportFormat {
|
|
case .rawText:
|
|
if let callDate {
|
|
return "Convoqué le "
|
|
+ callDate.formatted(.dateTime.weekday().day().month().hour().minute())
|
|
} else {
|
|
return nil
|
|
}
|
|
case .csv:
|
|
if let callDate {
|
|
return callDate.formatted(.dateTime.weekday().day().month().hour().minute())
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
|
|
public func playersPasteData(_ exportFormat: ExportFormat = .rawText) -> String {
|
|
switch exportFormat {
|
|
case .rawText:
|
|
return players().map { $0.pasteData(exportFormat) }.joined(
|
|
separator: exportFormat.newLineSeparator())
|
|
case .csv:
|
|
return players().map {
|
|
[$0.pasteData(exportFormat), isWildCard() ? "WC" : $0.computedRank.formatted()]
|
|
.joined(separator: exportFormat.separator())
|
|
}.joined(separator: exportFormat.separator())
|
|
}
|
|
}
|
|
|
|
public typealias TeamRange = (left: TeamRegistration?, right: TeamRegistration?)
|
|
|
|
public func replacementRange() -> TeamRange? {
|
|
guard let tournamentObject = tournamentObject() else { return nil }
|
|
guard let index = tournamentObject.indexOf(team: self) else { return nil }
|
|
let selectedSortedTeams = tournamentObject.selectedSortedTeams()
|
|
let left = selectedSortedTeams[safe: index - 1]
|
|
let right = selectedSortedTeams[safe: index + 1]
|
|
return (left: left, right: right)
|
|
}
|
|
|
|
public func replacementRangeExtended() -> TeamRange? {
|
|
guard let tournamentObject = tournamentObject() else { return nil }
|
|
guard let groupStagePosition else { return nil }
|
|
let selectedSortedTeams = tournamentObject.selectedSortedTeams()
|
|
var left: TeamRegistration? = nil
|
|
if groupStagePosition == 0 {
|
|
left = tournamentObject.seeds().last
|
|
} else {
|
|
let previousHat = selectedSortedTeams.filter({
|
|
$0.groupStagePosition == groupStagePosition - 1
|
|
}).sorted(by: \.weight)
|
|
left = previousHat.last
|
|
}
|
|
var right: TeamRegistration? = nil
|
|
if groupStagePosition == tournamentObject.teamsPerGroupStage - 1 {
|
|
right = nil
|
|
} else {
|
|
let previousHat = selectedSortedTeams.filter({
|
|
$0.groupStagePosition == groupStagePosition + 1
|
|
}).sorted(by: \.weight)
|
|
right = previousHat.first
|
|
}
|
|
return (left: left, right: right)
|
|
}
|
|
|
|
typealias AreInIncreasingOrder = (PlayerRegistration, PlayerRegistration) -> Bool
|
|
|
|
public func players() -> [PlayerRegistration] {
|
|
|
|
self.unsortedPlayers().sorted { (lhs, rhs) in
|
|
let predicates: [AreInIncreasingOrder] = [
|
|
{ $0.sex?.rawValue ?? 0 < $1.sex?.rawValue ?? 0 },
|
|
{ $0.rank ?? Int.max < $1.rank ?? Int.max },
|
|
{ $0.lastName < $1.lastName },
|
|
{ $0.firstName < $1.firstName },
|
|
]
|
|
|
|
for predicate in predicates {
|
|
if !predicate(lhs, rhs) && !predicate(rhs, lhs) {
|
|
continue
|
|
}
|
|
|
|
return predicate(lhs, rhs)
|
|
}
|
|
|
|
return false
|
|
}
|
|
}
|
|
|
|
public func coaches() -> [PlayerRegistration] {
|
|
guard let store = self.tournamentStore else { return [] }
|
|
return store.playerRegistrations.filter { $0.coach }
|
|
}
|
|
|
|
public func setWeight(
|
|
from players: [PlayerRegistration],
|
|
inTournamentCategory tournamentCategory: TournamentCategory
|
|
) {
|
|
let significantPlayerCount = significantPlayerCount()
|
|
let sortedPlayers = players.sorted(by: \.computedRank, order: .ascending)
|
|
weight = (sortedPlayers.prefix(significantPlayerCount).map { $0.computedRank } + missingPlayerType(inTournamentCategory: tournamentCategory).map { unrankValue(for: $0 == 1 ? true : false ) }).prefix(significantPlayerCount).reduce(0,+)
|
|
}
|
|
|
|
public func significantPlayerCount() -> Int {
|
|
return tournamentObject()?.significantPlayerCount() ?? 2
|
|
}
|
|
|
|
public func missingPlayerType(inTournamentCategory tournamentCategory: TournamentCategory) -> [Int] {
|
|
let players = unsortedPlayers()
|
|
if players.count >= 2 { return [] }
|
|
let s = players.compactMap { $0.sex?.rawValue }
|
|
var missing = tournamentCategory.mandatoryPlayerType()
|
|
s.forEach { i in
|
|
if let index = missing.firstIndex(of: i) {
|
|
missing.remove(at: index)
|
|
}
|
|
}
|
|
return missing
|
|
}
|
|
|
|
public func unrankValue(for malePlayer: Bool) -> Int {
|
|
return tournamentObject()?.unrankValue(for: malePlayer) ?? 90_415
|
|
}
|
|
|
|
public func groupStageObject() -> GroupStage? {
|
|
guard let groupStage else { return nil }
|
|
return self.tournamentStore?.groupStages.findById(groupStage)
|
|
}
|
|
|
|
public func initialRound() -> Round? {
|
|
guard let bracketPosition else { return nil }
|
|
let roundIndex = RoundRule.roundIndex(fromMatchIndex: bracketPosition / 2)
|
|
return self.tournamentStore?.rounds.first(where: { $0.index == roundIndex })
|
|
}
|
|
|
|
public func initialMatch() -> Match? {
|
|
guard let bracketPosition else { return nil }
|
|
guard let initialRoundObject = initialRound() else { return nil }
|
|
return self.tournamentStore?.matches.first(where: {
|
|
$0.round == initialRoundObject.id && $0.index == bracketPosition / 2
|
|
})
|
|
}
|
|
|
|
public func toggleSummonConfirmation() {
|
|
if confirmationDate == nil { confirmationDate = Date() } else { confirmationDate = nil }
|
|
}
|
|
|
|
public func didConfirmSummon() -> Bool {
|
|
confirmationDate != nil
|
|
}
|
|
|
|
public func tournamentObject() -> Tournament? {
|
|
return Store.main.findById(tournament)
|
|
}
|
|
|
|
public func groupStagePositionAtStep(_ step: Int) -> Int? {
|
|
guard let groupStagePosition else { return nil }
|
|
if step == 0 {
|
|
return groupStagePosition
|
|
} else if let groupStageObject = groupStageObject(), groupStageObject.hasEnded() {
|
|
return groupStageObject.index
|
|
}
|
|
return nil
|
|
}
|
|
|
|
public func wildcardLabel() -> String? {
|
|
if isWildCard() {
|
|
let wildcardLabel: String = ["Wildcard", (wildCardBracket ? "Tableau" : "Poule")].joined(separator: " ")
|
|
return wildcardLabel
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
public func restingTime() -> Date? {
|
|
if let _cachedRestingTime { return _cachedRestingTime.1 }
|
|
let restingTime = matches().filter({ $0.hasEnded() }).sorted(
|
|
by: \.computedEndDateForSorting
|
|
).last?.endDate
|
|
_cachedRestingTime = (true, restingTime)
|
|
return restingTime
|
|
}
|
|
|
|
public func resetRestingTime() {
|
|
_cachedRestingTime = nil
|
|
}
|
|
|
|
public var restingTimeForSorting: Date {
|
|
restingTime()!
|
|
}
|
|
|
|
public func teamNameLabel() -> String {
|
|
if let name, name.isEmpty == false {
|
|
return name
|
|
} else {
|
|
return "Toute l'équipe"
|
|
}
|
|
}
|
|
|
|
public func isDifferentPosition(_ drawMatchIndex: Int?) -> Bool {
|
|
if let bracketPosition, let drawMatchIndex {
|
|
return drawMatchIndex != bracketPosition
|
|
} else if bracketPosition != nil {
|
|
return true
|
|
} else if drawMatchIndex != nil {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
public func shouldDisplayRankAndWeight() -> Bool {
|
|
unsortedPlayers().count > 0
|
|
}
|
|
|
|
public func teamInitialPositionBracket() -> String? {
|
|
let round = initialMatch()?.roundAndMatchTitle()
|
|
if let round {
|
|
return round
|
|
}
|
|
return nil
|
|
}
|
|
|
|
public func teamInitialPositionGroupStage() -> String? {
|
|
let groupStage = self.groupStageObject()
|
|
let group = groupStage?.groupStageTitle(.title)
|
|
var groupPositionLabel: String? = nil
|
|
if let finalPosition = groupStage?.finalPosition(ofTeam: self) {
|
|
groupPositionLabel = (finalPosition + 1).ordinalFormatted()
|
|
} else if let groupStagePosition {
|
|
groupPositionLabel = "\(groupStagePosition + 1)"
|
|
}
|
|
|
|
if let group {
|
|
if let groupPositionLabel {
|
|
return [group, "#\(groupPositionLabel)"].joined(separator: " ")
|
|
} else {
|
|
return group
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
public func qualifiedStatus(hideBracketStatus: Bool = false) -> String? {
|
|
let teamInitialPositionBracket = teamInitialPositionBracket()
|
|
let groupStageTitle = teamInitialPositionGroupStage()
|
|
|
|
let base: String? = qualified ? "Qualifié" : nil
|
|
if let groupStageTitle, let teamInitialPositionBracket, hideBracketStatus == false {
|
|
return [base, groupStageTitle, ">", teamInitialPositionBracket].compactMap({ $0 }).joined(separator: " ")
|
|
} else if let groupStageTitle {
|
|
return [base, groupStageTitle].compactMap({ $0 }).joined(separator: " ")
|
|
} else if hideBracketStatus == false {
|
|
return teamInitialPositionBracket
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func insertOnServer() {
|
|
self.tournamentStore?.teamRegistrations.writeChangeAndInsertOnServer(instance: self)
|
|
for playerRegistration in self.unsortedPlayers() {
|
|
playerRegistration.insertOnServer()
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
enum TeamDataSource: Int, Codable {
|
|
case beachPadel
|
|
}
|
|
|