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.
 
 
PadelClub/PadelClub/Data/Federal/FederalPlayer.swift

246 lines
9.0 KiB

//
// FederalPlayer.swift
// PadelClub
//
// Created by Razmig Sarkissian on 01/03/2024.
//
import Foundation
class FederalPlayer: Decodable {
var rank: Int
var lastName: String
var firstName: String
var country: String
var license: String
var points: Double?
var assimilation: String
var tournamentCount: Int?
var ligue: String
var clubCode: String
var club: String
var isMale: Bool
var birthYear: Int?
var progression: Int
var bestRank: Int?
// MARK: - Nationnalite
struct Nationnalite: Hashable, Codable {
let code, codeFov: String
}
required init(from decoder: Decoder) throws {
/*
"classement": 9,
"evolution": 2,
"nom": "PEREZ LE TIEC",
"prenom": "Pierre",
"meilleurClassement": null,
"nationalite": "FRA",
"ageSportif": 30,
"points": 14210,
"nombreTournoisJoues": 24,
"ligue": "ILE DE FRANCE",
"assimilation": false
*/
enum CodingKeys: String, CodingKey {
case nom
case prenom
case licence
case meilleurClassement
case nationalite
case codeClub
case nomClub
case ligue
case classement
case evolution
case points
case nombreTournoisJoues
case assimilation
case ageSportif
}
let container = try decoder.container(keyedBy: CodingKeys.self)
isMale = (decoder.userInfo[.maleData] as? Bool) == true
let _lastName = try container.decodeIfPresent(String.self, forKey: .nom)
let _firstName = try container.decodeIfPresent(String.self, forKey: .prenom)
lastName = _lastName ?? ""
firstName = _firstName ?? ""
if let lic = try? container.decodeIfPresent(Int.self, forKey: .licence) {
license = String(lic)
} else {
license = ""
}
country = try container.decodeIfPresent(String.self, forKey: .nationalite) ?? ""
bestRank = try container.decodeIfPresent(Int.self, forKey: .meilleurClassement)
let ageSportif = try container.decodeIfPresent(Int.self, forKey: .ageSportif)
if let ageSportif {
let month = Calendar.current.component(.month, from: Date())
if month > 8 {
birthYear = Calendar.current.component(.year, from: Date()) + 1 - ageSportif
} else {
birthYear = Calendar.current.component(.year, from: Date()) - ageSportif
}
}
clubCode = try container.decodeIfPresent(String.self, forKey: .codeClub) ?? ""
club = try container.decodeIfPresent(String.self, forKey: .nomClub) ?? ""
ligue = try container.decodeIfPresent(String.self, forKey: .ligue) ?? ""
rank = try container.decode(Int.self, forKey: .classement)
progression = (try? container.decodeIfPresent(Int.self, forKey: .evolution)) ?? 0
let pointsAsInt = try? container.decodeIfPresent(Int.self, forKey: .points)
if let pointsAsInt {
points = Double(pointsAsInt)
} else {
points = nil
}
tournamentCount = try? container.decodeIfPresent(Int.self, forKey: .nombreTournoisJoues)
let assimile = try container.decode(Bool.self, forKey: .assimilation)
assimilation = assimile ? "Oui" : "Non"
}
func exportToCSV() -> String {
let pointsString = points != nil ? String(Int(points!)) : ""
let tournamentCountString = tournamentCount != nil ? String(tournamentCount!) : ""
let strippedLicense = license.strippedLicense ?? ""
let line = ";\(rank);\(lastName);\(firstName);\(country);\(strippedLicense);\(pointsString);\(assimilation);\(tournamentCountString);\(ligue);\(formatNumbers(clubCode));\(club);\(progression.formattedAsRawString());\(bestRank?.formattedAsRawString() ?? "");\(birthYear?.formattedAsRawString() ?? "");"
return line
}
func formatNumbers(_ input: String) -> String {
if input.isEmpty { return input }
// Insert spaces at appropriate positions
let formattedString = insertSeparator(input, separator: " ", every: [2, 4])
return formattedString
}
func insertSeparator(_ input: String, separator: String, every positions: [Int]) -> String {
var modifiedString = input
// Adjust for the index shift caused by inserting characters
var offset = 0
// Insert separator at specified positions
for position in positions {
let index = modifiedString.index(modifiedString.startIndex, offsetBy: position + offset)
modifiedString.insert(contentsOf: separator, at: index)
// Increase offset to adjust for the inserted character
offset += separator.count
}
return modifiedString
}
/*
;RANG;NOM;PRENOM;Nationalité;N° Licence;POINTS;Assimilation;NB. DE TOURNOIS JOUES;LIGUE;CODE CLUB;CLUB;
*/
var isManPlayer: Bool {
isMale
}
var isAssimilated: Bool {
assimilation == "Oui"
}
var currentRank: Int {
rank
}
init?(_ data: String, isMale: Bool = false) {
self.isMale = isMale
var result = data.components(separatedBy: .newlines).map { $0.trimmed }
result = result.reversed().drop(while: {
$0.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
}).reversed() as [String]
result = Array(result.drop(while: {
$0.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
}))
//print(result)
if result.count < 11 {
return nil
}
if let _rank = Int(result[0]) {
rank = _rank
} else {
return nil
}
lastName = result[1]
firstName = result[2]
country = result[3]
license = result[4]
// let matches = result[5].matches(of: try! Regex("[0-9]{1,5}\\.00"))
//
// if matches.count == 1 {
// let pts = result[5][matches.first!.range]
// points = Double(pts.replacingOccurrences(of: ",", with: "."))
// if pts.count < result[5].count {
//
// }
// }
//
points = Double(result[5].replacingOccurrences(of: ",", with: "."))
assimilation = result[6]
tournamentCount = Int(result[7])
ligue = result[8]
clubCode = result[9]
club = result[10]
progression = result[safe: 11]?.toInt() ?? 0
bestRank = result[safe: 12]?.toInt()
birthYear = result[safe: 13]?.toInt()
}
static func anonymousCount(mostRecentDateAvailable: Date?) async -> Int? {
let context = PersistenceController.shared.localContainer.newBackgroundContext()
let importedPlayerFetchRequest = ImportedPlayer.fetchRequest()
var predicate = NSPredicate(format: "lastName == %@ && firstName == %@", "", "")
if let mostRecentDateAvailable {
predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate, NSPredicate(format: "importDate == %@", mostRecentDateAvailable as CVarArg)])
}
importedPlayerFetchRequest.predicate = predicate
let count = try? context.count(for: importedPlayerFetchRequest)
return count
}
static func lastRank(mostRecentDateAvailable: Date?, man: Bool) async -> (Int, Int?)? {
let context = PersistenceController.shared.localContainer.newBackgroundContext()
let lastPlayerFetch = ImportedPlayer.fetchRequest()
lastPlayerFetch.sortDescriptors = [NSSortDescriptor(keyPath: \ImportedPlayer.rank, ascending: false)]
var predicate = NSPredicate(format: "male == \(man)")
if let mostRecentDateAvailable {
predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate, NSPredicate(format: "importDate == %@", mostRecentDateAvailable as CVarArg)])
}
lastPlayerFetch.predicate = predicate
let count = try? context.count(for: lastPlayerFetch)
do {
if let lr = try context.fetch(lastPlayerFetch).first?.rank {
let fetch = ImportedPlayer.fetchRequest()
var rankPredicate = NSPredicate(format: "rank == %i", lr)
if let mostRecentDateAvailable {
rankPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [rankPredicate, NSPredicate(format: "importDate == %@", mostRecentDateAvailable as CVarArg)])
}
fetch.predicate = rankPredicate
print(fetch.predicate)
let lastPlayersCount = try context.count(for: fetch)
print(Int(lr), Int(lastPlayersCount) - 1, count)
return (Int(lr) + Int(lastPlayersCount) - 1, count)
}
} catch {
print("ImportedPlayer.fetchRequest", error)
}
return nil
}
}
extension CodingUserInfoKey {
static let maleData = Self(rawValue: "maleData")!
}