@ -9,7 +9,7 @@ import Foundation
import LeStorage
import LeStorage
@ Observable
@ Observable
class Tournament : ModelObject , Storable {
final class Tournament : ModelObject , Storable {
static func resourceName ( ) -> String { " tournaments " }
static func resourceName ( ) -> String { " tournaments " }
static func tokenExemptedMethods ( ) -> [ HTTPMethod ] { return [ ] }
static func tokenExemptedMethods ( ) -> [ HTTPMethod ] { return [ ] }
static func filterByStoreIdentifier ( ) -> Bool { return false }
static func filterByStoreIdentifier ( ) -> Bool { return false }
@ -55,6 +55,7 @@ class Tournament : ModelObject, Storable {
var hideTeamsWeight : Bool = false
var hideTeamsWeight : Bool = false
var publishTournament : Bool = false
var publishTournament : Bool = false
var hidePointsEarned : Bool = false
var hidePointsEarned : Bool = false
var publishRankings : Bool = false
@ ObservationIgnored
@ ObservationIgnored
var navigationPath : [ Screen ] = [ ]
var navigationPath : [ Screen ] = [ ]
@ -102,9 +103,10 @@ class Tournament : ModelObject, Storable {
case _hideTeamsWeight = " hideTeamsWeight "
case _hideTeamsWeight = " hideTeamsWeight "
case _publishTournament = " publishTournament "
case _publishTournament = " publishTournament "
case _hidePointsEarned = " hidePointsEarned "
case _hidePointsEarned = " hidePointsEarned "
case _publishRankings = " publishRankings "
}
}
internal init ( event : String ? = nil , name : String ? = nil , startDate : Date = Date ( ) , endDate : Date ? = nil , creationDate : Date = Date ( ) , isPrivate : Bool = false , groupStageFormat : MatchFormat ? = nil , roundFormat : MatchFormat ? = nil , loserRoundFormat : MatchFormat ? = nil , groupStageSortMode : GroupStageOrderingMode , groupStageCount : Int = 4 , rankSourceDate : Date ? = nil , dayDuration : Int = 1 , teamCount : Int = 24 , teamSorting : TeamSortingType ? = nil , federalCategory : TournamentCategory , federalLevelCategory : TournamentLevel , federalAgeCategory : FederalTournamentAge , closedRegistrationDate : Date ? = nil , groupStageAdditionalQualified : Int = 0 , courtCount : Int = 2 , prioritizeClubMembers : Bool = false , qualifiedPerGroupStage : Int = 1 , teamsPerGroupStage : Int = 4 , entryFee : Double ? = nil , additionalEstimationDuration : Int = 0 , isDeleted : Bool = false , publishTeams : Bool = false , publishSummons : Bool = false , publishGroupStages : Bool = false , publishBrackets : Bool = false , shouldVerifyBracket : Bool = false , shouldVerifyGroupStage : Bool = false , hideTeamsWeight : Bool = false , publishTournament : Bool = false , hidePointsEarned : Bool = false ) {
internal init ( event : String ? = nil , name : String ? = nil , startDate : Date = Date ( ) , endDate : Date ? = nil , creationDate : Date = Date ( ) , isPrivate : Bool = false , groupStageFormat : MatchFormat ? = nil , roundFormat : MatchFormat ? = nil , loserRoundFormat : MatchFormat ? = nil , groupStageSortMode : GroupStageOrderingMode , groupStageCount : Int = 4 , rankSourceDate : Date ? = nil , dayDuration : Int = 1 , teamCount : Int = 24 , teamSorting : TeamSortingType ? = nil , federalCategory : TournamentCategory , federalLevelCategory : TournamentLevel , federalAgeCategory : FederalTournamentAge , closedRegistrationDate : Date ? = nil , groupStageAdditionalQualified : Int = 0 , courtCount : Int = 2 , prioritizeClubMembers : Bool = false , qualifiedPerGroupStage : Int = 1 , teamsPerGroupStage : Int = 4 , entryFee : Double ? = nil , additionalEstimationDuration : Int = 0 , isDeleted : Bool = false , publishTeams : Bool = false , publishSummons : Bool = false , publishGroupStages : Bool = false , publishBrackets : Bool = false , shouldVerifyBracket : Bool = false , shouldVerifyGroupStage : Bool = false , hideTeamsWeight : Bool = false , publishTournament : Bool = false , hidePointsEarned : Bool = false , publishRankings : Bool = false ) {
self . event = event
self . event = event
self . name = name
self . name = name
self . startDate = startDate
self . startDate = startDate
@ -141,6 +143,7 @@ class Tournament : ModelObject, Storable {
self . hideTeamsWeight = hideTeamsWeight
self . hideTeamsWeight = hideTeamsWeight
self . publishTournament = publishTournament
self . publishTournament = publishTournament
self . hidePointsEarned = hidePointsEarned
self . hidePointsEarned = hidePointsEarned
self . publishRankings = publishRankings
}
}
required init ( from decoder : Decoder ) throws {
required init ( from decoder : Decoder ) throws {
@ -184,6 +187,7 @@ class Tournament : ModelObject, Storable {
hideTeamsWeight = try container . decodeIfPresent ( Bool . self , forKey : . _hideTeamsWeight ) ? ? false
hideTeamsWeight = try container . decodeIfPresent ( Bool . self , forKey : . _hideTeamsWeight ) ? ? false
publishTournament = try container . decodeIfPresent ( Bool . self , forKey : . _publishTournament ) ? ? false
publishTournament = try container . decodeIfPresent ( Bool . self , forKey : . _publishTournament ) ? ? false
hidePointsEarned = try container . decodeIfPresent ( Bool . self , forKey : . _hidePointsEarned ) ? ? false
hidePointsEarned = try container . decodeIfPresent ( Bool . self , forKey : . _hidePointsEarned ) ? ? false
publishRankings = try container . decodeIfPresent ( Bool . self , forKey : . _publishRankings ) ? ? false
}
}
fileprivate static let _numberFormatter : NumberFormatter = NumberFormatter ( )
fileprivate static let _numberFormatter : NumberFormatter = NumberFormatter ( )
@ -298,6 +302,7 @@ class Tournament : ModelObject, Storable {
try container . encode ( hideTeamsWeight , forKey : . _hideTeamsWeight )
try container . encode ( hideTeamsWeight , forKey : . _hideTeamsWeight )
try container . encode ( publishTournament , forKey : . _publishTournament )
try container . encode ( publishTournament , forKey : . _publishTournament )
try container . encode ( hidePointsEarned , forKey : . _hidePointsEarned )
try container . encode ( hidePointsEarned , forKey : . _hidePointsEarned )
try container . encode ( publishRankings , forKey : . _publishRankings )
}
}
fileprivate func _encodePayment ( container : inout KeyedEncodingContainer < CodingKeys > ) throws {
fileprivate func _encodePayment ( container : inout KeyedEncodingContainer < CodingKeys > ) throws {
@ -487,8 +492,7 @@ class Tournament : ModelObject, Storable {
}
}
func courtUsed ( ) -> [ Int ] {
func courtUsed ( ) -> [ Int ] {
#if DEBUG // 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 {
let duration = Duration . milliseconds ( Date ( ) . timeIntervalSince ( start ) * 1_000 )
let duration = Duration . milliseconds ( Date ( ) . timeIntervalSince ( start ) * 1_000 )
@ -1104,6 +1108,17 @@ defer {
return selected . sorted ( by : \ . finalRanking ! , order : . ascending )
return selected . sorted ( by : \ . finalRanking ! , order : . ascending )
}
}
private func _removeStrings ( from dictionary : inout [ Int : [ String ] ] , stringsToRemove : [ String ] ) {
for key in dictionary . keys {
if var stringArray = dictionary [ key ] {
// R e m o v e a l l i n s t a n c e s o f e a c h s t r i n g i n s t r i n g s T o R e m o v e
stringArray . removeAll { stringsToRemove . contains ( $0 ) }
dictionary [ key ] = stringArray
}
}
}
func finalRanking ( ) async -> [ Int : [ String ] ] {
func finalRanking ( ) async -> [ Int : [ String ] ] {
var teams : [ Int : [ String ] ] = [ : ]
var teams : [ Int : [ String ] ] = [ : ]
var ids : Set < String > = Set < String > ( )
var ids : Set < String > = Set < String > ( )
@ -1119,6 +1134,14 @@ defer {
}
}
let others : [ Round ] = rounds . flatMap { round in
let others : [ Round ] = rounds . flatMap { round in
let losers = round . losers ( )
let minimumFinalPosition = round . seedInterval ( ) ? . last ? ? teamCount
if teams [ minimumFinalPosition ] = = nil {
teams [ minimumFinalPosition ] = losers . map { $0 . id }
} else {
teams [ minimumFinalPosition ] ? . append ( contentsOf : losers . map { $0 . id } )
}
print ( " round " , round . roundTitle ( ) )
print ( " round " , round . roundTitle ( ) )
let rounds = round . loserRoundsAndChildren ( ) . filter { $0 . isRankDisabled ( ) = = false && $0 . hasNextRound ( ) = = false }
let rounds = round . loserRoundsAndChildren ( ) . filter { $0 . isRankDisabled ( ) = = false && $0 . hasNextRound ( ) = = false }
print ( rounds . count , rounds . map { $0 . roundTitle ( ) } )
print ( rounds . count , rounds . map { $0 . roundTitle ( ) } )
@ -1137,28 +1160,40 @@ defer {
print ( " losers " , losers . count )
print ( " losers " , losers . count )
if winners . isEmpty {
if winners . isEmpty {
let disabledIds = playedMatches . flatMap ( { $0 . teamScores . compactMap ( { $0 . teamRegistration } ) } ) . filter ( { ids . contains ( $0 ) = = false } )
let disabledIds = playedMatches . flatMap ( { $0 . teamScores . compactMap ( { $0 . teamRegistration } ) } ) . filter ( { ids . contains ( $0 ) = = false } )
teams [ interval . computedLast ] = disabledIds
if disabledIds . isEmpty = = false {
let teamNames : [ String ] = disabledIds . compactMap {
_removeStrings ( from : & teams , stringsToRemove : disabledIds )
let t : TeamRegistration ? = Store . main . findById ( $0 )
teams [ interval . computedLast ] = disabledIds
return t
let teamNames : [ String ] = disabledIds . compactMap {
} . map { $0 . canonicalName }
let t : TeamRegistration ? = Store . main . findById ( $0 )
print ( " winners.isEmpty " , " \( interval . computedLast ) : " , teamNames )
return t
disabledIds . forEach { ids . insert ( $0 ) }
} . map { $0 . canonicalName }
print ( " winners.isEmpty " , " \( interval . computedLast ) : " , teamNames )
disabledIds . forEach {
ids . insert ( $0 )
}
}
} else {
} else {
teams [ interval . computedFirst + winners . count - 1 ] = winners
if winners . isEmpty = = false {
let teamNames : [ String ] = winners . compactMap {
_removeStrings ( from : & teams , stringsToRemove : winners )
let t : TeamRegistration ? = Store . main . findById ( $0 )
teams [ interval . computedFirst + winners . count - 1 ] = winners
return t
let teamNames : [ String ] = winners . compactMap {
} . map { $0 . canonicalName }
let t : TeamRegistration ? = Store . main . findById ( $0 )
print ( " winners " , " \( interval . computedFirst + winners . count - 1 ) : " , teamNames )
return t
winners . forEach { ids . insert ( $0 ) }
} . map { $0 . canonicalName }
teams [ interval . computedLast ] = losers
print ( " winners " , " \( interval . computedFirst + winners . count - 1 ) : " , teamNames )
let loserTeamNames : [ String ] = losers . compactMap {
winners . forEach { ids . insert ( $0 ) }
let t : TeamRegistration ? = Store . main . findById ( $0 )
}
return t
} . map { $0 . canonicalName }
if losers . isEmpty = = false {
print ( " losers " , " \( interval . computedLast ) : " , loserTeamNames )
_removeStrings ( from : & teams , stringsToRemove : losers )
losers . forEach { ids . insert ( $0 ) }
teams [ interval . computedLast ] = losers
let loserTeamNames : [ String ] = losers . compactMap {
let t : TeamRegistration ? = Store . main . findById ( $0 )
return t
} . map { $0 . canonicalName }
print ( " losers " , " \( interval . computedLast ) : " , loserTeamNames )
losers . forEach { ids . insert ( $0 ) }
}
}
}
}
}
}
}
@ -1882,7 +1917,7 @@ defer {
let selected = selectedSortedTeams ( )
let selected = selectedSortedTeams ( )
let allTeams = unsortedTeams ( )
let allTeams = unsortedTeams ( )
let seedCount = max ( selected . count - groupStageSpots ( ) , 0 )
let seedCount = max ( selected . count - groupStageSpots ( ) , 0 )
let newGroup = selected . prefix ( seedCount )
let newGroup = selected . prefix ( seedCount ) + selected . filter ( { $0 . qualified } )
let currentGroup = allTeams . filter ( { $0 . bracketPosition != nil } )
let currentGroup = allTeams . filter ( { $0 . bracketPosition != nil } )
let selectedIds = newGroup . map { $0 . id }
let selectedIds = newGroup . map { $0 . id }
let groupIds = currentGroup . map { $0 . id }
let groupIds = currentGroup . map { $0 . id }