package org.rr.commons.collection;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
/**
* A list which maps two lists into one without copy.
*/
public class CompoundList<E> extends AbstractList<E> {
public static final int ADD_TO_FIRST = 0;
public static final int ADD_TO_SECOND = 1;
private int addTo = 1;
private List<E> first;
private List<E> second;
/**
* Constructs a new {@link CompoundList} instance.
*
* @param first first {@link List} to merge into this {@link CompoundList} instance.
* @param second second {@link List} to merge into this {@link CompoundList} instance.
* @param addTo Determines which {@link List} gets new added entries. Valid values
* are {@link CompoundList#ADD_TO_FIRST} or {@link CompoundList#ADD_TO_SECOND}
*/
public CompoundList(List<E> first, List<E> second, int addTo) {
if(first == null) {
this.first = new ArrayList<>();
} else {
this.first = first;
}
if(second == null) {
this.second = new ArrayList<>();
} else {
this.second = second;
}
this.addTo = addTo;
}
/**
* Constructs a new {@link CompoundList} instance which adds it's new entries to
* the {@link List} given with the second parameter.
*
* @param first first {@link List} to merge into this {@link CompoundList} instance.
* @param second second {@link List} to merge into this {@link CompoundList} instance.
*/
public CompoundList(List<E> first, List<E> second) {
this(first, second, ADD_TO_SECOND);
}
@Override
public boolean add(E e) {
if(addTo == ADD_TO_SECOND) {
return second.add(e);
} else {
return first.add(e);
}
}
@Override
public void add(int index, E element) {
int size = first.size();
if(index <= size) {
first.add(index, element);
} else {
second.add(index - size, element);
}
}
@Override
public boolean addAll(Collection<? extends E> c) {
if(addTo == ADD_TO_SECOND) {
return second.addAll(c);
} else {
return first.addAll(c);
}
}
@Override
public boolean addAll(int index, Collection<? extends E> c) {
int size = first.size();
if(index <= size) {
return first.addAll(index, c);
} else {
return second.addAll(index - size, c);
}
}
@Override
public void clear() {
first.clear();
second.clear();
}
@Override
public boolean contains(Object o) {
return first.contains(o) || second.contains(o);
}
@Override
public boolean containsAll(Collection<?> c) {
for(Object o : c) {
if(!contains(o)) {
return false;
}
}
return true;
}
@Override
public E get(int index) {
if(index >= first.size()) {
final int indexOnSecond = index - first.size();
try {
return second.get(indexOnSecond);
} catch (IndexOutOfBoundsException e) {
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size());
}
} else {
return first.get(index);
}
}
@Override
public int indexOf(Object o) {
int firstIndexOf = first.indexOf(o);
if(firstIndexOf!=-1) {
return firstIndexOf;
} else {
final int secondIndexOf = second.indexOf(o);
if(secondIndexOf!=-1) {
return secondIndexOf + first.size();
} else {
return -1;
}
}
}
@Override
public boolean isEmpty() {
return first.isEmpty() && second.isEmpty();
}
@Override
public Iterator<E> iterator() {
return new CompoundIterator<E>(first.iterator(), second.iterator());
}
@Override
public int lastIndexOf(Object o) {
int secondLastIndexOf = second.lastIndexOf(o);
if(secondLastIndexOf!=-1) {
return secondLastIndexOf + first.size();
} else {
return first.lastIndexOf(o);
}
}
@Override
public ListIterator<E> listIterator() {
return super.listIterator();
}
@Override
public ListIterator<E> listIterator(int index) {
return super.listIterator(index);
}
@Override
public boolean remove(Object o) {
if(first.remove(o)) {
return true;
} else {
return second.remove(o);
}
}
@Override
public E remove(int index) {
if(index >= first.size()) {
final int indexOnSecond = index - first.size();
return second.remove(indexOnSecond);
} else {
return first.remove(index);
}
}
@Override
public boolean removeAll(Collection<?> c) {
boolean changed = false;
for (Object object : c) {
if(this.remove(object)) {
changed = true;
}
}
return changed;
}
@Override
public boolean retainAll(Collection<?> c) {
return super.retainAll(c);
}
@Override
public E set(int index, E element) {
if(index >= first.size()) {
final int indexOnSecond = index - first.size();
return second.set(indexOnSecond, element);
} else {
return first.set(index, element);
}
}
@Override
public int size() {
return first.size() + second.size();
}
}