From 5f51b4512023363e13b97d6b8abdca17e39a0cfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20P=C5=99ib=C3=ADk?= Date: Thu, 23 Oct 2025 21:16:34 +0200 Subject: [PATCH 1/8] test: cll find item --- .../customlist/api/CustomLinkedListTest.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) 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; From 53657608ba65b4be933fe19bc310573c8862933b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20P=C5=99ib=C3=ADk?= Date: Thu, 23 Oct 2025 21:17:08 +0200 Subject: [PATCH 2/8] impl: cll find item --- .../appointmentplanner/customlist/api/CustomLinkedList.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/assignment/src/main/java/appointmentplanner/customlist/api/CustomLinkedList.java b/assignment/src/main/java/appointmentplanner/customlist/api/CustomLinkedList.java index 6da82e4..2423c9a 100644 --- a/assignment/src/main/java/appointmentplanner/customlist/api/CustomLinkedList.java +++ b/assignment/src/main/java/appointmentplanner/customlist/api/CustomLinkedList.java @@ -1,6 +1,8 @@ package appointmentplanner.customlist.api; +import java.util.function.Predicate; + public interface CustomLinkedList extends Iterable { void add(T item); @@ -18,4 +20,6 @@ public interface CustomLinkedList extends Iterable { boolean contains(T item); int size(); + + CustomLinkedList find(Predicate filter); } From 542c0932228b61914010779db639f2a7cecc0a16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20P=C5=99ib=C3=ADk?= Date: Thu, 23 Oct 2025 21:17:43 +0200 Subject: [PATCH 3/8] impl: cll remove items with filter --- .../appointmentplanner/customlist/api/CustomLinkedList.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/assignment/src/main/java/appointmentplanner/customlist/api/CustomLinkedList.java b/assignment/src/main/java/appointmentplanner/customlist/api/CustomLinkedList.java index 2423c9a..5621bd0 100644 --- a/assignment/src/main/java/appointmentplanner/customlist/api/CustomLinkedList.java +++ b/assignment/src/main/java/appointmentplanner/customlist/api/CustomLinkedList.java @@ -7,7 +7,9 @@ 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); From 335854583e8fea9ab54c16cbe9e9fbe2802adad4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20P=C5=99ib=C3=ADk?= Date: Thu, 23 Oct 2025 21:18:42 +0200 Subject: [PATCH 4/8] test: ldp fin matching free slot on empty day --- .../test/java/appointmentplanner/LocalDayPlanTest.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/assignment/src/test/java/appointmentplanner/LocalDayPlanTest.java b/assignment/src/test/java/appointmentplanner/LocalDayPlanTest.java index f93060b..3af4fc5 100644 --- a/assignment/src/test/java/appointmentplanner/LocalDayPlanTest.java +++ b/assignment/src/test/java/appointmentplanner/LocalDayPlanTest.java @@ -45,4 +45,13 @@ public class LocalDayPlanTest { 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); + } } From 427e963cac7aaf3790ebcef1417dabf11b35233a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20P=C5=99ib=C3=ADk?= Date: Thu, 23 Oct 2025 21:18:52 +0200 Subject: [PATCH 5/8] impl: time slot --- .../java/appointmentplanner/TimeSlotImpl.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 assignment/src/main/java/appointmentplanner/TimeSlotImpl.java 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; + } + +} From 2df2500b778db1893f46f364338e26bf344e6f37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20P=C5=99ib=C3=ADk?= Date: Thu, 23 Oct 2025 21:19:32 +0200 Subject: [PATCH 6/8] impl: ldp find gaps fitting --- .../appointmentplanner/LocalDayPlanImpl.java | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/assignment/src/main/java/appointmentplanner/LocalDayPlanImpl.java b/assignment/src/main/java/appointmentplanner/LocalDayPlanImpl.java index 9e929cc..fb0be1c 100644 --- a/assignment/src/main/java/appointmentplanner/LocalDayPlanImpl.java +++ b/assignment/src/main/java/appointmentplanner/LocalDayPlanImpl.java @@ -89,10 +89,32 @@ 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 From ff10df17c384dd5e0a8cd70cafdf2af4c72aa51d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20P=C5=99ib=C3=ADk?= Date: Thu, 23 Oct 2025 21:20:12 +0200 Subject: [PATCH 7/8] impl: ldp remove aps using predicate --- .../test/java/appointmentplanner/LocalDayPlanTest.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/assignment/src/test/java/appointmentplanner/LocalDayPlanTest.java b/assignment/src/test/java/appointmentplanner/LocalDayPlanTest.java index 3af4fc5..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,7 +44,7 @@ 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()); From 457804d2517cdfde360a402ccf34eff8f6d70470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20P=C5=99ib=C3=ADk?= Date: Thu, 23 Oct 2025 21:20:33 +0200 Subject: [PATCH 8/8] impl: ldp remove ap using predicate --- .../java/appointmentplanner/APFactory.java | 3 +- .../appointmentplanner/AppointmentImpl.java | 7 ++++ .../appointmentplanner/LocalDayPlanImpl.java | 34 ++++++++------- .../customlist/CustomLinkedListImpl.java | 42 ++++++++++++++++--- .../customlist/CustomLinkedListIterator.java | 3 ++ 5 files changed, 67 insertions(+), 22 deletions(-) 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 fb0be1c..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 @@ -119,20 +126,17 @@ public class LocalDayPlanImpl implements LocalDayPlan { @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/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; }