from os import WEXITED, preadv from django.db import models from django.contrib.auth.models import AbstractUser from django.conf import settings import uuid import os, json from django.utils import timezone from django.utils.encoding import Promise import tournaments class FederalCategory(models.IntegerChoices): MEN = 0, 'Men' WOMEN = 1, 'Women' MIXED = 2, 'Mixed' class FederalLevelCategory(models.IntegerChoices): P25 = 25, 'P25' P100 = 100, 'P100' P250 = 250, 'P250' P500 = 500, 'P500' P1000 = 1000, 'P1000' P1500 = 1500, 'P1500' P2000 = 2000, 'P2000' class FederalAgeCategory(models.IntegerChoices): A11_12 = 120, 'A11_12' A13_14 = 140, 'A13_14' A15_16 = 160, 'A15_16' A17_18 = 180, 'A17_18' SENIOR = 200, 'SENIOR' A45 = 450, 'A45' A55 = 550, 'A55' class FederalMatchCategory(models.IntegerChoices): TWO_SETS = 0, 'Two sets' TWO_SETS_SUPER_TIE = 1, 'Two sets super tie' TWO_SETS_FOUR_GAME = 2, 'Two sets of four games' NINE_GAMES = 3, 'Nine games' SUPER_TIE = 4, 'Super Tie-Break' MEGA_TIE = 5, 'Mega Tie-Break' TWO_SETS_DECISIVE_POINT = 6, 'Two Sets with decisive point' TWO_SETS_DECISIVE_POINT_SUPER_TIE = 7, 'Two Sets with decisive point and super tie-break' TWO_SETS_FOUR_GAME_DECISIVE_POINT = 8, 'Two sets of four games with decisive point' NINE_GAMES_DECISIVE_POINT = 9, 'Nine games with decisive point' class Club(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) name = models.CharField(max_length=50) acronym = models.CharField(max_length=10) phone = models.CharField(max_length=15, null=True, blank=True) code = models.CharField(max_length=10, null=True, blank=True) federal_club_data = models.JSONField(null=True, blank=True) address = models.CharField(max_length=200, null=True, blank=True) city = models.CharField(max_length=100, null=True, blank=True) zip_code = models.CharField(max_length=10, null=True, blank=True) latitude = models.FloatField(null=True, blank=True) longitude = models.FloatField(null=True, blank=True) def __str__(self): return self.name class CustomUser(AbstractUser): pass id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) umpire_code = models.CharField(max_length=50, blank=True, null=True) clubs = models.ManyToManyField(Club) phone = models.CharField(max_length=15, null=True, blank=True) first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) licence_id = models.CharField(max_length=10, null=True, blank=True) def __str__(self): return self.username class Event(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) club = models.ForeignKey(Club, on_delete=models.CASCADE) date = models.DateTimeField() name = models.CharField(max_length=200, null=True, blank=True) federal_tournament_data = models.JSONField(null=True, blank=True) court_count = models.IntegerField(null=True, blank=True) tenup_id = models.IntegerField(null=True, blank=True) group_stage_format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True) round_format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True) loser_round_format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True) def __str__(self): return self.name class Tournament(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) event = models.ForeignKey(Event, blank=True, null=True, on_delete=models.CASCADE) creator = models.ForeignKey(CustomUser, blank=True, null=True, on_delete=models.CASCADE) name = models.CharField(max_length=200, null=True, blank=True) start_date = models.DateTimeField() end_date = models.DateTimeField(null=True, blank=True) creation_date = models.DateTimeField() is_private = models.BooleanField() format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True) group_stage_format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True) round_format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True) loser_round_format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True) bracket_sort_mode = models.IntegerField(default=0) group_stage_count = models.IntegerField(default=0) rank_source_date = models.DateTimeField(null=True, blank=True) # custom_name = models.CharField(max_length=100, null=True, blank=True) day_duration = models.IntegerField(default=0) team_count = models.IntegerField(default=0) team_sorting = models.IntegerField(default=0) federal_category = models.IntegerField(default=FederalCategory.MEN, choices=FederalCategory.choices) # optional ? federal_level_category = models.IntegerField(default=FederalLevelCategory.P100, choices=FederalLevelCategory.choices) federal_age_category = models.IntegerField(default=FederalAgeCategory.SENIOR, choices=FederalAgeCategory.choices) group_stage_court_count = models.IntegerField(null=True, blank=True) seed_count = models.IntegerField(default=0) closed_registration_date = models.DateTimeField(null=True, blank=True) group_stage_additional_qualified = models.IntegerField(default=0) court_count = models.IntegerField(null=True, blank=True) prioritize_club_members = models.BooleanField() qualified_per_group_stage = models.IntegerField(default=0) teams_per_group_stage = models.IntegerField(default=0) #estimated_end_date = models.DateTimeField(null=True, blank=True) def __str__(self): return self.name def level(self): return self.get_federal_level_category_display() def category(self): return self.get_federal_category_display() def formatted_start_date(self): return self.start_date.strftime("%d/%m/%y") def team_calls(self): team_calls = [] for team_registration in self.teamregistration_set.all(): call_date = team_registration.call_date if call_date: names = team_registration.team_names() stage = team_registration.next_stage() weight = team_registration.weight() team_call = TeamCall(names, call_date, weight, stage, team_registration.logo) team_calls.append(team_call) return team_calls def live_matches(self): matches = [] for group_stage in self.groupstage_set.all(): for match in group_stage.match_set.all(): matches.append(match) for round in self.round_set.all(): for match in round.match_set.all(): matches.append(match) # matches = [m for m in matches if m.broadcasted==True] print(len(matches)) return map(lambda match: match.live_match(), matches) # # Convert object attributes to a dictionary # dict = self.__dict__ # # Convert dictionary to JSON # return json.dumps(dict) class Round(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) tournament = models.ForeignKey(Tournament, on_delete=models.CASCADE) index = models.IntegerField(null=True, blank=True) loser = models.ForeignKey('self', blank=True, null=True, on_delete=models.CASCADE) format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True) def __str__(self): return f"{self.tournament.name} - {self.name()}" # def stage_call(self): # stage_call = StageCall(f"1/{self.index}") # for match in self.match_set.all(): # names = map(lambda ts: ts.player_names(), match.teamstate_set.all()) # if names: # team_call = TeamCall(names, match.formatted_start_date) # stage_call.add_team(team_call) # return stage_call def name(self): if self.index == 0: return "Finale" elif self.index == 1: return "Demi-Finales" elif self.index == 2: return "Quarts de finale" elif self.index == 3: return "Huitième de finale" elif self.index == 4: return "Seizième de finale" else: return "" class GroupStage(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) tournament = models.ForeignKey(Tournament, on_delete=models.CASCADE) index = models.IntegerField(null=True, blank=True) format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True) def __str__(self): return f"{self.tournament.name} - {self.name()}" def name(self): return f"Poule {self.index}" def next_match(self, player_registration): matches = self.matches_for_registration(player_registration).filter(end_date__isnull=False).order_by('start_date') return matches[0] def matches_for_registration(self, player_registration): team_scores = TeamScore.objects.filter(player_registrations=player_registration) return map(lambda ts: ts.match, team_scores) class Match(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) round = models.ForeignKey(Round, null=True, blank=True, on_delete=models.CASCADE) group_stage = models.ForeignKey(GroupStage, null=True, blank=True, on_delete=models.CASCADE) start_date = models.DateTimeField(null=True, blank=True) end_date = models.DateTimeField(null=True, blank=True) index = models.IntegerField(null=True, blank=True) format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True) court = models.CharField(max_length=50, null=True, blank=True) serving_team_id = models.UUIDField(null=True, blank=True) winning_team_id = models.UUIDField(null=True, blank=True) losing_team_id = models.UUIDField(null=True, blank=True) broadcasted = models.BooleanField(default=False) def __str__(self): items = [f"Match {self.index}", self.formatted_start_date()] desc = " - ".join(items) player_names = " / ".join(self.player_names()) if self.round: return f"{str(self.round)} > {desc} > {player_names}" elif self.group_stage: return f"{str(self.group_stage)} > {desc} > {player_names}" def player_names(self): return map(lambda ts: ts.player_names(), self.team_scores.all()) def formatted_start_date(self): if self.start_date: return self.start_date.strftime("%H:%M") else: return "no date" # return str(self.start_date) #.strftime("%H:%M") def current_duration(self): if self.end_date: return (self.end_date - self.start_date).total_seconds() else: return (timezone.now() - self.start_date).total_seconds() def durationPrefix(self): if self.current_duration() > 0: return "Temps de jeu" else: return "Démarrage prévu dans" def formatted_duration(self): _seconds = self.current_duration() if _seconds > 0: _hours = int(_seconds / 3600) _minutes = int((_seconds % 3600) / 60) return f"{_hours:02d}h{_minutes:02d}min" else : _seconds = _seconds * -1 _hours = int(_seconds / 3600) _minutes = int((_seconds % 3600) / 60) return f"{_hours:02d}h{_minutes:02d}min" # def seconds(self): # return (timezone.now() - self.start_date).total_seconds() def live_match(self): title = f"Match {self.index}" date = self.formatted_start_date() duration = self.formatted_duration() court = "" if self.court: court = f"Terrain {self.court}" livematch = LiveMatch(title, date, duration, court) for team_score in self.team_scores.all(): image = team_score.team_registration.logo names = team_score.team_names() scores = team_score.scores_array() weight = team_score.team_registration.weight() is_winner = team_score.team_registration == self.winning_team_id team = Team(image, names, scores, weight, is_winner) livematch.add_team(team) return livematch class TeamRegistration(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) tournament = models.ForeignKey(Tournament, on_delete=models.CASCADE) group_stage = models.ForeignKey(GroupStage, null=True, blank=True, on_delete=models.SET_NULL) registration_date = models.DateTimeField(null=True, blank=True) call_date = models.DateTimeField(null=True, blank=True) bracket_position = models.IntegerField(null=True, blank=True) group_stage_position = models.IntegerField(null=True, blank=True) comment = models.CharField(max_length=200, null=True, blank=True) source = models.CharField(max_length=20, null=True, blank=True) source_value = models.CharField(max_length=200, null=True, blank=True) logo = models.CharField(max_length=200, null=True, blank=True) #models.FilePathField(path=os.path.join(settings.STATIC_ROOT, "images"), null=True, blank=True) name = models.CharField(max_length=200, null=True, blank=True) def __str__(self): return self.player_names() def team_names(self): if self.name: return [self.name] else: return map(lambda pr: pr.name(), self.playerregistration_set.all()) def player_names(self): names = map(lambda pr: pr.name(), self.playerregistration_set.all()) str = " - ".join(names) if len(str) > 0: return str else: return "no players" def next_stage(self): matches = Match.objects.filter(group_stage__isnull=True, team_scores__player_registrations__id=self.id).order_by('round__index') if matches: return matches[0].round.name() elif self.group_stage: return self.group_stage.name() else: return "--" def weight(self): top_two_players = self.playerregistration_set.all().order_by('rank')[:2] weight = 0 for player in top_two_players: rank = player.rank if player.rank is not None else 0 weight += rank return weight class PlayerRegistration(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) team_registration = models.ForeignKey(TeamRegistration, on_delete=models.CASCADE) first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) licence_id = models.CharField(max_length=20, null=True, blank=True) rank = models.IntegerField(null=True, blank=True) has_paid = models.BooleanField(default=False) unranked = models.BooleanField(default=False) def __str__(self): return self.name() def name(self): return f"{self.first_name} {self.last_name}" class TeamScore(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) match = models.ForeignKey(Match, on_delete=models.CASCADE, related_name="team_scores") team_registration = models.ForeignKey(TeamRegistration, on_delete=models.CASCADE, null=True, blank=True) player_registrations = models.ManyToManyField(PlayerRegistration, blank=True) score = models.CharField(max_length=50, null=True, blank=True) walk_out = models.IntegerField(null=True, blank=True) #id, int of the walked_out team lucky_loser = models.BooleanField() def __str__(self): return f"{str(self.match)}: {self.player_names()}" def player_names(self): names = map(lambda player: player.name(), self.player_registrations.all()) return " - ".join(names) def team_names(self): names = [] if self.team_registration.name: names.append(self.team_registration.name) else: names = list(map(lambda player: player.name(), self.player_registrations.all())) return names def scores_array(self): return [int(x) for x in self.score.split(',')] class Team: def __init__(self, image, names, scores, weight, is_winner): self.image = image self.names = names self.scores = scores self.weight = weight self.is_winner = is_winner class LiveMatch: def __init__(self, title, date, duration, court): self.title = title self.date = date self.teams = [] self.duration = duration self.court = court def add_team(self, team): self.teams.append(team) def toJSON(self): return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4) class TeamCall: def __init__(self, names, date, weight, stage, image): self.names = [] self.names = names self.date = date self.weight = weight self.stage = stage self.image = image # class Set(models.Model): # class Game(models.Model): # set = models.ForeignKey(Set, on_delete=models.CASCADE) # format = models.IntegerField() # class Point(models.Model): # game = models.ForeignKey(Game, on_delete=models.CASCADE) # action = models.IntegerField() # date = models.DateTimeField() # team_id = models.IntegerField()