diff --git a/assignment/src/main/java/appointmentplanner/APFactory.java b/assignment/src/main/java/appointmentplanner/APFactory.java index 5dd1f71..c56deb5 100644 --- a/assignment/src/main/java/appointmentplanner/APFactory.java +++ b/assignment/src/main/java/appointmentplanner/APFactory.java @@ -28,8 +28,7 @@ public class APFactory implements AbstractAPFactory { @Override public LocalDayPlan createLocalDayPlan(LocalDay day, Instant start, Instant end) { - // TODO Return an instance of your class that implements LocalDayPlan - return null; + return new LocalDayPlanImpl(day, start, end); } @Override diff --git a/assignment/src/main/java/appointmentplanner/AppointmentImpl.java b/assignment/src/main/java/appointmentplanner/AppointmentImpl.java index 2ad57e6..1fc203d 100644 --- a/assignment/src/main/java/appointmentplanner/AppointmentImpl.java +++ b/assignment/src/main/java/appointmentplanner/AppointmentImpl.java @@ -12,6 +12,13 @@ public class AppointmentImpl implements Appointment { private AppointmentRequest request; + public AppointmentImpl(Instant start, AppointmentRequest request) { + this.start = start; + this.request = request; + + this.stop = start.plus(request.duration()); + } + @Override public Instant start() { return start; diff --git a/assignment/src/main/java/appointmentplanner/LocalDayPlanImpl.java b/assignment/src/main/java/appointmentplanner/LocalDayPlanImpl.java index 9e929cc..895ad57 100644 --- a/assignment/src/main/java/appointmentplanner/LocalDayPlanImpl.java +++ b/assignment/src/main/java/appointmentplanner/LocalDayPlanImpl.java @@ -3,6 +3,7 @@ package appointmentplanner; import java.time.Duration; import java.time.Instant; import java.time.LocalTime; +import java.util.Iterator; import java.util.List; import java.util.Optional; import java.util.function.Predicate; @@ -15,11 +16,12 @@ import appointmentplanner.api.LocalDayPlan; import appointmentplanner.api.TimePreference; import appointmentplanner.api.TimeSlot; import appointmentplanner.customlist.CustomLinkedListImpl; +import appointmentplanner.customlist.CustomListToJavaBinding; import appointmentplanner.customlist.api.CustomLinkedList; public class LocalDayPlanImpl implements LocalDayPlan { - private CustomLinkedList timeline = new CustomLinkedListImpl<>(); + private CustomLinkedList timeline = new CustomLinkedListImpl<>(); public LocalDayPlanImpl(LocalDay day, Instant start, Instant end) { this.day = day; @@ -55,8 +57,7 @@ public class LocalDayPlanImpl implements LocalDayPlan { @Override public Optional addAppointment(AppointmentData appointmentData, LocalTime startTime) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'addAppointment'"); + throw new UnsupportedOperationException(); } @Override @@ -67,20 +68,26 @@ public class LocalDayPlanImpl implements LocalDayPlan { @Override public AppointmentRequest removeAppointment(Appointment appointment) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'removeAppointment'"); + Appointment removedItem = timeline.remove(appointment); + return removedItem == null ? null : removedItem.request(); } @Override public List removeAppointments(Predicate filter) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'removeAppointments'"); + + CustomLinkedList removedRequests = new CustomLinkedListImpl<>(); + + for (Appointment appointment : timeline.removeFound(filter)) { + removedRequests.add(appointment.request()); + } + + return new CustomListToJavaBinding<>(removedRequests); + } @Override public List appointments() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'appointments'"); + return new CustomListToJavaBinding(timeline); } @Override @@ -89,28 +96,47 @@ public class LocalDayPlanImpl implements LocalDayPlan { throw new UnsupportedOperationException("Unimplemented method 'findMatchingFreeSlotsOfDuration'"); } + private CustomLinkedList traverseGapsFitting(Duration toFind, CustomLinkedList goodSlots, + Instant startOfBefore, Iterator iterator) { + + boolean hasNext = iterator.hasNext(); + + Appointment nextAppointment = hasNext ? iterator.next() : null; + + TimeSlot possibleFittingSlot = new TimeSlotImpl(hasNext ? nextAppointment.end() : startOfDay(), + startOfBefore == null ? endOfDay() : startOfBefore); + + if (possibleFittingSlot.fits(toFind)) { + goodSlots.add(possibleFittingSlot); + } + + if (!hasNext) { + return goodSlots; + } + + return traverseGapsFitting(toFind, goodSlots, nextAppointment.start(), iterator); + + } + @Override public List findGapsFitting(Duration duration) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'findGapsFitting'"); + return new CustomListToJavaBinding<>( + traverseGapsFitting(duration, new CustomLinkedListImpl<>(), null, timeline.iterator())); } @Override public List findAppointments(Predicate filter) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'findAppointments'"); + return new CustomListToJavaBinding<>(timeline.find(filter)); } @Override public boolean contains(Appointment appointment) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'contains'"); + return timeline.contains(appointment); } @Override public int nrOfAppointments() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'nrOfAppointments'"); + return timeline.size(); } @Override diff --git a/assignment/src/main/java/appointmentplanner/TimeSlotImpl.java b/assignment/src/main/java/appointmentplanner/TimeSlotImpl.java new file mode 100644 index 0000000..15c41cd --- /dev/null +++ b/assignment/src/main/java/appointmentplanner/TimeSlotImpl.java @@ -0,0 +1,27 @@ +package appointmentplanner; + +import java.time.Instant; + +import appointmentplanner.api.TimeSlot; + +public class TimeSlotImpl implements TimeSlot { + + private Instant start; + private Instant end; + + public TimeSlotImpl(Instant start, Instant end) { + this.start = start; + this.end = end; + } + + @Override + public Instant start() { + return start; + } + + @Override + public Instant end() { + return end; + } + +} diff --git a/assignment/src/main/java/appointmentplanner/customlist/CustomLinkedListImpl.java b/assignment/src/main/java/appointmentplanner/customlist/CustomLinkedListImpl.java index 5d482a2..316730d 100644 --- a/assignment/src/main/java/appointmentplanner/customlist/CustomLinkedListImpl.java +++ b/assignment/src/main/java/appointmentplanner/customlist/CustomLinkedListImpl.java @@ -1,6 +1,7 @@ package appointmentplanner.customlist; import java.util.Iterator; +import java.util.function.Predicate; import appointmentplanner.customlist.api.CustomLinkedList; @@ -84,31 +85,32 @@ public class CustomLinkedListImpl implements CustomLinkedList { } @Override - public void remove(T item) { + public T remove(T item) { if (head == null) { - return; + return null; } if (head.getItem().equals(item)) { head = head.getNext(); - return; + return item; } CustomLinkedListNode beforeNode = traverseFind(head, item, ItemPosition.BEFORE); if (beforeNode == null) { - return; + return item; } CustomLinkedListNode nodeToRemove = beforeNode.getNext(); if (beforeNode.getNext() == null) { beforeNode.setNext(null); - return; + return item; } beforeNode.setNext(nodeToRemove.getNext()); + return item; } @Override @@ -172,4 +174,34 @@ public class CustomLinkedListImpl implements CustomLinkedList { return recursiveSizeCalc(this.head, 1); } + private CustomLinkedList traverseFilter(Predicate filter, CustomLinkedListNode node, + CustomLinkedList found) { + + if (node == null) { + return found; + } + + T item = node.getItem(); + + if (filter.test(item)) { + found.add(item); + } + + return traverseFilter(filter, node.getNext(), found); + } + + @Override + public CustomLinkedList find(Predicate filter) { + return traverseFilter(filter, head, new CustomLinkedListImpl<>()); + } + + @Override + public CustomLinkedList removeFound(Predicate filter) { + CustomLinkedList items = find(filter); + for (T item : items) { + remove(item); + } + return items; + } + } diff --git a/assignment/src/main/java/appointmentplanner/customlist/CustomLinkedListIterator.java b/assignment/src/main/java/appointmentplanner/customlist/CustomLinkedListIterator.java index a8d56a7..a688e79 100644 --- a/assignment/src/main/java/appointmentplanner/customlist/CustomLinkedListIterator.java +++ b/assignment/src/main/java/appointmentplanner/customlist/CustomLinkedListIterator.java @@ -17,6 +17,9 @@ public class CustomLinkedListIterator implements Iterator { @Override public boolean hasNext() { + if (lastNode == null) { + return false; + } return lastNode.getNext() != null; } diff --git a/assignment/src/main/java/appointmentplanner/customlist/api/CustomLinkedList.java b/assignment/src/main/java/appointmentplanner/customlist/api/CustomLinkedList.java index 6da82e4..5621bd0 100644 --- a/assignment/src/main/java/appointmentplanner/customlist/api/CustomLinkedList.java +++ b/assignment/src/main/java/appointmentplanner/customlist/api/CustomLinkedList.java @@ -1,11 +1,15 @@ package appointmentplanner.customlist.api; +import java.util.function.Predicate; + public interface CustomLinkedList extends Iterable { void add(T item); - void remove(T item); + T remove(T item); + + CustomLinkedList removeFound(Predicate filter); void insertAfter(T reference, T item); @@ -18,4 +22,6 @@ public interface CustomLinkedList extends Iterable { boolean contains(T item); int size(); + + CustomLinkedList find(Predicate filter); } diff --git a/assignment/src/test/java/appointmentplanner/LocalDayPlanTest.java b/assignment/src/test/java/appointmentplanner/LocalDayPlanTest.java index f93060b..61c52e2 100644 --- a/assignment/src/test/java/appointmentplanner/LocalDayPlanTest.java +++ b/assignment/src/test/java/appointmentplanner/LocalDayPlanTest.java @@ -2,15 +2,19 @@ package appointmentplanner; import static org.assertj.core.api.Assertions.assertThat; +import java.time.Duration; import java.time.Instant; +import java.util.List; import java.util.stream.Stream; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import appointmentplanner.api.LocalDay; import appointmentplanner.api.LocalDayPlan; +import appointmentplanner.api.TimeSlot; public class LocalDayPlanTest { @@ -23,14 +27,14 @@ public class LocalDayPlanTest { @ParameterizedTest @MethodSource("provideLocalDPDataset") - void ldPlanInit_shouldBeSuccessful(LocalDay day, Instant start, Instant end) { + void ldpInit_shouldBeSuccessful(LocalDay day, Instant start, Instant end) { LocalDayPlan plan = new LocalDayPlanImpl(day, start, end); assertThat(plan).isNotNull(); } @ParameterizedTest @MethodSource("provideLocalDPDataset") - void ldPlanGetters_shouldReturnSetValues(LocalDay day, Instant start, Instant end) { + void ldpGetters_shouldReturnSetValues(LocalDay day, Instant start, Instant end) { LocalDayPlan plan = new LocalDayPlanImpl(day, start, end); assertThat(plan.day()).isEqualTo(day); @@ -40,9 +44,18 @@ public class LocalDayPlanTest { @ParameterizedTest @MethodSource("provideLocalDPDataset") - void ldToString_shouldReturnStringContainingLocalDateAndTimeZone(LocalDay day, Instant start, Instant end) { + void ldpToString_shouldReturnStringContainingLocalDateAndTimeZone(LocalDay day, Instant start, Instant end) { LocalDayPlan plan = new LocalDayPlanImpl(day, start, end); assertThat(plan.toString()).contains(day.zone().toString(), day.date().toString()); } + + @Test + void ldpFindMatchingFreeSlotsOnEmptyDay() { + LocalDayPlan plan = TestData.emptyWorkingDay(); + + List freeSlots = plan.findGapsFitting(Duration.ofHours(2)); + + assertThat(freeSlots.size()).isEqualTo(1); + } } diff --git a/assignment/src/test/java/appointmentplanner/customlist/api/CustomLinkedListTest.java b/assignment/src/test/java/appointmentplanner/customlist/api/CustomLinkedListTest.java index bb8bf56..5d931c4 100644 --- a/assignment/src/test/java/appointmentplanner/customlist/api/CustomLinkedListTest.java +++ b/assignment/src/test/java/appointmentplanner/customlist/api/CustomLinkedListTest.java @@ -160,7 +160,21 @@ public class CustomLinkedListTest { } - private CustomLinkedList initPopulatedList(String[] initData) { + @Test + void cllFind_shouldFindCorrectItem() { + CustomLinkedList list = initPopulatedList("Ahoj", "ja", "jsem", "kkt"); + + CustomLinkedList foundItems = list.find(i -> i.length() == 4); + + assertThat(foundItems.size()).isEqualTo(2); + + assertThat(foundItems.contains("Ahoj")).isTrue(); + assertThat(foundItems.contains("jsem")).isTrue(); + assertThat(foundItems.contains("kkt")).isFalse(); + + } + + private CustomLinkedList initPopulatedList(String... initData) { CustomLinkedList list = new CustomLinkedListImpl<>(); Stream.of(initData).forEach(list::add); return list;