@ -32,32 +32,16 @@ final public class Tournament: BaseTournament {
return TournamentLibrary . shared . store ( tournamentId : self . id )
return TournamentLibrary . shared . store ( tournamentId : self . id )
}
}
public override func deleteUnusedShared Dependencies ( store : Store ) {
public override func deleteDependencies ( store : Store , shouldBeSynchronized : Bool ) {
do {
do {
let tournamentStore = try store . alternateStore ( identifier : self . id )
let tournamentStore = try store . alternateStore ( identifier : self . id )
tournamentStore . deleteUnusedSharedDependencies ( type : DrawLog . self )
tournamentStore . deleteAllDependencies ( type : DrawLog . self , shouldBeSynchronized : shouldBeSynchronized )
tournamentStore . deleteUnusedSharedDependencies ( type : TeamRegistration . self )
tournamentStore . deleteAllDependencies ( type : TeamRegistration . self , shouldBeSynchronized : shouldBeSynchronized )
tournamentStore . deleteUnusedSharedDependencies ( type : GroupStage . self )
tournamentStore . deleteAllDependencies ( type : GroupStage . self , shouldBeSynchronized : shouldBeSynchronized )
tournamentStore . deleteUnusedSharedDependencies ( type : Round . self )
tournamentStore . deleteAllDependencies ( type : Round . self , shouldBeSynchronized : shouldBeSynchronized )
} catch {
tournamentStore . deleteAllDependencies ( type : MatchScheduler . self , shouldBeSynchronized : shouldBeSynchronized )
Logger . error ( error )
}
store . deleteUnusedSharedDependencies ( type : Court . self ) { $0 . club = = self . id }
}
public override func deleteDependencies ( store : Store , actionOption : ActionOption ) {
do {
let tournamentStore = try store . alternateStore ( identifier : self . id )
tournamentStore . deleteAllDependencies ( type : DrawLog . self , actionOption : actionOption )
tournamentStore . deleteAllDependencies ( type : TeamRegistration . self , actionOption : actionOption )
tournamentStore . deleteAllDependencies ( type : GroupStage . self , actionOption : actionOption )
tournamentStore . deleteAllDependencies ( type : Round . self , actionOption : actionOption )
tournamentStore . deleteAllDependencies ( type : MatchScheduler . self , actionOption : actionOption )
} catch {
} catch {
Logger . error ( error )
Logger . error ( error )
}
}
@ -104,37 +88,12 @@ final public class Tournament: BaseTournament {
return self . tournamentStore ? . teamRegistrations . count ? ? 0
return self . tournamentStore ? . teamRegistrations . count ? ? 0
}
}
public func deleteGroupStage ( _ groupStage : GroupStage ) {
groupStage . removeAllTeams ( )
let index = groupStage . index
self . tournamentStore ? . groupStages . delete ( instance : groupStage )
self . groupStageCount -= 1
let groupStages = self . groupStages ( )
groupStages . filter ( { $0 . index > index } ) . forEach { gs in
gs . index -= 1
}
self . tournamentStore ? . groupStages . addOrUpdate ( contentOfs : groupStages )
}
public func addGroupStage ( ) {
let groupStage = GroupStage ( tournament : id , index : groupStageCount , size : teamsPerGroupStage , format : groupStageFormat )
self . tournamentStore ? . groupStages . addOrUpdate ( instance : groupStage )
groupStage . buildMatches ( keepExistingMatches : false )
self . groupStageCount += 1
}
public func groupStages ( atStep step : Int = 0 ) -> [ GroupStage ] {
public func groupStages ( atStep step : Int = 0 ) -> [ GroupStage ] {
guard let tournamentStore = self . tournamentStore else { return [ ] }
guard let tournamentStore = self . tournamentStore else { return [ ] }
let groupStages : [ GroupStage ] = tournamentStore . groupStages . filter { $0 . step = = step }
let groupStages : [ GroupStage ] = tournamentStore . groupStages . filter { $0 . tournament = = self . id && $0 . step = = step }
return groupStages . sorted ( by : \ . index )
return groupStages . sorted ( by : \ . index )
}
}
public func hasGroupeStages ( ) -> Bool {
if groupStageCount > 0 { return true }
guard let tournamentStore = self . tournamentStore else { return false }
return tournamentStore . groupStages . isEmpty = = false
}
public func allGroupStages ( ) -> [ GroupStage ] {
public func allGroupStages ( ) -> [ GroupStage ] {
guard let tournamentStore = self . tournamentStore else { return [ ] }
guard let tournamentStore = self . tournamentStore else { return [ ] }
return tournamentStore . groupStages . sorted ( by : \ GroupStage . computedOrder )
return tournamentStore . groupStages . sorted ( by : \ GroupStage . computedOrder )
@ -277,24 +236,17 @@ defer {
return Store . main . findById ( event )
return Store . main . findById ( event )
}
}
public func pasteDataForImporting ( _ exportFormat : ExportFormat = . rawText , type : ExportType ) -> String {
public func pasteDataForImporting ( _ exportFormat : ExportFormat = . rawText ) -> String {
let _selectedSortedTeams = selectedSortedTeams ( )
let _selectedSortedTeams = selectedSortedTeams ( )
let selectedSortedTeams = _selectedSortedTeams + waitingListSortedTeams ( selectedSortedTeams : _selectedSortedTeams )
let selectedSortedTeams = _selectedSortedTeams + waitingListSortedTeams ( selectedSortedTeams : _selectedSortedTeams )
switch exportFormat {
switch exportFormat {
case . rawText :
case . rawText :
let waitingList = waitingListTeams ( in : selectedSortedTeams , includingWalkOuts : true )
return ( selectedSortedTeams . compactMap { $0 . pasteData ( exportFormat ) } + [ " Liste d'attente " ] + waitingListTeams ( in : selectedSortedTeams , includingWalkOuts : true ) . compactMap { $0 . pasteData ( exportFormat ) } ) . joined ( separator : exportFormat . newLineSeparator ( 2 ) )
var stats = [ String ] ( )
if type = = . payment , isAnimation ( ) , minimumPlayerPerTeam = = 1 {
stats += [ " \( self . selectedPlayers ( ) . count . formatted ( ) ) personnes " ]
} else {
stats += [ selectedSortedTeams . count . formatted ( ) + " équipes " ]
}
return ( stats + selectedSortedTeams . compactMap { $0 . pasteData ( exportFormat , type : type ) } + ( waitingList . isEmpty = = false ? [ " Liste d'attente " ] : [ ] ) + waitingList . compactMap { $0 . pasteData ( exportFormat , type : type ) } ) . joined ( separator : exportFormat . newLineSeparator ( 1 ) )
case . csv :
case . csv :
let headers = [ " N° " , " Nom Prénom " , " rang " , " Nom Prénom " , " rang " , " poids " , " Paire " ] . joined ( separator : exportFormat . separator ( ) )
let headers = [ " N° " , " Nom Prénom " , " rang " , " Nom Prénom " , " rang " , " poids " , " Paire " ] . joined ( separator : exportFormat . separator ( ) )
var teamPaste = [ headers ]
var teamPaste = [ headers ]
for ( index , team ) in selectedSortedTeams . enumerated ( ) {
for ( index , team ) in selectedSortedTeams . enumerated ( ) {
var teamData = team . pasteData ( exportFormat , type : type , index + 1 )
var teamData = team . pasteData ( exportFormat , index + 1 )
teamData . append ( exportFormat . separator ( ) )
teamData . append ( exportFormat . separator ( ) )
teamData . append ( team . teamLastNames ( ) . joined ( separator : " / " ) )
teamData . append ( team . teamLastNames ( ) . joined ( separator : " / " ) )
teamPaste . append ( teamData )
teamPaste . append ( teamData )
@ -393,7 +345,6 @@ defer {
public func availableSeedOpponentSpot ( inRoundIndex roundIndex : Int ) -> [ Match ] {
public func availableSeedOpponentSpot ( inRoundIndex roundIndex : Int ) -> [ Match ] {
return getRound ( atRoundIndex : roundIndex ) ? . playedMatches ( ) . filter { $0 . hasSpaceLeft ( ) } ? ? [ ]
return getRound ( atRoundIndex : roundIndex ) ? . playedMatches ( ) . filter { $0 . hasSpaceLeft ( ) } ? ? [ ]
}
}
public func availableSeedGroups ( includeAll : Bool = false ) -> [ SeedInterval ] {
public func availableSeedGroups ( includeAll : Bool = false ) -> [ SeedInterval ] {
let seeds = seeds ( )
let seeds = seeds ( )
var availableSeedGroup = Set < SeedInterval > ( )
var availableSeedGroup = Set < SeedInterval > ( )
@ -411,24 +362,6 @@ defer {
return availableSeedGroup . sorted ( by : < )
return availableSeedGroup . sorted ( by : < )
}
}
public func generateSeedGroups ( base : Int , teamCount : Int ) -> [ SeedInterval ] {
let start = base + 1
let root = SeedInterval ( first : start , last : start + teamCount - 1 )
var groups : [ SeedInterval ] = [ ]
func split ( interval : SeedInterval ) {
groups . append ( interval )
if let chunks = interval . chunks ( ) {
for chunk in chunks {
split ( interval : chunk )
}
}
}
split ( interval : root )
return groups . sorted ( by : < )
}
public func chunksBy ( in chunks : [ SeedInterval ] , availableSeedGroup : inout Set < SeedInterval > ) {
public func chunksBy ( in chunks : [ SeedInterval ] , availableSeedGroup : inout Set < SeedInterval > ) {
chunks . forEach { chunk in
chunks . forEach { chunk in
availableSeedGroup . insert ( chunk )
availableSeedGroup . insert ( chunk )
@ -721,7 +654,7 @@ defer {
var groupStageTeamCount : Int = groupStageSpots - wcGroupStage . count
var groupStageTeamCount : Int = groupStageSpots - wcGroupStage . count
if groupStageTeamCount < 0 { groupStageTeamCount = 0 }
if groupStageTeamCount < 0 { groupStageTeamCount = 0 }
if bracketSeeds < 0 { bracketSeeds = 0 }
if bracketSeeds < 0 { bracketSeeds = 0 }
let clubName = self . clubName
if prioritizeClubMembers {
if prioritizeClubMembers {
var bracketTeams : [ TeamRegistration ] = [ ]
var bracketTeams : [ TeamRegistration ] = [ ]
@ -904,7 +837,7 @@ defer {
return allMatches . filter ( { $0 . isRunning ( ) && $0 . isReady ( ) } ) . sorted ( using : defaultSorting , order : . ascending )
return allMatches . filter ( { $0 . isRunning ( ) && $0 . isReady ( ) } ) . sorted ( using : defaultSorting , order : . ascending )
}
}
public static func readyMatches ( _ allMatches : [ Match ] , runningMatches : [ Match ] ) -> [ Match ] {
public static func readyMatches ( _ allMatches : [ Match ] ) -> [ Match ] {
#if _DEBUG_TIME // D E B U G I N G T I M E
#if _DEBUG_TIME // D E B U G I N G T I M E
let start = Date ( )
let start = Date ( )
defer {
defer {
@ -912,10 +845,7 @@ defer {
print ( " func tournament readyMatches " , id , duration . formatted ( . units ( allowed : [ . seconds , . milliseconds ] ) ) )
print ( " func tournament readyMatches " , id , duration . formatted ( . units ( allowed : [ . seconds , . milliseconds ] ) ) )
}
}
#endif
#endif
return allMatches . filter ( { $0 . isReady ( ) && $0 . isRunning ( ) = = false && $0 . hasEnded ( ) = = false } ) . sorted ( using : defaultSorting , order : . ascending )
let playingTeams = runningMatches . flatMap ( { $0 . teams ( ) } ) . map ( { $0 . id } )
return allMatches . filter ( { $0 . isReady ( ) && $0 . isRunning ( ) = = false && $0 . hasEnded ( ) = = false && $0 . containsTeamIds ( playingTeams ) = = false } ) . sorted ( using : defaultSorting , order : . ascending )
}
}
public static func matchesLeft ( _ allMatches : [ Match ] ) -> [ Match ] {
public static func matchesLeft ( _ allMatches : [ Match ] ) -> [ Match ] {
@ -1179,10 +1109,10 @@ defer {
}
}
public func tournamentTitle ( _ displayStyle : DisplayStyle = . wide , hideSenior : Bool = false ) -> String {
public func tournamentTitle ( _ displayStyle : DisplayStyle = . wide , hideSenior : Bool = false ) -> String {
if tournamentLevel = = . unlisted {
if tournamentLevel = = . unlisted , displayStyle = = . title {
if let name {
if let name {
return name
return name
} else if displayStyle = = . title {
} else {
return tournamentLevel . localizedLevelLabel ( . title )
return tournamentLevel . localizedLevelLabel ( . title )
}
}
}
}
@ -1222,7 +1152,14 @@ defer {
}
}
public func formattedDate ( _ displayStyle : DisplayStyle = . wide ) -> String {
public func formattedDate ( _ displayStyle : DisplayStyle = . wide ) -> String {
startDate . formattedDate ( displayStyle )
switch displayStyle {
case . title :
startDate . formatted ( . dateTime . weekday ( . abbreviated ) . day ( ) . month ( . abbreviated ) . year ( ) )
case . wide :
startDate . formatted ( date : Date . FormatStyle . DateStyle . complete , time : Date . FormatStyle . TimeStyle . omitted )
case . short :
startDate . formatted ( date : . numeric , time : . omitted )
}
}
}
public func qualifiedFromGroupStage ( ) -> Int {
public func qualifiedFromGroupStage ( ) -> Int {
@ -1472,7 +1409,7 @@ defer {
var _groupStages = [ GroupStage ] ( )
var _groupStages = [ GroupStage ] ( )
for index in 0. . < groupStageCount {
for index in 0. . < groupStageCount {
let groupStage = GroupStage ( tournament : id , index : index , size : teamsPerGroupStage , format : groupStageSmartMatch Format ( ) )
let groupStage = GroupStage ( tournament : id , index : index , size : teamsPerGroupStage , format : groupStageFormat )
_groupStages . append ( groupStage )
_groupStages . append ( groupStage )
}
}
@ -1491,7 +1428,7 @@ defer {
let matchCount = RoundRule . numberOfMatches ( forTeams : minimalBracketTeamCount ? ? bracketTeamCount ( ) )
let matchCount = RoundRule . numberOfMatches ( forTeams : minimalBracketTeamCount ? ? bracketTeamCount ( ) )
let rounds = ( 0. . < roundCount ) . map { // i n d e x 0 i s t h e f i n a l
let rounds = ( 0. . < roundCount ) . map { // i n d e x 0 i s t h e f i n a l
return Round ( tournament : id , index : $0 , format : roundS martMa tchFormat( $0 ) , loserBracketMode : loserBracketMode )
return Round ( tournament : id , index : $0 , format : matchFormat , loserBracketMode : loserBracketMode )
}
}
if rounds . isEmpty {
if rounds . isEmpty {
@ -1553,9 +1490,6 @@ defer {
public func deleteGroupStages ( ) {
public func deleteGroupStages ( ) {
self . tournamentStore ? . groupStages . delete ( contentOfs : allGroupStages ( ) )
self . tournamentStore ? . groupStages . delete ( contentOfs : allGroupStages ( ) )
if let gs = self . groupStageLoserBracket ( ) {
self . tournamentStore ? . rounds . delete ( instance : gs )
}
}
}
public func refreshGroupStages ( keepExistingMatches : Bool = false ) {
public func refreshGroupStages ( keepExistingMatches : Bool = false ) {
@ -1693,9 +1627,9 @@ defer {
set {
set {
federalLevelCategory = newValue
federalLevelCategory = newValue
teamSorting = newValue . defaultTeamSortingType
teamSorting = newValue . defaultTeamSortingType
groupStageMatchFormat = DataStore . shared . user . groupStageMatchFormatPreference ? ? groupStageSmartMatchFormat ( )
groupStageMatchFormat = groupStageSmartMatchFormat ( )
loserBracketMatchFormat = DataStore . shared . user . loserBracketMatchFormatPreference ? ? loserBracketSmartMatchFormat ( )
loserBracketMatchFormat = loserBracketSmartMatchFormat ( 1 )
matchFormat = DataStore . shared . user . bracketMatchFormatPreference ? ? roundSmartMatchFormat ( 5 )
matchFormat = roundSmartMatchFormat ( 5 )
}
}
}
}
@ -1708,8 +1642,8 @@ defer {
}
}
}
}
public func loserBracketSmartMatchFormat ( ) -> MatchFormat {
public func loserBracketSmartMatchFormat ( _ roundIndex : Int ) -> MatchFormat {
let format = tournamentLevel . federalFormatForLoserBracketRound ( )
let format = tournamentLevel . federalFormatForLoserBracketRound ( roundIndex )
if tournamentLevel = = . p25 { return . superTie }
if tournamentLevel = = . p25 { return . superTie }
if format . rank < loserBracketMatchFormat . rank {
if format . rank < loserBracketMatchFormat . rank {
return format
return format
@ -1720,6 +1654,7 @@ defer {
public func groupStageSmartMatchFormat ( ) -> MatchFormat {
public func groupStageSmartMatchFormat ( ) -> MatchFormat {
let format = tournamentLevel . federalFormatForGroupStage ( )
let format = tournamentLevel . federalFormatForGroupStage ( )
if tournamentLevel = = . p25 { return . superTie }
if format . rank < groupStageMatchFormat . rank {
if format . rank < groupStageMatchFormat . rank {
return format
return format
} else {
} else {
@ -1728,21 +1663,19 @@ defer {
}
}
public func initSettings ( templateTournament : Tournament ? , overrideTeamCount : Bool = true ) {
public func initSettings ( templateTournament : Tournament ? , overrideTeamCount : Bool = true ) {
courtCount = eventObject ( ) ? . clubObject ( ) ? . courtCount ? ? 2
setupDefaultPrivateSettings ( templateTournament : templateTournament )
setupDefaultPrivateSettings ( templateTournament : templateTournament )
setupUmpireSettings ( defaultTournament : nil ) // d e f a u l t i s n o t t e m p l a t e , d e f a u l t i s f o r e v e n t s h a r i n g s e t t i n g s
setupUmpireSettings ( defaultTournament : nil ) // d e f a u l t i s n o t t e m p l a t e , d e f a u l t i s f o r e v e n t s h a r i n g s e t t i n g s
if let templateTournament {
if let templateTournament {
setupRegistrationSettings ( templateTournament : templateTournament , overrideTeamCount : overrideTeamCount )
setupRegistrationSettings ( templateTournament : templateTournament , overrideTeamCount : overrideTeamCount )
}
}
setupFederalSettings ( )
setupFederalSettings ( )
customizeUsingPreferences ( )
}
}
public func setupFederalSettings ( ) {
public func setupFederalSettings ( ) {
teamSorting = tournamentLevel . defaultTeamSortingType
teamSorting = tournamentLevel . defaultTeamSortingType
groupStageMatchFormat = DataStore . shared . user . groupStageMatchFormatPreference ? ? groupStageSmartMatchFormat ( )
groupStageMatchFormat = groupStageSmartMatchFormat ( )
loserBracketMatchFormat = DataStore . shared . user . loserBracketMatchFormatPreference ? ? loserBracketSmartMatchFormat ( )
loserBracketMatchFormat = loserBracketSmartMatchFormat ( 5 )
matchFormat = DataStore . shared . user . bracketMatchFormatPreference ? ? roundSmartMatchFormat ( 5 )
matchFormat = roundSmartMatchFormat ( 5 )
entryFee = tournamentLevel . entryFee
entryFee = tournamentLevel . entryFee
registrationDateLimit = deadline ( for : . inscription )
registrationDateLimit = deadline ( for : . inscription )
if enableOnlineRegistration , isAnimation ( ) = = false {
if enableOnlineRegistration , isAnimation ( ) = = false {
@ -1751,23 +1684,6 @@ defer {
}
}
}
}
public func customizeUsingPreferences ( ) {
guard let lastTournamentWithSameBuild = DataStore . shared . tournaments . filter ( { tournament in
tournament . tournamentLevel = = self . tournamentLevel
&& tournament . tournamentCategory = = self . tournamentCategory
&& tournament . federalTournamentAge = = self . federalTournamentAge
&& tournament . hasEnded ( ) = = true
&& tournament . isCanceled = = false
&& tournament . isDeleted = = false
} ) . sorted ( by : \ . endDate ! , order : . descending ) . first else {
return
}
self . entryFee = lastTournamentWithSameBuild . entryFee
self . clubMemberFeeDeduction = lastTournamentWithSameBuild . clubMemberFeeDeduction
}
public func deadline ( for type : TournamentDeadlineType ) -> Date ? {
public func deadline ( for type : TournamentDeadlineType ) -> Date ? {
guard [ . p500 , . p1000 , . p1500 , . p2000 ] . contains ( tournamentLevel ) else { return nil }
guard [ . p500 , . p1000 , . p1500 , . p2000 ] . contains ( tournamentLevel ) else { return nil }
@ -1857,6 +1773,7 @@ defer {
public func roundSmartMatchFormat ( _ roundIndex : Int ) -> MatchFormat {
public func roundSmartMatchFormat ( _ roundIndex : Int ) -> MatchFormat {
let format = tournamentLevel . federalFormatForBracketRound ( roundIndex )
let format = tournamentLevel . federalFormatForBracketRound ( roundIndex )
if tournamentLevel = = . p25 { return . superTie }
if format . rank < matchFormat . rank {
if format . rank < matchFormat . rank {
return format
return format
} else {
} else {
@ -2124,17 +2041,6 @@ defer {
}
}
}
}
public func removeRound ( _ round : Round ) async {
await MainActor . run {
let teams = round . seeds ( )
teams . forEach { team in
team . resetBracketPosition ( )
}
tournamentStore ? . teamRegistrations . addOrUpdate ( contentOfs : teams )
tournamentStore ? . rounds . delete ( instance : round )
}
}
public func addNewRound ( _ roundIndex : Int ) async {
public func addNewRound ( _ roundIndex : Int ) async {
await MainActor . run {
await MainActor . run {
let round = Round ( tournament : id , index : roundIndex , format : matchFormat )
let round = Round ( tournament : id , index : roundIndex , format : matchFormat )
@ -2320,11 +2226,7 @@ defer {
}
}
public func onlineTeams ( ) -> [ TeamRegistration ] {
public func onlineTeams ( ) -> [ TeamRegistration ] {
// g u a r d l e t t e a m R e g i s t r a t i o n s = t o u r n a m e n t S t o r e ? . t e a m R e g i s t r a t i o n s e l s e { r e t u r n [ ] }
unsortedTeams ( ) . filter ( { $0 . hasRegisteredOnline ( ) } )
// r e t u r n t e a m R e g i s t r a t i o n s . c a c h e d ( k e y : " o n l i n e " ) { c o l l e c t i o n i n
// c o l l e c t i o n . f i l t e r { $ 0 . h a s R e g i s t e r e d O n l i n e ( ) }
// }
return unsortedTeams ( ) . filter ( { $0 . hasRegisteredOnline ( ) } )
}
}
public func paidOnlineTeams ( ) -> [ TeamRegistration ] {
public func paidOnlineTeams ( ) -> [ TeamRegistration ] {
@ -2359,7 +2261,7 @@ defer {
}
}
public func mailSubject ( ) -> String {
public func mailSubject ( ) -> String {
let subject = [ tournamentTitle ( hideSenior : true ) , formattedDate ( . short ) , customClubName ? ? c lubName ] . compactMap ( { $0 } ) . joined ( separator : " | " )
let subject = [ tournamentTitle ( hideSenior : true ) , formattedDate ( . short ) , clubName ] . compactMap ( { $0 } ) . joined ( separator : " | " )
return subject
return subject
}
}
@ -2464,9 +2366,6 @@ defer {
}
}
public func addon ( for playerRank : Int , manMax : Int , womanMax : Int ) -> Int {
public func addon ( for playerRank : Int , manMax : Int , womanMax : Int ) -> Int {
if tournamentCategory != . men {
return 0
}
switch playerRank {
switch playerRank {
case 0 : return 0
case 0 : return 0
case womanMax : return manMax - womanMax
case womanMax : return manMax - womanMax
@ -2506,16 +2405,6 @@ defer {
self . tournamentStore ? . rounds . addOrUpdate ( contentOfs : allRounds )
self . tournamentStore ? . rounds . addOrUpdate ( contentOfs : allRounds )
}
}
public func formatSummary ( ) -> String {
var label = [ String ] ( )
if groupStageCount > 0 {
label . append ( " Poules " + groupStageMatchFormat . format )
}
label . append ( " Tableau " + matchFormat . format )
label . append ( " Classement " + loserBracketMatchFormat . format )
return label . joined ( separator : " , " )
}
// MARK: -
// MARK: -
func insertOnServer ( ) throws {
func insertOnServer ( ) throws {