diff --git a/walkthroughs/week-5-tdd/project/src/main/java/com/google/sps/FindMeetingQuery.java b/walkthroughs/week-5-tdd/project/src/main/java/com/google/sps/FindMeetingQuery.java index d8fcc66..fee8ab9 100644 --- a/walkthroughs/week-5-tdd/project/src/main/java/com/google/sps/FindMeetingQuery.java +++ b/walkthroughs/week-5-tdd/project/src/main/java/com/google/sps/FindMeetingQuery.java @@ -21,6 +21,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -30,7 +31,10 @@ public Collection query(Collection events, MeetingRequest requ clearUnattendedEvents(eventsSortedByEnd, request.getAttendees()); - return findAvailableTimeSlots(eventsSortedByEnd, request.getDuration()); + Collection options = + findAvailableTimeSlots(eventsSortedByEnd, request.getDuration()); + + return accommodateOptionalAttendees(options, events, request); } private static Collection findAvailableTimeSlots( @@ -86,4 +90,55 @@ private static void clearUnattendedEvents( Collection events, Collection meetingAttendees) { events.removeIf(e -> Collections.disjoint(e.getAttendees(), meetingAttendees)); } + + private static Collection accommodateOptionalAttendees( + Collection currentOptions, Collection events, MeetingRequest request) { + Collection optionalAttendees = request.getOptionalAttendees(); + long minDuration = request.getDuration(); + Collection eventsSortedByEnd = sortEvents(events, TimeRange.ORDER_BY_END); + clearUnattendedEvents(eventsSortedByEnd, optionalAttendees); + if (optionalAttendees.isEmpty() || eventsSortedByEnd.isEmpty()) { + return currentOptions; + } + + if (currentOptions.isEmpty()) { + return findAvailableTimeSlots(eventsSortedByEnd, request.getDuration()); + } + + Collection trimmedOptions = new HashSet<>(); + Iterator slotsIter = currentOptions.iterator(); + TimeRange currentSlot = slotsIter.next(); + Iterator eventIter = eventsSortedByEnd.iterator(); + while (eventIter.hasNext()) { + Event event = eventIter.next(); + boolean useNextSlot = false; + if (currentSlot.overlaps(event.getWhen())) { + useNextSlot = slotsIter.hasNext(); + if (!event.getWhen().contains(currentSlot)) { + int newStartTime = + currentSlot.start() < event.getWhen().start() + ? currentSlot.start() + : event.getWhen().end(); + int newEndTime = + currentSlot.end() < event.getWhen().end() + ? event.getWhen().start() + : currentSlot.end(); + TimeRange possibleSlot = + TimeRange.fromStartEnd(newStartTime, newEndTime, TimeRange.END_OF_DAY == newEndTime); + if (possibleSlot.duration() >= minDuration) { + trimmedOptions.add(possibleSlot); + } + } + } else if (currentSlot.end() < event.getWhen().start()) { + useNextSlot = slotsIter.hasNext(); + trimmedOptions.add(currentSlot); + } + + if (useNextSlot) { + currentSlot = slotsIter.next(); + } + } + + return trimmedOptions.isEmpty() ? currentOptions : trimmedOptions; + } }