Compare commits

..

11 Commits

Author SHA1 Message Date
Václav Přibík
886de3df55 feat: remove list to java binding 2025-10-24 13:08:49 +02:00
Václav Přibík
145682e44f impl: cll to array list 2025-10-24 13:05:35 +02:00
Václav Přibík
e28e179e2b test: cll to array list 2025-10-24 13:05:29 +02:00
Václav Přibík
6b7eda244c feat: cll to array lsit 2025-10-24 13:05:17 +02:00
Václav Přibík
c9523a9a23 Merge branch 'dev' 2025-10-23 21:20:59 +02:00
Václav Přibík
457804d251 impl: ldp remove ap using predicate 2025-10-23 21:20:33 +02:00
Václav Přibík
ff10df17c3 impl: ldp remove aps using predicate 2025-10-23 21:20:12 +02:00
Václav Přibík
2df2500b77 impl: ldp find gaps fitting 2025-10-23 21:19:32 +02:00
Václav Přibík
427e963cac impl: time slot 2025-10-23 21:18:52 +02:00
Václav Přibík
335854583e test: ldp fin matching free slot on empty day 2025-10-23 21:18:42 +02:00
xGl0ck
26e9858ca3 Merge pull request #1 from FontysVenlo/dev
Dev
2025-10-18 15:13:13 +02:00
10 changed files with 165 additions and 184 deletions

View File

@@ -28,8 +28,7 @@ public class APFactory implements AbstractAPFactory {
@Override @Override
public LocalDayPlan createLocalDayPlan(LocalDay day, Instant start, Instant end) { public LocalDayPlan createLocalDayPlan(LocalDay day, Instant start, Instant end) {
// TODO Return an instance of your class that implements LocalDayPlan return new LocalDayPlanImpl(day, start, end);
return null;
} }
@Override @Override

View File

@@ -12,6 +12,13 @@ public class AppointmentImpl implements Appointment {
private AppointmentRequest request; private AppointmentRequest request;
public AppointmentImpl(Instant start, AppointmentRequest request) {
this.start = start;
this.request = request;
this.stop = start.plus(request.duration());
}
@Override @Override
public Instant start() { public Instant start() {
return start; return start;

View File

@@ -3,6 +3,7 @@ package appointmentplanner;
import java.time.Duration; import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.time.LocalTime; import java.time.LocalTime;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.function.Predicate; import java.util.function.Predicate;
@@ -19,7 +20,7 @@ import appointmentplanner.customlist.api.CustomLinkedList;
public class LocalDayPlanImpl implements LocalDayPlan { public class LocalDayPlanImpl implements LocalDayPlan {
private CustomLinkedList<AppointmentImpl> timeline = new CustomLinkedListImpl<>(); private CustomLinkedList<Appointment> timeline = new CustomLinkedListImpl<>();
public LocalDayPlanImpl(LocalDay day, Instant start, Instant end) { public LocalDayPlanImpl(LocalDay day, Instant start, Instant end) {
this.day = day; this.day = day;
@@ -55,8 +56,7 @@ public class LocalDayPlanImpl implements LocalDayPlan {
@Override @Override
public Optional<Appointment> addAppointment(AppointmentData appointmentData, LocalTime startTime) { public Optional<Appointment> addAppointment(AppointmentData appointmentData, LocalTime startTime) {
// TODO Auto-generated method stub throw new UnsupportedOperationException();
throw new UnsupportedOperationException("Unimplemented method 'addAppointment'");
} }
@Override @Override
@@ -67,20 +67,25 @@ public class LocalDayPlanImpl implements LocalDayPlan {
@Override @Override
public AppointmentRequest removeAppointment(Appointment appointment) { public AppointmentRequest removeAppointment(Appointment appointment) {
// TODO Auto-generated method stub Appointment removedItem = timeline.remove(appointment);
throw new UnsupportedOperationException("Unimplemented method 'removeAppointment'"); return removedItem == null ? null : removedItem.request();
} }
@Override @Override
public List<AppointmentRequest> removeAppointments(Predicate<Appointment> filter) { public List<AppointmentRequest> removeAppointments(Predicate<Appointment> filter) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'removeAppointments'"); CustomLinkedList<AppointmentRequest> removedRequests = new CustomLinkedListImpl<>();
for (Appointment appointment : timeline.removeFound(filter)) {
removedRequests.add(appointment.request());
}
return removedRequests.toArrayList();
} }
@Override @Override
public List<Appointment> appointments() { public List<Appointment> appointments() {
// TODO Auto-generated method stub return timeline.toArrayList();
throw new UnsupportedOperationException("Unimplemented method 'appointments'");
} }
@Override @Override
@@ -89,28 +94,46 @@ public class LocalDayPlanImpl implements LocalDayPlan {
throw new UnsupportedOperationException("Unimplemented method 'findMatchingFreeSlotsOfDuration'"); throw new UnsupportedOperationException("Unimplemented method 'findMatchingFreeSlotsOfDuration'");
} }
private CustomLinkedList<TimeSlot> traverseGapsFitting(Duration toFind, CustomLinkedList<TimeSlot> goodSlots,
Instant startOfBefore, Iterator<Appointment> 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 @Override
public List<TimeSlot> findGapsFitting(Duration duration) { public List<TimeSlot> findGapsFitting(Duration duration) {
// TODO Auto-generated method stub return traverseGapsFitting(duration, new CustomLinkedListImpl<>(), null, timeline.iterator()).toArrayList();
throw new UnsupportedOperationException("Unimplemented method 'findGapsFitting'");
} }
@Override @Override
public List<Appointment> findAppointments(Predicate<Appointment> filter) { public List<Appointment> findAppointments(Predicate<Appointment> filter) {
// TODO Auto-generated method stub return timeline.find(filter).toArrayList();
throw new UnsupportedOperationException("Unimplemented method 'findAppointments'");
} }
@Override @Override
public boolean contains(Appointment appointment) { public boolean contains(Appointment appointment) {
// TODO Auto-generated method stub return timeline.contains(appointment);
throw new UnsupportedOperationException("Unimplemented method 'contains'");
} }
@Override @Override
public int nrOfAppointments() { public int nrOfAppointments() {
// TODO Auto-generated method stub return timeline.size();
throw new UnsupportedOperationException("Unimplemented method 'nrOfAppointments'");
} }
@Override @Override

View File

@@ -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;
}
}

View File

@@ -1,6 +1,8 @@
package appointmentplanner.customlist; package appointmentplanner.customlist;
import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.function.Predicate;
import appointmentplanner.customlist.api.CustomLinkedList; import appointmentplanner.customlist.api.CustomLinkedList;
@@ -84,31 +86,32 @@ public class CustomLinkedListImpl<T> implements CustomLinkedList<T> {
} }
@Override @Override
public void remove(T item) { public T remove(T item) {
if (head == null) { if (head == null) {
return; return null;
} }
if (head.getItem().equals(item)) { if (head.getItem().equals(item)) {
head = head.getNext(); head = head.getNext();
return; return item;
} }
CustomLinkedListNode<T> beforeNode = traverseFind(head, item, ItemPosition.BEFORE); CustomLinkedListNode<T> beforeNode = traverseFind(head, item, ItemPosition.BEFORE);
if (beforeNode == null) { if (beforeNode == null) {
return; return item;
} }
CustomLinkedListNode<T> nodeToRemove = beforeNode.getNext(); CustomLinkedListNode<T> nodeToRemove = beforeNode.getNext();
if (beforeNode.getNext() == null) { if (beforeNode.getNext() == null) {
beforeNode.setNext(null); beforeNode.setNext(null);
return; return item;
} }
beforeNode.setNext(nodeToRemove.getNext()); beforeNode.setNext(nodeToRemove.getNext());
return item;
} }
@Override @Override
@@ -120,6 +123,7 @@ public class CustomLinkedListImpl<T> implements CustomLinkedList<T> {
} }
CustomLinkedListNode<T> nodeBefore = traverseFind(head, reference, ItemPosition.BEFORE); CustomLinkedListNode<T> nodeBefore = traverseFind(head, reference, ItemPosition.BEFORE);
CustomLinkedListNode<T> nodeToInsert = new CustomLinkedListNode<>(nodeBefore.getNext(), item); CustomLinkedListNode<T> nodeToInsert = new CustomLinkedListNode<>(nodeBefore.getNext(), item);
nodeBefore.setNext(nodeToInsert); nodeBefore.setNext(nodeToInsert);
} }
@@ -172,4 +176,48 @@ public class CustomLinkedListImpl<T> implements CustomLinkedList<T> {
return recursiveSizeCalc(this.head, 1); return recursiveSizeCalc(this.head, 1);
} }
private CustomLinkedList<T> traverseFilter(Predicate<T> filter, CustomLinkedListNode<T> node,
CustomLinkedList<T> 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<T> find(Predicate<T> filter) {
return traverseFilter(filter, head, new CustomLinkedListImpl<>());
}
@Override
public CustomLinkedList<T> removeFound(Predicate<T> filter) {
CustomLinkedList<T> items = find(filter);
for (T item : items) {
remove(item);
}
return items;
}
private ArrayList<T> mapToArrayList(CustomLinkedListNode<T> node, ArrayList<T> list) {
if (node == null) {
return list;
}
mapToArrayList(node.getNext(), list);
list.add(node.getItem());
return list;
}
@Override
public ArrayList<T> toArrayList() {
return mapToArrayList(head, new ArrayList<>());
}
} }

View File

@@ -17,6 +17,9 @@ public class CustomLinkedListIterator<T> implements Iterator<T> {
@Override @Override
public boolean hasNext() { public boolean hasNext() {
if (lastNode == null) {
return false;
}
return lastNode.getNext() != null; return lastNode.getNext() != null;
} }

View File

@@ -1,157 +0,0 @@
package appointmentplanner.customlist;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import appointmentplanner.customlist.api.*;
public class CustomListToJavaBinding<T> implements List<T> {
private CustomLinkedList<T> list;
public CustomListToJavaBinding(CustomLinkedList<T> list) {
this.list = list;
}
@Override
public boolean add(T arg0) {
list.add(arg0);
return true;
}
@Override
public void add(int arg0, T arg1) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Cannot add to exact index in linked list");
}
@Override
public boolean addAll(Collection<? extends T> c) {
c.stream().forEach(list::add);
return true;
}
@Override
public boolean addAll(int index, Collection<? extends T> c) {
throw new UnsupportedOperationException("Cannot add to exact index in linked list");
}
@Override
public void clear() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'clear'");
}
@Override
public boolean containsAll(Collection<?> c) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'containsAll'");
}
@Override
public T get(int index) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'get'");
}
@Override
public int indexOf(Object o) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'indexOf'");
}
@Override
public boolean isEmpty() {
return list.size() == 0;
}
@Override
public Iterator<T> iterator() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'iterator'");
}
@Override
public int lastIndexOf(Object o) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'lastIndexOf'");
}
@Override
public ListIterator<T> listIterator() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'listIterator'");
}
@Override
public ListIterator<T> listIterator(int index) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'listIterator'");
}
@Override
public boolean remove(Object o) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'remove'");
}
@Override
public T remove(int index) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'remove'");
}
@Override
public boolean removeAll(Collection<?> c) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'removeAll'");
}
@Override
public boolean retainAll(Collection<?> c) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'retainAll'");
}
@Override
public T set(int arg0, T arg1) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'set'");
}
@Override
public int size() {
return list.size();
}
@Override
public List<T> subList(int fromIndex, int toIndex) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'subList'");
}
@Override
public Object[] toArray() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'toArray'");
}
@Override
public <T> T[] toArray(T[] arg0) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'toArray'");
}
@Override
public boolean contains(Object o) {
try {
T bal = (T) o;
return list.contains(bal);
} catch (Exception e) {
return false;
}
}
}

View File

@@ -1,6 +1,7 @@
package appointmentplanner.customlist.api; package appointmentplanner.customlist.api;
import java.util.ArrayList;
import java.util.function.Predicate; import java.util.function.Predicate;
public interface CustomLinkedList<T> extends Iterable<T> { public interface CustomLinkedList<T> extends Iterable<T> {
@@ -24,4 +25,6 @@ public interface CustomLinkedList<T> extends Iterable<T> {
int size(); int size();
CustomLinkedList<T> find(Predicate<T> filter); CustomLinkedList<T> find(Predicate<T> filter);
ArrayList<T> toArrayList();
} }

View File

@@ -2,15 +2,19 @@ package appointmentplanner;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.util.List;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import appointmentplanner.api.LocalDay; import appointmentplanner.api.LocalDay;
import appointmentplanner.api.LocalDayPlan; import appointmentplanner.api.LocalDayPlan;
import appointmentplanner.api.TimeSlot;
public class LocalDayPlanTest { public class LocalDayPlanTest {
@@ -23,14 +27,14 @@ public class LocalDayPlanTest {
@ParameterizedTest @ParameterizedTest
@MethodSource("provideLocalDPDataset") @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); LocalDayPlan plan = new LocalDayPlanImpl(day, start, end);
assertThat(plan).isNotNull(); assertThat(plan).isNotNull();
} }
@ParameterizedTest @ParameterizedTest
@MethodSource("provideLocalDPDataset") @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); LocalDayPlan plan = new LocalDayPlanImpl(day, start, end);
assertThat(plan.day()).isEqualTo(day); assertThat(plan.day()).isEqualTo(day);
@@ -40,9 +44,18 @@ public class LocalDayPlanTest {
@ParameterizedTest @ParameterizedTest
@MethodSource("provideLocalDPDataset") @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); LocalDayPlan plan = new LocalDayPlanImpl(day, start, end);
assertThat(plan.toString()).contains(day.zone().toString(), day.date().toString()); assertThat(plan.toString()).contains(day.zone().toString(), day.date().toString());
} }
@Test
void ldpFindMatchingFreeSlotsOnEmptyDay() {
LocalDayPlan plan = TestData.emptyWorkingDay();
List<TimeSlot> freeSlots = plan.findGapsFitting(Duration.ofHours(2));
assertThat(freeSlots.size()).isEqualTo(1);
}
} }

View File

@@ -2,6 +2,7 @@ package appointmentplanner.customlist.api;
import static org.assertj.core.api.Assertions.*; import static org.assertj.core.api.Assertions.*;
import java.util.ArrayList;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@@ -174,6 +175,20 @@ public class CustomLinkedListTest {
} }
@Test
void cllToArrayList() {
String[] items = new String[] { "Uz", "toho", "mam", "dost" };
CustomLinkedList<String> ll = initPopulatedList(items);
ArrayList<String> convertedAl = ll.toArrayList();
for (int i = 0; i < items.length; i++) {
assertThat(items[i]).isEqualTo(convertedAl.get(i));
}
}
private CustomLinkedList<String> initPopulatedList(String... initData) { private CustomLinkedList<String> initPopulatedList(String... initData) {
CustomLinkedList<String> list = new CustomLinkedListImpl<>(); CustomLinkedList<String> list = new CustomLinkedListImpl<>();
Stream.of(initData).forEach(list::add); Stream.of(initData).forEach(list::add);