|
1 | 1 | package com.ODG.ODG_back.strategy; |
2 | 2 |
|
| 3 | +import com.ODG.ODG_back.domain.Meeting; |
| 4 | +import com.ODG.ODG_back.domain.Midpoint; |
| 5 | +import com.ODG.ODG_back.domain.Participant; |
| 6 | +import com.ODG.ODG_back.domain.RecommendedMidpoint; |
3 | 7 | import com.ODG.ODG_back.dto.midpoint.response.MidpointResponseDto; |
4 | 8 | import com.ODG.ODG_back.external.google.GoogleMatrixApiClient; |
| 9 | +import com.ODG.ODG_back.mapper.MidpointMapper; |
5 | 10 | import com.ODG.ODG_back.repository.MeetingRepository; |
| 11 | +import com.ODG.ODG_back.repository.MidpointRepository; |
6 | 12 | import com.ODG.ODG_back.repository.RecommendedMidpointRepository; |
7 | 13 | import lombok.RequiredArgsConstructor; |
8 | 14 | import org.springframework.stereotype.Component; |
9 | 15 |
|
| 16 | +import java.util.ArrayList; |
| 17 | +import java.util.Comparator; |
10 | 18 | import java.util.List; |
11 | 19 |
|
| 20 | +import static java.util.stream.Collectors.groupingBy; |
| 21 | + |
12 | 22 | @Component("timeMatrixStrategy") |
13 | 23 | @RequiredArgsConstructor |
14 | 24 | public class TimeMatrixMidpointStrategy implements MidpointStrategy { |
15 | 25 |
|
16 | 26 | private final MeetingRepository meetingRepository; |
17 | 27 | private final RecommendedMidpointRepository recommendedMidpointRepository; |
18 | 28 | private final GoogleMatrixApiClient matrixApiClient; // 소요 시간 API 요청 |
| 29 | + private final MidpointRepository midpointRepository; |
| 30 | + private final MidpointMapper midpointMapper; |
19 | 31 |
|
20 | 32 | @Override |
21 | | - public List<MidpointResponseDto> calculateMidpoints(String inviteCode) { |
22 | | - return List.of(); |
| 33 | + public MidpointResponseDto calculateMidpoints(String inviteCode) { |
| 34 | + |
| 35 | + Meeting meeting = meetingRepository.findByInviteCode(inviteCode); |
| 36 | + List<Participant> participants = meeting.getParticipants(); |
| 37 | + List<Midpoint> allMidpoints = midpointRepository.findAll(); |
| 38 | + |
| 39 | + int[][] timeMatrix = buildTimeMatrix(participants, allMidpoints); |
| 40 | + MidpointScore best = scoreMidpoints(timeMatrix, allMidpoints, participants.size()); |
| 41 | + |
| 42 | + saveRecommendedMidpoint(best, meeting); |
| 43 | + return midpointMapper.toDto(best.midpoint()); |
| 44 | + } |
| 45 | + |
| 46 | + private int[][] buildTimeMatrix(List<Participant> participants, List<Midpoint> allMidpoints) { |
| 47 | + |
| 48 | + List <String> destinations = allMidpoints.stream() |
| 49 | + .map(m -> m.getLatitude() + ", " + m.getLongitude()) |
| 50 | + .toList(); |
| 51 | + int[][] timeMatrix = new int[participants.size()][destinations.size()]; |
| 52 | + |
| 53 | + var grouped = participants.stream() |
| 54 | + .collect(groupingBy(Participant::getTransport)); |
| 55 | + int rowIndex = 0; |
| 56 | + |
| 57 | + for (var entry: grouped.entrySet()) { |
| 58 | + List<Participant> group = entry.getValue(); |
| 59 | + List<String> origins = group.stream() |
| 60 | + .map(p -> p.getLatitude() + ", " + p.getLongitude()) |
| 61 | + .toList(); |
| 62 | + |
| 63 | + int[][] groupMatrix = matrixApiClient.getTimeMatrix(origins, destinations, entry.getKey()); |
| 64 | + |
| 65 | + for (int i = 0; i < group.size(); i++) { |
| 66 | + timeMatrix[rowIndex++] = groupMatrix[i]; |
| 67 | + } |
| 68 | + } |
| 69 | + return timeMatrix; |
| 70 | + } |
| 71 | + |
| 72 | + private MidpointScore scoreMidpoints(int[][] timeMatrix, List<Midpoint> midpoints, int numParticipants) { |
| 73 | + List<MidpointScore> scored = new ArrayList<>(); |
| 74 | + |
| 75 | + for (int j = 0; j < midpoints.size(); j++) { |
| 76 | + int sum = 0; |
| 77 | + for (int i = 0; i < numParticipants; i++) { |
| 78 | + sum += timeMatrix[i][j]; |
| 79 | + } |
| 80 | + double avg = sum / (double) numParticipants; |
| 81 | + |
| 82 | + double totalDeviation = 0; |
| 83 | + for (int i = 0; i < numParticipants; i++) { |
| 84 | + totalDeviation += Math.abs(timeMatrix[i][j] - avg); |
| 85 | + } |
| 86 | + |
| 87 | + scored.add(new MidpointScore(midpoints.get(j), avg, totalDeviation )); |
| 88 | + } |
| 89 | + |
| 90 | + return scored.stream() |
| 91 | + .sorted(Comparator.comparingDouble(MidpointScore::avg) |
| 92 | + .thenComparingDouble(MidpointScore::totalDeviation)) |
| 93 | + .findFirst() |
| 94 | + .orElseThrow(() -> new RuntimeException("No MIDPOINT found")); |
23 | 95 | } |
| 96 | + |
| 97 | + private void saveRecommendedMidpoint(MidpointScore best, Meeting meeting) { |
| 98 | + RecommendedMidpoint recommended = new RecommendedMidpoint( |
| 99 | + null, |
| 100 | + best.avg(), |
| 101 | + 1, |
| 102 | + java.time.LocalDateTime.now(), |
| 103 | + meeting, |
| 104 | + best.midpoint() |
| 105 | + ); |
| 106 | + recommendedMidpointRepository.save(recommended); |
| 107 | + } |
| 108 | + |
| 109 | + private record MidpointScore(Midpoint midpoint, double avg, double totalDeviation) {} |
24 | 110 | } |
0 commit comments