/*
* $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.math.tree;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.xtext.xbase.lib.Pure;
import org.arakhne.afc.math.tree.iterator.BroadFirstForestIterator;
import org.arakhne.afc.math.tree.iterator.DataBroadFirstForestIterator;
import org.arakhne.afc.math.tree.iterator.DataDepthFirstForestIterator;
import org.arakhne.afc.math.tree.iterator.DepthFirstForestIterator;
import org.arakhne.afc.math.tree.iterator.DepthFirstNodeOrder;
/**
* This is the generic implementation of a
* forest of trees.
*
* <p>A forest of trees is a collection of trees.
*
* @param <D> is the type of the data inside the forest
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
* @since 13.0
*/
public abstract class AbstractForest<D> implements Forest<D> {
/**
* Indicates if the forests are using a linked list
* by default to store the trees.
*/
public static final boolean USE_LINKED_LIST = false;
/** List of trees.
*/
private final List<Tree<D, ?>> trees;
private Collection<ForestListener> listeners;
/**
* @param internalList is the internal list to use.
*/
protected AbstractForest(List<Tree<D, ?>> internalList) {
assert internalList != null;
this.trees = internalList;
}
/**
* @param internalList is the internal list to use.
* @param trees is the trees to put inside the forest.
*/
protected AbstractForest(List<Tree<D, ?>> internalList, Collection<? extends Tree<D, ?>> trees) {
assert internalList != null;
assert trees != null;
this.trees = internalList;
this.trees.addAll(trees);
}
@Override
@Pure
public final int getMinHeight() {
if (this.trees.isEmpty()) {
return 0;
}
int height;
int min = Integer.MAX_VALUE;
for (final Tree<D, ?> tree : this.trees) {
height = tree.getMinHeight();
if (height < min) {
min = height;
}
}
return min;
}
@Override
@Pure
public final int getMaxHeight() {
if (this.trees.isEmpty()) {
return 0;
}
int height;
int max = 0;
for (final Tree<D, ?> tree : this.trees) {
height = tree.getMaxHeight();
if (height > max) {
max = height;
}
}
return max;
}
@Override
@Pure
public final int[] getHeights() {
int[] array = new int[0];
for (final Tree<D, ?> tree : this.trees) {
final int[] a = tree.getHeights();
if (a != null && a.length > 0) {
final int[] b = new int[array.length + a.length];
System.arraycopy(array, 0, b, 0, array.length);
System.arraycopy(a, 0, b, array.length, a.length);
array = b;
}
}
return array;
}
@Override
@Pure
public final Iterator<TreeNode<D, ?>> depthFirstIterator(DepthFirstNodeOrder nodeOrder) {
return new DepthFirstForestIterator<>(
nodeOrder,
this.trees.iterator());
}
@Override
@Pure
public final Iterator<TreeNode<D, ?>> depthFirstIterator() {
return new DepthFirstForestIterator<>(
DepthFirstNodeOrder.PREFIX,
this.trees.iterator());
}
@Override
@Pure
public final Iterator<TreeNode<D, ?>> broadFirstIterator() {
return new BroadFirstForestIterator<>(this.trees.iterator());
}
@Override
@Pure
public final Iterator<D> dataDepthFirstIterator() {
return new DataDepthFirstForestIterator<>(
DepthFirstNodeOrder.PREFIX,
this.trees.iterator());
}
@Override
@Pure
public final Iterator<D> dataDepthFirstIterator(DepthFirstNodeOrder nodeOrder) {
return new DataDepthFirstForestIterator<>(
nodeOrder,
this.trees.iterator());
}
@Override
@Pure
public final Iterator<D> dataDepthFirstIterator(int infixPosition) {
if (infixPosition <= 0) {
return new DataDepthFirstForestIterator<>(
DepthFirstNodeOrder.PREFIX,
this.trees.iterator());
}
return new DataDepthFirstForestIterator<>(
infixPosition,
this.trees.iterator());
}
@Override
@Pure
public final Iterator<D> dataBroadFirstIterator() {
return new DataBroadFirstForestIterator<>(this.trees.iterator());
}
@Override
public boolean add(Tree<D, ?> tree) {
if (this.trees.add(tree)) {
fireTreeAddition(tree);
return true;
}
return false;
}
@Override
public boolean addAll(Collection<? extends Tree<D, ?>> newTrees) {
if (newTrees.isEmpty()) {
return false;
}
boolean allAdded = true;
for (final Tree<D, ?> tree : newTrees) {
if (!add(tree)) {
allAdded = false;
}
}
return allAdded;
}
@Override
public void clear() {
for (final Tree<D, ?> tree : this.trees) {
fireTreeRemoval(tree);
}
this.trees.clear();
}
@Override
@Pure
public boolean contains(Object tree) {
return this.trees.contains(tree);
}
@Override
@Pure
public boolean containsAll(Collection<?> treeCollection) {
return this.trees.containsAll(treeCollection);
}
@Override
@Pure
public boolean isEmpty() {
if (this.trees.isEmpty()) {
return true;
}
for (final Tree<D, ?> tree : this.trees) {
if (!tree.isEmpty()) {
return false;
}
}
return true;
}
@Override
@Pure
public Iterator<Tree<D, ?>> iterator() {
return new ForestIterator(this.trees.iterator());
}
@SuppressWarnings("unchecked")
@Override
public boolean remove(Object obj) {
final Tree<D, ?> tree;
try {
tree = (Tree<D, ?>) obj;
} catch (AssertionError e) {
throw e;
} catch (Throwable e) {
return false;
}
if (this.trees.remove(obj)) {
fireTreeRemoval(tree);
return true;
}
return false;
}
@Override
public boolean removeAll(Collection<?> tree) {
if (tree.isEmpty()) {
return false;
}
boolean allRemoved = true;
for (final Object o : tree) {
if (!remove(o)) {
allRemoved = false;
}
}
return allRemoved;
}
@SuppressWarnings("unchecked")
@Override
public boolean retainAll(Collection<?> tree) {
final List<Tree<D, ?>> retained = new LinkedList<>();
boolean changed = false;
for (final Object o : tree) {
if (this.trees.remove(o)) {
retained.add((Tree<D, ?>) o);
changed = true;
}
}
for (final Tree<D, ?> t : this.trees) {
fireTreeRemoval(t);
changed = true;
}
this.trees.clear();
this.trees.addAll(retained);
return changed;
}
@Override
@Pure
public int size() {
return this.trees.size();
}
@Override
@Pure
public Object[] toArray() {
return this.trees.toArray();
}
@Override
public <TT> TT[] toArray(TT[] array) {
return this.trees.toArray(array);
}
/** Add forest listener.
*
* @param listener the listener.
*/
public synchronized void addForestListener(ForestListener listener) {
if (this.listeners == null) {
this.listeners = new ArrayList<>();
}
this.listeners.add(listener);
}
/** Remove forest listener.
*
* @param listener the listener.
*/
public synchronized void removeForestListener(ForestListener listener) {
if (this.listeners != null) {
this.listeners.remove(listener);
if (this.listeners.isEmpty()) {
this.listeners = null;
}
}
}
/** Fire the addition event.
*
* @param tree is the new tree in the forest.
*/
protected synchronized void fireTreeAddition(Tree<D, ?> tree) {
if (this.listeners != null) {
final ForestListener[] list = new ForestListener[this.listeners.size()];
this.listeners.toArray(list);
final ForestEvent event = new ForestEvent(this, null, tree);
for (final ForestListener listener : list) {
listener.forestChanged(event);
}
}
}
/** Fire the removal event.
*
* @param tree is the old tree in the forest.
*/
protected synchronized void fireTreeRemoval(Tree<D, ?> tree) {
if (this.listeners != null) {
final ForestListener[] list = new ForestListener[this.listeners.size()];
this.listeners.toArray(list);
final ForestEvent event = new ForestEvent(this, tree, null);
for (final ForestListener listener : list) {
listener.forestChanged(event);
}
}
}
/** Iterator on trees in a forest.
*
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
* @since 13.0
*/
private class ForestIterator implements Iterator<Tree<D, ?>> {
private final Iterator<Tree<D, ?>> iterator;
private Tree<D, ?> lastReplied;
/** Construct the iterator.
*
* @param iterator1 the initial iterator.
*/
ForestIterator(Iterator<Tree<D, ?>> iterator1) {
this.iterator = iterator1;
}
@Override
public boolean hasNext() {
return this.iterator.hasNext();
}
@Override
public Tree<D, ?> next() {
final Tree<D, ?> t = this.iterator.next();
this.lastReplied = t;
return t;
}
@Override
public void remove() {
this.iterator.remove();
if (this.lastReplied != null) {
fireTreeRemoval(this.lastReplied);
this.lastReplied = null;
}
}
}
}