package nl.connectedit.swiss.service; import jakarta.transaction.Transactional; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; import lombok.RequiredArgsConstructor; import nl.connectedit.swiss.domain.EventType; import nl.connectedit.swiss.domain.Status; import nl.connectedit.swiss.domain.TournamentStatus; import nl.connectedit.swiss.domain.entity.Event; import nl.connectedit.swiss.domain.entity.Group; import nl.connectedit.swiss.domain.entity.Registration; import nl.connectedit.swiss.domain.entity.Team; import nl.connectedit.swiss.domain.entity.Tournament; import nl.connectedit.swiss.repository.TournamentRepository; import org.springframework.stereotype.Service; @Service @RequiredArgsConstructor public class TournamentDivideService { private final TournamentValidationService tournamentValidationService; private final TournamentRepository tournamentRepository; @Transactional public Tournament divide(Tournament tournament) { if (tournamentValidationService.validate(tournament).hasErrors()) { return tournament; } for (var event : tournament.getEvents()) { if ((event.getType().isDoublesEvent() && event.getRegistrations().size() >= 8) || (!event.getType().isDoublesEvent() && event.getRegistrations().size() >= 4)) { divide(event); } } tournament.setStatus(TournamentStatus.DIVIDED); tournamentRepository.save(tournament); return tournament; } public void divide(Event event) { List registrations; if (event.getType().isDoublesEvent()) { registrations = groupRegistrations(event.getRegistrations()); } else { registrations = event.getRegistrations(); } event.setGroups(new ArrayList<>()); if (registrations.size() <= 16) { var group = getGroup(registrations, event.getType()); group.setEvent(event); event.getGroups().add(group); } else { var groups = getGroups(registrations, event.getType()); groups.forEach(group -> group.setEvent(event)); event.getGroups().addAll(groups); } } private List groupRegistrations(List registrations) { var groupedRegistrations = new ArrayList(); nextRegistration: for (var registration : registrations) { for (var groupedRegistration : groupedRegistrations) { if (Objects.equals(groupedRegistration.getPartner(), registration.getPlayer())) { continue nextRegistration; } } groupedRegistrations.add(registration); } return groupedRegistrations; } private Group getGroup(List registrations, EventType type) { var group = new Group(); group.setName(type.getText()); group.setType(type); group.setStatus(Status.IN_PROGRESS); group.setTeams(new ArrayList<>()); for (var registration : registrations) { group.getTeams().add(getTeam(registration, group)); } return group; } private List getGroups(List orgRegistrations, EventType type) { var registrations = new ArrayList<>(orgRegistrations); var group1 = new Group(); group1.setName(type.getText() + " 1"); group1.setType(type); group1.setStatus(Status.IN_PROGRESS); group1.setTeams(new ArrayList<>()); var group2 = new Group(); group2.setName(type.getText() + " 2"); group2.setType(type); group2.setStatus(Status.IN_PROGRESS); group2.setTeams(new ArrayList<>()); var registrationStrengthMap = new HashMap(); for (var registration : registrations) { var strength = registration.getPlayer().getStrength().getCoefficient(); if (registration.getPartner() != null) { strength += registration.getPartner().getStrength().getCoefficient(); } registrationStrengthMap.put(registration, strength); } var sortedRegistrations = registrationStrengthMap .entrySet() .stream() .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())) .map(Map.Entry::getKey) .toList(); for (Iterator i = sortedRegistrations.iterator(); i.hasNext(); ) { group1.getTeams().add(getTeam(i.next(), group1)); if (i.hasNext()) { group2.getTeams().add(getTeam(i.next(), group2)); } } if (group1.getTeams().size() % 2 == 1 && group2.getTeams().size() % 2 == 1) { group1.getTeams().add(group2.getTeams().getLast()); group2.getTeams().removeLast(); } return List.of(group1, group2); } private Team getTeam(Registration registration, Group group) { var team = new Team(); team.setPlayer1(registration.getPlayer()); team.setPlayer2(registration.getPartner()); team.setGroups(List.of(group)); return team; } public Tournament clear(Tournament tournament) { for (var event : tournament.getEvents()) { event.getGroups().clear(); } tournament.setStatus(TournamentStatus.UPCOMING); tournamentRepository.save(tournament); return tournament; } }