package app.data.service; import app.data.bean.CalculatedMatch; import app.data.bean.PlayerForTable; import app.data.entity.Matchday; import app.data.entity.Player; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.vaadin.artur.helpers.CrudService; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @Service public class PlayerService extends CrudService { private final PlayerRepository repository; private final MatchdayService matchdayService; private final MatchService matchService; public PlayerService(@Autowired PlayerRepository repository, @Autowired MatchdayService matchdayService, @Autowired MatchService matchService) { this.repository = repository; this.matchdayService = matchdayService; this.matchService = matchService; } @Override protected PlayerRepository getRepository() { return repository; } public List getPlayersForTable(Matchday matchday) { return new PlayerForTableProvider(matchday).getPlayersForTableSorted(); } private class PlayerForTableProvider { List matchdays = new ArrayList<>(); List calculatedMatches = new ArrayList<>(); List players = repository.findAll(); public PlayerForTableProvider(Matchday matchday) { matchdays.addAll(matchdayService.getMatchdaysSorted(matchday.getSeason()).stream() .filter(matchdayToFilter -> matchdayToFilter.getNumber() <= matchday.getNumber()) .collect(Collectors.toList())); calculatedMatches.addAll(matchdays.stream() .flatMap((Function>) matchdayToMap -> matchService.getCalculatedMatches(matchdayToMap).stream()) .collect(Collectors.toList())); } private List getPlayersForTableSorted() { List playerForTableList = players.stream() .map(this::getPlayerForTable) .sorted(Comparator.comparingDouble(PlayerForTable::getGamePointsForSelf).reversed()) .sorted(Comparator.comparingDouble(PlayerForTable::getGamePointDiff).reversed()) .sorted(Comparator.comparingInt(PlayerForTable::getMatchPoints).reversed()) .collect(Collectors.toList()); int offset = 0; PlayerForTable lastPlayer; PlayerForTable currentPlayer; for (int i = 0; i < playerForTableList.size(); i++) { currentPlayer = playerForTableList.get(i); if (i > 0) { lastPlayer = playerForTableList.get(i - 1); // TODO: add direct comparison below if (Objects.equals(currentPlayer.getMatchPoints(), lastPlayer.getMatchPoints()) && Objects.equals(currentPlayer.getGamePointsForSelf(), lastPlayer.getGamePointsForSelf()) && Objects.equals(currentPlayer.getGamePointsForOpponents(), lastPlayer.getGamePointsForOpponents())) { offset += 1; } else { offset = 0; } } currentPlayer.setPlace(i + 1 - offset); currentPlayer.setPlaceString(offset == 0 ? String.valueOf(i + 1) : ""); } // TODO: add diff to last matchday return playerForTableList; } private PlayerForTable getPlayerForTable(Player player) { List matchesAsPlayer1 = getMatchesAsPlayer1(player); List matchesAsPlayer2 = getMatchesAsPlayer2(player); Map> map = getWinStateLists(matchesAsPlayer1, matchesAsPlayer2); int amountOfMatchesWon = map.get(WinState.WON).size(); int amountOfMatchesDrawn = map.get(WinState.DRAWN).size(); int amountOfMatchesLost = map.get(WinState.LOST).size(); int amountOfMatches = amountOfMatchesWon + amountOfMatchesDrawn + amountOfMatchesLost; int matchPoints = amountOfMatchesWon * 2 + amountOfMatchesDrawn; double gamePointsForSelf = 0; gamePointsForSelf += matchesAsPlayer1.stream().mapToDouble(CalculatedMatch::getScore1).sum(); gamePointsForSelf += matchesAsPlayer2.stream().mapToDouble(CalculatedMatch::getScore2).sum(); double gamePointsForOpponents = 0; gamePointsForOpponents += matchesAsPlayer1.stream().mapToDouble(CalculatedMatch::getScore2).sum(); gamePointsForOpponents += matchesAsPlayer2.stream().mapToDouble(CalculatedMatch::getScore1).sum(); double gamePointDiff = gamePointsForSelf - gamePointsForOpponents; return new PlayerForTable(player, matchPoints, amountOfMatches, amountOfMatchesWon, amountOfMatchesDrawn, amountOfMatchesLost, gamePointsForSelf, gamePointsForOpponents, gamePointDiff); } private List getMatchesAsPlayer1(Player player) { return calculatedMatches.stream() .filter(match -> match.getPlayer1().equals(player)) .collect(Collectors.toList()); } private List getMatchesAsPlayer2(Player player) { return calculatedMatches.stream() .filter(match -> match.getPlayer2().equals(player)) .collect(Collectors.toList()); } private Map> getWinStateLists(List matchesAsPlayer1, List matchesAsPlayer2) { Map> map = new HashMap<>(); map.put(WinState.WON, new ArrayList<>()); map.put(WinState.DRAWN, new ArrayList<>()); map.put(WinState.LOST, new ArrayList<>()); for (CalculatedMatch match : matchesAsPlayer1) { if (match.getScore1() > match.getScore2()) { map.get(WinState.WON).add(match); continue; } if (match.getScore1() < match.getScore2()) { map.get(WinState.LOST).add(match); continue; } if (match.getScore1() > 0) { map.get(WinState.DRAWN).add(match); } } for (CalculatedMatch match : matchesAsPlayer2) { if (match.getScore2() > match.getScore1()) { map.get(WinState.WON).add(match); continue; } if (match.getScore2() < match.getScore1()) { map.get(WinState.LOST).add(match); continue; } if (match.getScore2() > 0) { map.get(WinState.DRAWN).add(match); } } return map; } } private enum WinState { WON, DRAWN, LOST } }