/*
* $Id$
* This file is a part of the Arakhne Foundation Classes, http://www.arakhne.org/afc
*
* Copyright (c) 2000-2012 Stephane GALLAND.
* Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports,
* Universite de Technologie de Belfort-Montbeliard.
* Copyright (c) 2013-2016 The original authors, and other authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.arakhne.afc.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import org.eclipse.xtext.xbase.lib.Pure;
/**
* A collection composed of collections.
*
* <p>This collection is not thread-safe.
*
* <p>This collection is read-only.
*
* @param <E> is the type of elements in the collections.
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
*/
public class MultiCollection<E> implements Collection<E> {
private final List<Collection<? extends E>> collections = new ArrayList<>();
/** Construct the collection.
*/
public MultiCollection() {
//
}
/** Add a collection inside this multicollection.
*
* @param collection the collection to add.
*/
public void addCollection(Collection<? extends E> collection) {
if (collection != null && !collection.isEmpty()) {
this.collections.add(collection);
}
}
/** Remove a collection from this multicollection.
*
* @param collection the collection to remove.
* @return <code>true</code> if the multi-collection has changed,
* otherwise <code>false</code>.
*/
public boolean removeCollection(Collection<? extends E> collection) {
return this.collections.remove(collection);
}
@Override
public void clear() {
this.collections.clear();
}
/**
* This function is not supported, see {@link #addCollection(Collection)}.
*/
@Override
public boolean add(E value) {
throw new UnsupportedOperationException();
}
/**
* This function is not supported, see {@link #addCollection(Collection)}.
*/
@Override
public boolean addAll(Collection<? extends E> collection) {
throw new UnsupportedOperationException();
}
@Override
@Pure
public boolean contains(Object obj) {
for (final Collection<? extends E> c : this.collections) {
if (c.contains(obj)) {
return true;
}
}
return false;
}
@Override
@Pure
public boolean containsAll(Collection<?> collection) {
for (final Object o : collection) {
if (!contains(o)) {
return false;
}
}
return true;
}
@Override
@Pure
public boolean isEmpty() {
for (final Collection<? extends E> c : this.collections) {
if (!c.isEmpty()) {
return false;
}
}
return true;
}
@Override
@Pure
public Iterator<E> iterator() {
return new MultiIterator<>(this.collections.iterator());
}
/**
* This function is not supported, see {@link #removeCollection(Collection)}.
*/
@Override
public boolean remove(Object obj) {
throw new UnsupportedOperationException();
}
/**
* This function is not supported, see {@link #removeCollection(Collection)}.
*/
@Override
public boolean removeAll(Collection<?> collection) {
throw new UnsupportedOperationException();
}
/**
* This function is not supported, see {@link #removeCollection(Collection)}.
*/
@Override
public boolean retainAll(Collection<?> collection) {
throw new UnsupportedOperationException();
}
@Override
@Pure
public int size() {
int t = 0;
for (final Collection<? extends E> c : this.collections) {
t += c.size();
}
return t;
}
@Override
@Pure
public Object[] toArray() {
throw new UnsupportedOperationException();
}
@Override
public <T> T[] toArray(T[] array) {
throw new UnsupportedOperationException();
}
/** Iterator on multicollection.
*
* @param <E> is the type of elements in the collections.
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
*/
public static class MultiIterator<E> implements Iterator<E> {
private final Iterator<Collection<? extends E>> iterator;
private Iterator<? extends E> currentIterator;
/** Construct the iterator.
*
* @param iterator original iterator.
*/
public MultiIterator(Iterator<Collection<? extends E>> iterator) {
this.iterator = iterator;
searchNext();
}
private void searchNext() {
if (this.currentIterator == null || !this.currentIterator.hasNext()) {
this.currentIterator = null;
while (this.currentIterator == null && this.iterator.hasNext()) {
final Collection<? extends E> iterable = this.iterator.next();
final Iterator<? extends E> iter = iterable.iterator();
if (iter.hasNext()) {
this.currentIterator = iter;
}
}
}
}
@Override
public boolean hasNext() {
return this.currentIterator != null && this.currentIterator.hasNext();
}
@Override
public E next() {
if (this.currentIterator == null) {
throw new NoSuchElementException();
}
final E n = this.currentIterator.next();
searchNext();
return n;
}
}
}