Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,44 +39,91 @@ public int compare(Event a, Event b) {

Collections.sort(eventsArray, compareByEventStart);

Collection<String> requestedEventAttendees = request.getAttendees();

// collection of available meeting times
Collection<TimeRange> openTimes = new ArrayList<>();
Collection<TimeRange> openTimesRequiredAttendees = new ArrayList<>();
Collection<TimeRange> openTimesOptionalAttendees = new ArrayList<>();

// keep track of when the next block of free time starts for requried
// attendees and optional attendees
int requiredAttendeesStart = TimeRange.START_OF_DAY;
int optionalAttendeesStart = TimeRange.START_OF_DAY;

// initial available time: the entire day
int start = TimeRange.START_OF_DAY;
int end = TimeRange.END_OF_DAY;

for (Event event: eventsArray) {
TimeRange tryTime = TimeRange.fromStartEnd(start, end, true);
// try largest block of free time
TimeRange tryTime = TimeRange.fromStartEnd(requiredAttendeesStart, end, true);

if (tryTime.overlaps(event.getWhen())) {
// get lists of event attendees
Collection<String> requestedEventAttendees = request.getAttendees();
Set<String> scheduledEventAttendees = event.getAttendees();

for (String attendee: requestedEventAttendees) {
// check for overlapping attendees
if (scheduledEventAttendees.contains(attendee)) {
int newEnd = event.getWhen().start();

// see if meeting can be scheduled between start and conflicting event
if (newEnd - start >= request.getDuration()) {
openTimes.add(TimeRange.fromStartEnd(start, newEnd, false));
// get lists of the current event attendees
Set<String> eventAttendees = event.getAttendees();


if (checkConflictingAttendees(requestedEventAttendees, eventAttendees)) {
int endOfFreeTime = event.getWhen().start();
if (endOfFreeTime - requiredAttendeesStart >= request.getDuration()) {
openTimesRequiredAttendees.add(TimeRange.fromStartEnd(requiredAttendeesStart, endOfFreeTime, false));
}

if (endOfFreeTime - optionalAttendeesStart >= request.getDuration()) {
openTimesOptionalAttendees.add(TimeRange.fromStartEnd(optionalAttendeesStart, endOfFreeTime, false));
}

requiredAttendeesStart = event.getWhen().end();

if (optionalAttendeesStart < event.getWhen().end()) {
optionalAttendeesStart = event.getWhen().end();
}

} else {
// required attendees are all free, check if optional attendees are also free
Collection<String> optionalEventAttendees = request.getOptionalAttendees();
if (checkConflictingAttendees(optionalEventAttendees, eventAttendees)) {
int endOfFreeTime = event.getWhen().start();
if (endOfFreeTime - optionalAttendeesStart >= request.getDuration()) {
openTimesOptionalAttendees.add(TimeRange.fromStartEnd(optionalAttendeesStart, endOfFreeTime, false));
}

start = event.getWhen().end();
break;
optionalAttendeesStart = event.getWhen().end();
}

}

}
}

// see if meeting can be scheduled from start to end of day
if (end - start >= request.getDuration()) {
openTimes.add(TimeRange.fromStartEnd(start, end, true));
if (end - requiredAttendeesStart >= request.getDuration()) {
openTimesRequiredAttendees.add(TimeRange.fromStartEnd(requiredAttendeesStart, end, true));
}

if (end - optionalAttendeesStart >= request.getDuration()) {
openTimesOptionalAttendees.add(TimeRange.fromStartEnd(optionalAttendeesStart, end, true));
}

if (openTimesOptionalAttendees.isEmpty()) {
if (requestedEventAttendees.isEmpty()) {
return new ArrayList<>();
}
return openTimesRequiredAttendees;
} else {
return openTimesOptionalAttendees;
}
}

public boolean checkConflictingAttendees(Collection<String> eventAttendees,
Set<String> requestedAttendees) {

return openTimes;
for (String attendee: eventAttendees) {
if (requestedAttendees.contains(attendee)) {
return true;
}
}

return false;
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public final class FindMeetingQueryTest {
// Some people that we can use in our tests.
private static final String PERSON_A = "Person A";
private static final String PERSON_B = "Person B";
private static final String PERSON_C = "Person C";

// All dates are the first day of the year 2020.
private static final int TIME_0800AM = TimeRange.getTimeInMinutes(8, 0);
Expand Down Expand Up @@ -270,5 +271,188 @@ public void notEnoughRoom() {

Assert.assertEquals(expected, actual);
}

@Test
public void optionalPersonAllDayEvent() {
// Have each person have different events and one optional attendee who is
// busy the entire day. We should see three options because the optional
// attendee cannot attend any other event so only consider other people
//
// Optional: |--------------C--------------|
// Events : |--A--| |--B--|
// Day : |-----------------------------|
// Options : |--1--| |--2--| |--3--|

Collection<Event> events = Arrays.asList(
new Event("Event 1", TimeRange.fromStartDuration(TIME_0800AM, DURATION_30_MINUTES),
Arrays.asList(PERSON_A)),
new Event("Event 2", TimeRange.fromStartDuration(TIME_0900AM, DURATION_30_MINUTES),
Arrays.asList(PERSON_B)),
new Event("Event 3",
TimeRange.fromStartDuration(TimeRange.START_OF_DAY, TimeRange.END_OF_DAY),
Arrays.asList(PERSON_C)));

MeetingRequest request =
new MeetingRequest(Arrays.asList(PERSON_A, PERSON_B), DURATION_30_MINUTES);

request.addOptionalAttendee(PERSON_C);

Collection<TimeRange> actual = query.query(events, request);
Collection<TimeRange> expected =
Arrays.asList(TimeRange.fromStartEnd(TimeRange.START_OF_DAY, TIME_0800AM, false),
TimeRange.fromStartEnd(TIME_0830AM, TIME_0900AM, false),
TimeRange.fromStartEnd(TIME_0930AM, TimeRange.END_OF_DAY, true));

Assert.assertEquals(expected, actual);
}

@Test
public void optionalPersonOneEvent() {
// Have each person have different events and one optional attendee
// overlapping with one of the free times. We should see two options because
// all three can attend at two times
//
// Optional : |-----C-----|
// Events : |--A--| |--B--|
// Day : |-----------------------------|
// Options : |--1--| |--2--|

Collection<Event> events = Arrays.asList(
new Event("Event 1", TimeRange.fromStartDuration(TIME_0800AM, DURATION_30_MINUTES),
Arrays.asList(PERSON_A)),
new Event("Event 2", TimeRange.fromStartDuration(TIME_0900AM, DURATION_30_MINUTES),
Arrays.asList(PERSON_B)),
new Event("Event 3",
TimeRange.fromStartEnd(TIME_0800AM, TIME_0900AM, false),
Arrays.asList(PERSON_C)));

MeetingRequest request =
new MeetingRequest(Arrays.asList(PERSON_A, PERSON_B), DURATION_30_MINUTES);

request.addOptionalAttendee(PERSON_C);

Collection<TimeRange> actual = query.query(events, request);
Collection<TimeRange> expected =
Arrays.asList(TimeRange.fromStartEnd(TimeRange.START_OF_DAY, TIME_0800AM, false),
TimeRange.fromStartEnd(TIME_0930AM, TimeRange.END_OF_DAY, true));

Assert.assertEquals(expected, actual);
}


@Test
public void justEnoughRoomWithoutOptional() {
// Have one person and one optional attendee, but make it so that there is
// just enough room at one point in the day to
// have the meeting if the optional attendee does not attend
//
// Optional: |-B-|
// Events : |--A--| |----A----|
// Day : |---------------------|
// Options : |-----|

Collection<Event> events = Arrays.asList(
new Event("Event 1", TimeRange.fromStartEnd(TimeRange.START_OF_DAY, TIME_0830AM, false),
Arrays.asList(PERSON_A)),
new Event("Event 2", TimeRange.fromStartEnd(TIME_0900AM, TimeRange.END_OF_DAY, true),
Arrays.asList(PERSON_A)),
new Event("Event 3", TimeRange.fromStartDuration(TIME_0830AM, 15),
Arrays.asList(PERSON_B)));

MeetingRequest request = new MeetingRequest(Arrays.asList(PERSON_A), DURATION_30_MINUTES);

request.addOptionalAttendee(PERSON_B);

Collection<TimeRange> actual = query.query(events, request);
Collection<TimeRange> expected =
Arrays.asList(TimeRange.fromStartDuration(TIME_0830AM, DURATION_30_MINUTES));

Assert.assertEquals(expected, actual);
}


@Test
public void onlyOptionalWithGaps() {
// Have only optional attendees with gaps in their schedules
//
// Optional: |--A--| |-A-||-B-| |-B-|
// Day : |------------------------------|
// Options : |--1--| |--2--|

Collection<Event> events = Arrays.asList(
new Event("Event 1", TimeRange.fromStartEnd(TimeRange.START_OF_DAY, TIME_0830AM, false),
Arrays.asList(PERSON_A)),
new Event("Event 2", TimeRange.fromStartEnd(TIME_0900AM, TIME_1100AM, false),
Arrays.asList(PERSON_A)),
new Event("Event 3", TimeRange.fromStartDuration(TIME_1100AM, 30),
Arrays.asList(PERSON_B)),
new Event("Event 4", TimeRange.fromStartEnd(TimeRange.END_OF_DAY - 30, TimeRange.END_OF_DAY, true),
Arrays.asList(PERSON_B)));

MeetingRequest request = new MeetingRequest(Arrays.asList(), DURATION_30_MINUTES);

request.addOptionalAttendee(PERSON_A);
request.addOptionalAttendee(PERSON_B);

Collection<TimeRange> actual = query.query(events, request);
Collection<TimeRange> expected =
Arrays.asList(TimeRange.fromStartDuration(TIME_0830AM, DURATION_30_MINUTES),
TimeRange.fromStartEnd(TIME_1100AM + 30, TimeRange.END_OF_DAY - 30, false));

Assert.assertEquals(expected, actual);
}

@Test
public void onlyOptionalWithoutGaps() {
// Have only optional attendees with no gaps in their schedules
//
// Optional: |----A----||-------B-------|
// Day : |--------------------------|
// Options :

Collection<Event> events = Arrays.asList(
new Event("Event 1", TimeRange.fromStartEnd(TimeRange.START_OF_DAY, TIME_1100AM, false),
Arrays.asList(PERSON_A)),
new Event("Event 2", TimeRange.fromStartEnd(TIME_1100AM, TimeRange.END_OF_DAY, true),
Arrays.asList(PERSON_B)));

MeetingRequest request = new MeetingRequest(Arrays.asList(), DURATION_30_MINUTES);

request.addOptionalAttendee(PERSON_A);
request.addOptionalAttendee(PERSON_B);

Collection<TimeRange> actual = query.query(events, request);
Collection<TimeRange> expected =
Arrays.asList();

Assert.assertEquals(expected, actual);
}

@Test
public void requiredFreeAllDayButNotOptional() {
// Have only optional attendees with no gaps in their schedules
//
// Optional: |---B---|
// Events :
// Day : |-------------------------|
// Options :

Collection<Event> events = Arrays.asList(
new Event("Event 2", TimeRange.fromStartEnd(TIME_0900AM, TIME_1100AM, false),
Arrays.asList(PERSON_B)));

MeetingRequest request = new MeetingRequest(Arrays.asList(PERSON_A), DURATION_30_MINUTES);

request.addOptionalAttendee(PERSON_B);

Collection<TimeRange> actual = query.query(events, request);
Collection<TimeRange> expected =
Arrays.asList(TimeRange.fromStartEnd(TimeRange.START_OF_DAY, TIME_0900AM, false),
TimeRange.fromStartEnd(TIME_1100AM, TimeRange.END_OF_DAY, true));

Assert.assertEquals(expected, actual);
}
}