package fr.titionfire.ffsaf.domain.service; import fr.titionfire.ffsaf.data.model.*; import fr.titionfire.ffsaf.data.repository.*; import fr.titionfire.ffsaf.rest.data.ResultCategoryData; import fr.titionfire.ffsaf.rest.exception.DForbiddenException; import fr.titionfire.ffsaf.utils.*; import io.quarkus.hibernate.reactive.panache.common.WithSession; import io.quarkus.runtime.annotations.RegisterForReflection; import io.smallrye.mutiny.Multi; import io.smallrye.mutiny.Uni; import io.smallrye.mutiny.unchecked.Unchecked; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import lombok.Builder; import org.hibernate.reactive.mutiny.Mutiny; import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Stream; @WithSession @ApplicationScoped public class ResultService { @Inject CompetitionRepository compRepository; @Inject RegisterRepository registerRepository; @Inject MembreService membreService; @Inject ClubRepository clubRepository; @Inject CompetitionGuestRepository competitionGuestRepository; @Inject CategoryRepository categoryRepository; @Inject MatchRepository matchRepository; private static final ResourceBundle BUNDLE = ResourceBundle.getBundle("lang.String"); public Uni> getList(SecurityCtx securityCtx) { return membreService.getByAccountId(securityCtx.getSubject()) .chain(m -> registerRepository.list("membre = ?1", m)) .onItem().transformToMulti(Multi.createFrom()::iterable) .onItem().call(r -> Mutiny.fetch(r.getCompetition())) .onItem().transform(r -> new Object[]{r.getCompetition().getUuid(), r.getCompetition().getName(), r.getCompetition().getDate()}) .collect().asList(); } public Uni> getCategoryList(String uuid) { return categoryRepository.list("compet.uuid = ?1", uuid) .map(categoryModels -> { HashMap map = new HashMap<>(); categoryModels.stream() .sorted(Comparator.comparing(CategoryModel::getName)) .forEachOrdered(categoryModel -> map.put(categoryModel.getName(), categoryModel.getId())); return map; }); } public Uni> getCategory(String uuid, SecurityCtx securityCtx) { return hasAccess(uuid, securityCtx) .chain(m -> categoryRepository.list("compet.uuid = ?1", uuid) .chain(cats -> matchRepository.list( "(c1_id = ?1 OR c2_id = ?1 OR True) AND category IN ?2", //TODO rm OR True m.getMembre(), cats))) .map(matchModels -> { HashMap> map = new HashMap<>(); for (MatchModel matchModel : matchModels) { if (!map.containsKey(matchModel.getCategory().getId())) map.put(matchModel.getCategory().getId(), new ArrayList<>()); map.get(matchModel.getCategory().getId()).add(matchModel); } return map.values(); }) .onItem() .transformToMulti(Multi.createFrom()::iterable) .onItem().call(list -> Mutiny.fetch(list.get(0).getCategory().getTree())) .onItem().transform(this::getData) .collect().asList(); } private ResultCategoryData getData(List matchModels) { ResultCategoryData out = new ResultCategoryData(); CategoryModel categoryModel = matchModels.get(0).getCategory(); out.setName(categoryModel.getName()); out.setType(categoryModel.getType()); out.setLiceName(categoryModel.getLiceName() == null ? new String[]{} : categoryModel.getLiceName().split(";")); out.setGenTime(System.currentTimeMillis()); getArray2(matchModels, out); getTree(categoryModel.getTree(), out); return out; } private void getArray2(List matchModels_, ResultCategoryData out) { List matchModels = matchModels_.stream().filter(o -> o.getCategory_ord() >= 0).toList(); HashMap> matchMap = new HashMap<>(); for (MatchModel model : matchModels) { char g = model.getPoule(); if (!matchMap.containsKey(g)) matchMap.put(g, new ArrayList<>()); matchMap.get(g).add(model); } matchMap.forEach((c, matchEntities) -> { List matchs = matchEntities.stream() .sorted(Comparator.comparing(MatchModel::getCategory_ord)) .map(ResultCategoryData.PouleArrayData::fromModel) .toList(); List rankArray = matchEntities.stream() .flatMap(m -> Stream.of(m.getC1Name(), m.getC2Name())) .distinct() .map(combName -> { AtomicInteger w = new AtomicInteger(0); AtomicInteger pointMake = new AtomicInteger(0); AtomicInteger pointTake = new AtomicInteger(0); matchEntities.stream() .filter(m -> m.isEnd() && (m.getC1Name().equals(combName) || m.getC2Name() .equals(combName))) .forEach(matchModel -> { int win = matchModel.win(); if ((matchModel.getC1Name() .equals(combName) && win > 0) || matchModel.getC2Name() .equals(combName) && win < 0) w.getAndIncrement(); for (ScoreEmbeddable score : matchModel.getScores()) { if (score.getS1() <= -900 || score.getS2() <= -900) continue; if (matchModel.getC1Name().equals(combName)) { pointMake.addAndGet(score.getS1()); pointTake.addAndGet(score.getS2()); } else { pointMake.addAndGet(score.getS2()); pointTake.addAndGet(score.getS1()); } } }); float pointRate = (pointTake.get() == 0) ? pointMake.get() : (float) pointMake.get() / pointTake.get(); return new ResultCategoryData.RankArray(0, combName, w.get(), pointMake.get(), pointTake.get(), pointRate); }) .sorted(Comparator .comparing(ResultCategoryData.RankArray::getWin) .thenComparing(ResultCategoryData.RankArray::getPointRate).reversed()) .toList(); out.getMatchs().put(c, matchs); int lastWin = -1; float pointRate = 0; int rank = 0; for (ResultCategoryData.RankArray rankArray1 : rankArray) { if (rankArray1.getWin() != lastWin || pointRate != rankArray1.getPointRate()) { lastWin = rankArray1.getWin(); pointRate = rankArray1.getPointRate(); rank++; } rankArray1.setRank(rank); } out.getRankArray().put(c, rankArray); }); } private static void convertTree(TreeModel src, TreeNode dst) { dst.setData(ResultCategoryData.TreeData.from(src.getMatch())); if (src.getLeft() != null) { dst.setLeft(new TreeNode<>()); convertTree(src.getLeft(), dst.getLeft()); } if (src.getRight() != null) { dst.setRight(new TreeNode<>()); convertTree(src.getRight(), dst.getRight()); } } public Uni getCategoryPublic(String uuid, long poule) { return matchRepository.list("category.compet.uuid = ?1 AND category.id = ?2", uuid, poule) .call(list -> Mutiny.fetch(list.get(0).getCategory().getTree())) .map(this::getData); } private void getTree(List treeModels, ResultCategoryData out) { ArrayList> trees = new ArrayList<>(); treeModels.stream().filter(t -> t.getLevel() != 0).forEach(treeModel -> { TreeNode root = new TreeNode<>(); convertTree(treeModel, root); trees.add(root); }); out.setTrees(trees); } public Uni getAllCombArray(String uuid, SecurityCtx securityCtx) { return hasAccess(uuid, securityCtx) .chain(__ -> getAllCombArray(uuid)); } public Uni getAllCombArrayPublic(String uuid) { return getAllCombArray(uuid); } public Uni getAllCombArray(String uuid) { return registerRepository.list("competition.uuid = ?1", uuid) .chain(registers -> matchRepository.list("category.compet.uuid = ?1", uuid) .map(matchModels -> new Pair<>(registers, matchModels))) .map(pair -> { List registers = pair.getKey(); List matchModels = pair.getValue(); CombsArrayData.CombsArrayDataBuilder builder = CombsArrayData.builder(); List combs = matchModels.stream() .flatMap(m -> Stream.of(m.getC1Name(), m.getC2Name())) .filter(Objects::nonNull) .distinct() .map(combName -> { var builder2 = CombsArrayData.CombsData.builder(); AtomicInteger w = new AtomicInteger(0); AtomicInteger l = new AtomicInteger(0); AtomicInteger pointMake = new AtomicInteger(); AtomicInteger pointTake = new AtomicInteger(); matchModels.stream() .filter(m -> m.isEnd() && (m.getC1Name().equals(combName) || m.getC2Name().equals(combName))) .forEach(matchModel -> { int win = matchModel.win(); if ((combName.equals(matchModel.getC1Name()) && win > 0) || combName.equals(matchModel.getC2Name()) && win < 0) { w.getAndIncrement(); } else { l.getAndIncrement(); } matchModel.getScores().stream() .filter(s -> s.getS1() > -900 && s.getS2() > -900) .forEach(score -> { if (combName.equals(matchModel.getC1Name())) { pointMake.addAndGet(score.getS1()); pointTake.addAndGet(score.getS2()); } else { pointMake.addAndGet(score.getS2()); pointTake.addAndGet(score.getS1()); } }); }); Categorie categorie = null; ClubModel club = null; Optional register = registers.stream() .filter(r -> r.getName().equals(combName)).findFirst(); if (register.isPresent()) { categorie = register.get().getCategorie(); club = register.get().getClub2(); } builder2.cat((categorie == null) ? "---" : categorie.getName(BUNDLE)); builder2.name(combName); builder2.w(w.get()); builder2.l(l.get()); builder2.ratioVictoire((l.get() == 0) ? w.get() : (float) w.get() / l.get()); builder2.club((club == null) ? BUNDLE.getString("no.licence") : club.getName()); builder2.pointMake(pointMake.get()); builder2.pointTake(pointTake.get()); builder2.ratioPoint( (pointTake.get() == 0) ? pointMake.get() : (float) pointMake.get() / pointTake.get()); return builder2.build(); }) .sorted(Comparator.comparing(CombsArrayData.CombsData::name)) .toList(); builder.nb_insc(combs.size()); builder.tt_match((int) matchModels.stream().filter(MatchModel::isEnd).count()); builder.point(combs.stream().mapToInt(CombsArrayData.CombsData::pointMake).sum()); builder.combs(combs); return builder.build(); }); } public Uni> getCombList(String uuid) { return registerRepository.list("competition.uuid = ?1", uuid) .map(models -> { HashMap map = new HashMap<>(); models.forEach(registerEmbeddable -> { map.put(Utils.getFullName(registerEmbeddable.getMembre()), registerEmbeddable.getMembre().getFname() + "¤" + registerEmbeddable.getMembre() .getLname()); }); return map; }) .chain(map -> competitionGuestRepository.list("competition.uuid = ?1", uuid) .map(models -> { models.forEach(guestModel -> map.put(Utils.getFullName(guestModel), guestModel.getFname() + "¤" + guestModel.getLname())); return map; }) ); } public Uni getCombArrayPublic(String uuid, String fname, String lname) { CombArrayData.CombArrayDataBuilder builder = CombArrayData.builder(); AtomicBoolean guest = new AtomicBoolean(false); AtomicLong id = new AtomicLong(0); return registerRepository.find("membre.fname = ?1 AND membre.lname = ?2 AND competition.uuid = ?3", fname, lname, uuid).firstResult() .chain(registerModel -> { if (registerModel == null) { return competitionGuestRepository.find("fname = ?1 AND lname = ?2 AND competition.uuid = ?3", fname, lname, uuid).firstResult() .chain(guestModel -> { builder.name(Utils.getFullName(guestModel)); builder.club(guestModel.getClub()); guest.set(true); id.set(guestModel.getId()); builder.cat((guestModel.getCategorie() == null) ? "---" : guestModel.getCategorie() .getName(BUNDLE)); return matchRepository.list( "category.compet.uuid = ?1 AND (c1_guest = ?2 OR c2_guest = ?2)", uuid, guestModel); }); } builder.name(Utils.getFullName(registerModel.getMembre())); builder.club((registerModel.getClub2() == null) ? BUNDLE.getString( "no.licence") : registerModel.getClub2().getName()); id.set(registerModel.getMembre().getId()); builder.cat((registerModel.getCategorie2() == null) ? "---" : registerModel.getCategorie2() .getName(BUNDLE)); return matchRepository.list("category.compet.uuid = ?1 AND (c1_id = ?2 OR c2_id = ?2)", uuid, registerModel.getMembre()); }) .invoke(matchModels -> { List pouleModels = matchModels.stream().map(MatchModel::getCategory).distinct() .toList(); List matchs = new ArrayList<>(); AtomicInteger sumW = new AtomicInteger(); AtomicInteger sumPointMake = new AtomicInteger(0); AtomicInteger sumPointTake = new AtomicInteger(0); for (MatchModel matchModel : matchModels) { if ((matchModel.getC1_id() == null && matchModel.getC1_guest() == null) || (matchModel.getC2_id() == null && matchModel.getC2_guest() == null)) continue; var builder2 = CombArrayData.MatchsData.builder(); builder2.date(matchModel.getDate()); builder2.poule(pouleModels.stream().filter(p -> p.equals(matchModel.getCategory())) .map(CategoryModel::getName).findFirst().orElse("")); AtomicInteger pointMake = new AtomicInteger(); AtomicInteger pointTake = new AtomicInteger(); if ((!guest.get() && matchModel.getC1_id() != null && matchModel.getC1_id().getId() == id.get()) || (guest.get() && matchModel.getC1_guest() != null && matchModel.getC1_guest() .getId() == id.get())) { builder2.adv(Utils.getFullName(matchModel.getC2_id(), matchModel.getC2_guest())); if (matchModel.isEnd()) { matchModel.getScores().stream() .filter(s -> s.getS1() > -900 && s.getS2() > -900) .forEach(scoreEntity -> { pointMake.addAndGet(scoreEntity.getS1()); pointTake.addAndGet(scoreEntity.getS2()); }); builder2.score(matchModel.getScores().stream() .map(s -> new Integer[]{s.getS1(), s.getS2()}).toList()); } else { builder2.score(new ArrayList<>()); } builder2.win(matchModel.win() > 0); } else { builder2.adv(Utils.getFullName(matchModel.getC1_id(), matchModel.getC1_guest())); if (matchModel.isEnd()) { matchModel.getScores().stream() .filter(s -> s.getS1() > -900 && s.getS2() > -900) .forEach(scoreEntity -> { pointMake.addAndGet(scoreEntity.getS2()); pointTake.addAndGet(scoreEntity.getS1()); }); builder2.score(matchModel.getScores().stream() .map(s -> new Integer[]{s.getS2(), s.getS1()}).toList()); } else { builder2.score(new ArrayList<>()); } builder2.win(matchModel.win() < 0); } builder2.ratio( (pointTake.get() == 0) ? pointMake.get() : (float) pointMake.get() / pointTake.get()); sumPointMake.addAndGet(pointMake.get()); sumPointTake.addAndGet(pointTake.get()); matchs.add(builder2.build()); if (builder2.win) sumW.getAndIncrement(); } builder.totalWin(sumW.get()); builder.pointRatio( (sumPointTake.get() == 0) ? sumPointMake.get() : (float) sumPointMake.get() / sumPointTake.get()); builder.pointMake(sumPointMake.get()); builder.pointTake(sumPointTake.get()); matchs.sort(Comparator.comparing(CombArrayData.MatchsData::poule) .thenComparing(CombArrayData.MatchsData::adv)); builder.matchs(matchs); }) .map(__ -> builder.build()); } @Builder @RegisterForReflection public static record CombsArrayData(int nb_insc, int tt_match, long point, List combs) { @Builder @RegisterForReflection public static record CombsData(String cat, String club, String name, int w, int l, float ratioVictoire, float ratioPoint, int pointMake, int pointTake) { } } @Builder @RegisterForReflection public static record CombArrayData(String name, String club, String cat, int totalWin, float pointRatio, int pointMake, int pointTake, List matchs) { @Builder @RegisterForReflection public static record MatchsData(Date date, String poule, String adv, List score, float ratio, boolean win) { } } public Uni> getClubList(String uuid) { // TODO add guest club return registerRepository.list("competition.uuid = ?1", uuid) .map(registers -> { HashMap registerMap = new HashMap<>(); registers.stream().map(RegisterModel::getClub2).distinct().filter(Objects::nonNull) .forEach(registerClub -> registerMap.put(registerClub.getName(), registerClub.getId())); return registerMap; }); } public Uni getClubArray(String uuid, SecurityCtx securityCtx) { return hasAccess(uuid, securityCtx).chain(cm_register -> getClubArray(uuid, cm_register.getClub2())); } public Uni getClubArrayPublic(String uuid, Long id) { return clubRepository.findById(id).chain(clubModel -> getClubArray(uuid, clubModel)); } public Uni getClubArray(String uuid, ClubModel clubModel) { ClubArrayData.ClubArrayDataBuilder builder = ClubArrayData.builder(); builder.name(clubModel.getName()); return registerRepository.list("competition.uuid = ?1 AND membre.club = ?2", uuid, clubModel) .chain(registers -> matchRepository.list("category.compet.uuid = ?1", uuid) .map(matchModels -> new Pair<>(registers, matchModels))) .map(pair -> { List registers = pair.getKey(); List matchModels = pair.getValue(); builder.nb_insc(registers.size()); AtomicInteger tt_win = new AtomicInteger(0); AtomicInteger tt_match = new AtomicInteger(0); List combData = registers.stream().map(register -> { var builder2 = ClubArrayData.CombData.builder(); AtomicInteger w = new AtomicInteger(0); AtomicInteger l = new AtomicInteger(0); AtomicInteger pointMake = new AtomicInteger(); AtomicInteger pointTake = new AtomicInteger(); matchModels.stream() .filter(m -> m.isEnd() && (register.getMembre().equals(m.getC1_id()) || register.getMembre().equals(m.getC2_id()))) .forEach(matchModel -> { int win = matchModel.win(); if ((register.getMembre().equals(matchModel.getC1_id()) && win > 0) || register.getMembre().equals(matchModel.getC2_id()) && win < 0) { w.getAndIncrement(); } else { l.getAndIncrement(); } matchModel.getScores().stream() .filter(s -> s.getS1() > -900 && s.getS2() > -900) .forEach(score -> { if (register.getMembre().equals(matchModel.getC1_id())) { pointMake.addAndGet(score.getS1()); pointTake.addAndGet(score.getS2()); } else { pointMake.addAndGet(score.getS2()); pointTake.addAndGet(score.getS1()); } }); }); Categorie categorie = register.getCategorie(); if (categorie == null) categorie = register.getMembre().getCategorie(); builder2.cat((categorie == null) ? "---" : categorie.getName(BUNDLE)); builder2.name(register.getName()); builder2.w(w.get()); builder2.l(l.get()); builder2.ratioVictoire((l.get() == 0) ? w.get() : (float) w.get() / l.get()); builder2.pointMake(pointMake.get()); builder2.pointTake(pointTake.get()); builder2.ratioPoint( (pointTake.get() == 0) ? pointMake.get() : (float) pointMake.get() / pointTake.get()); tt_win.addAndGet(w.get()); tt_match.addAndGet(w.get() + l.get()); return builder2.build(); }) .sorted(Comparator.comparing(ClubArrayData.CombData::name)) .toList(); builder.nb_match(tt_match.get()); builder.match_w(tt_win.get()); builder.ratioVictoire((float) combData.stream().filter(c -> c.l + c.w != 0) .mapToDouble(ClubArrayData.CombData::ratioVictoire).average().orElse(0L)); builder.pointMake(combData.stream().mapToInt(ClubArrayData.CombData::pointMake).sum()); builder.pointTake(combData.stream().mapToInt(ClubArrayData.CombData::pointTake).sum()); builder.ratioPoint((float) combData.stream().filter(c -> c.l + c.w != 0) .mapToDouble(ClubArrayData.CombData::ratioPoint).average().orElse(0L)); builder.combs(combData); return builder.build(); }); } @Builder @RegisterForReflection public static record ClubArrayData(String name, int nb_insc, int nb_match, int match_w, float ratioVictoire, float ratioPoint, int pointMake, int pointTake, List combs) { @Builder @RegisterForReflection public static record CombData(String cat, String name, int w, int l, float ratioVictoire, float ratioPoint, int pointMake, int pointTake) { } } private Uni hasAccess(String uuid, SecurityCtx securityCtx) { return registerRepository.find("membre.userId = ?1 AND competition.uuid = ?2", securityCtx.getSubject(), uuid) .firstResult() .invoke(Unchecked.consumer(o -> { if (o == null) throw new DForbiddenException("Access denied"); })); } private Uni hasAccess(Long compId, SecurityCtx securityCtx) { return registerRepository.find("membre.userId = ?1 AND competition.id = ?2", securityCtx.getSubject(), compId) .firstResult() .invoke(Unchecked.consumer(o -> { if (o == null) throw new DForbiddenException("Access denied"); })); } }