package turin.relations; import java.util.*; import java.util.stream.Collectors; public interface Relation<A, B> { public void link(A endpointA, B endpointB); public default void link(A endpointA, B endpointB, Subset bSubset) { throw new UnsupportedOperationException(); } public void unlink(Object endpointA, Object endpointB); public boolean areLinked(Object endpointA, Object endpointB); public static class ReferenceSingleEndpoint<A, B> { private B b; private Map<B, A> byEndpointB; private Relation<A,B> relation; public ReferenceSingleEndpoint(B b, Map<B, A> byEndpointB, Relation<A, B> relation) { this.b = b; this.byEndpointB = byEndpointB; this.relation = relation; } public boolean isPresent() { return byEndpointB.containsKey(b); } public A get() { return byEndpointB.get(b); } public void set(A a) { relation.link(a, b); } } public static class ReferenceMultipleEndpoint<A, B> implements List<B> { private A a; private Relation<A, B> relation; private Map<A, List<B>> byEndpointA; private Map<B, Subset> bSubsets; private Subset subset; public ReferenceMultipleEndpoint(A a, Map<A, List<B>> byEndpointA, Relation<A, B> relation) { this.a = a; this.byEndpointA = byEndpointA; this.relation = relation; } public ReferenceMultipleEndpoint(A a, Map<A, List<B>> byEndpointA, Relation<A, B> relation, Map<B, Subset> bSubsets, Subset subset) { this.a = a; this.byEndpointA = byEndpointA; this.relation = relation; this.bSubsets = bSubsets; this.subset = subset; } @Override public int size() { if (byEndpointA.containsKey(a)) { if (subset == null) { return byEndpointA.get(a).size(); } else { return (int) byEndpointA.get(a).stream() .filter((b) -> bSubsets.get(b) == subset) .count(); } } else { return 0; } } @Override public boolean isEmpty() { if (byEndpointA.containsKey(a)) { if (subset == null) { return byEndpointA.get(a).isEmpty(); } else { return byEndpointA.get(a).stream() .filter((b) -> bSubsets.get(b) == subset) .findFirst().isPresent(); } } else { return true; } } @Override public boolean contains(Object o) { if (byEndpointA.containsKey(a)) { if (subset == null) { return byEndpointA.get(a).contains(o); } else { return byEndpointA.get(a).stream() .filter((b) -> bSubsets.get(b) == subset && b.equals(o)) .findFirst().isPresent(); } } else { return false; } } @Override public Iterator<B> iterator() { if (byEndpointA.containsKey(a)) { if (subset == null) { return byEndpointA.get(a).iterator(); } else { return byEndpointA.get(a).stream() .filter((b) -> bSubsets.get(b) == subset) .iterator(); } } else { return Collections.emptyIterator(); } } @Override public Object[] toArray() { if (byEndpointA.containsKey(a)) { if (subset == null) { return byEndpointA.get(a).toArray(); } else { return byEndpointA.get(a).stream() .filter((b) -> bSubsets.get(b) == subset) .collect(Collectors.toList()).toArray(); } } else { return new Object[]{}; } } @Override public <T> T[] toArray(T[] a) { if (byEndpointA.containsKey(a)) { if (subset == null) { return byEndpointA.get(a).toArray(a); } else { return byEndpointA.get(a).stream() .filter((b) -> bSubsets.get(b) == subset) .collect(Collectors.toList()).toArray(a); } } else { return Arrays.copyOf(a, 0); } } @Override public boolean add(B b) { if (relation.areLinked(a, b)) { if (bSubsets.get(b) == subset) { return false; } else { bSubsets.put(b, subset); return true; } } else { relation.link(a, b, subset); return true; } } @Override public boolean remove(Object o) { if (relation.areLinked(a, o) && (subset==null || bSubsets.get(o) == subset)) { relation.unlink(a, o); return true; } else { return false; } } @Override public boolean containsAll(Collection<?> c) { for (Object o : c) { if (!contains(o)) { return false; } } return true; } @Override public boolean addAll(Collection<? extends B> c) { boolean changed = false; for (B o : c) { boolean partial = add(o); changed = changed || partial; } return changed; } @Override public boolean addAll(int index, Collection<? extends B> c) { boolean changed = false; for (B o : c) { boolean partial = !contains(o); if (partial) { add(index, o); changed = true; index++; } } return changed; } @Override public boolean retainAll(Collection<?> c) { boolean changed = false; for (Object o : c) { if (!contains(o)) { boolean partial = remove(o); changed = changed || partial; } } return changed; } @Override public boolean removeAll(Collection<?> c) { boolean changed = false; for (Object o : c) { boolean partial = remove(o); changed = changed || partial; } return changed; } @Override public void clear() { if (isEmpty()) { return; } relation.unlink(a, iterator().next()); clear(); } @Override public B get(int index) { if (subset == null) { return byEndpointA.get(a).get(index); } else { return byEndpointA.get(a).stream() .filter((b) -> bSubsets.get(b) == subset) .collect(Collectors.toList()).get(index); } } @Override public B set(int index, B element) { throw new UnsupportedOperationException(); } @Override public void add(int index, B element) { throw new UnsupportedOperationException(); } @Override public B remove(int index) { throw new UnsupportedOperationException(); } @Override public int indexOf(Object o) { throw new UnsupportedOperationException(); } @Override public int lastIndexOf(Object o) { throw new UnsupportedOperationException(); } @Override public ListIterator<B> listIterator() { throw new UnsupportedOperationException(); } @Override public ListIterator<B> listIterator(int index) { throw new UnsupportedOperationException(); } @Override public List<B> subList(int fromIndex, int toIndex) { throw new UnsupportedOperationException(); } } }