/* * Copyright (c) 2012 Data Harmonisation Panel * * All rights reserved. This program and the accompanying materials are made * available under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution. If not, see <http://www.gnu.org/licenses/>. * * Contributors: * HUMBOLDT EU Integrated Project #030962 * Data Harmonisation Panel <http://www.dhpanel.eu> */ package eu.esdihumboldt.util; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; /** * A list where the entries are sorted by dependencies, the dependencies to an * entry are before the entry * * @param <T> the entry type * * @author Simon Templer * @partner 01 / Fraunhofer Institute for Computer Graphics Research */ public class DependencyOrderedList<T> { private final List<T> list; /** * Create a new list * * <b>Attention:</b> Due to the use of recursion a huge dependency set may * result in a StackOverflowError. * * @param dependencies the dependency map */ public DependencyOrderedList(Map<T, Set<T>> dependencies) { list = new ArrayList<T>(dependencies.size()); Set<T> alreadyInserted = new HashSet<T>(); for (Entry<T, Set<T>> entry : dependencies.entrySet()) { if (!alreadyInserted.contains(entry.getKey())) { insert(entry.getKey(), dependencies, alreadyInserted); } } } /** * Insert an object into the list * * @param object the object to insert * @param dependencies the map with all dependencies * @param alreadyInserted the objects that were already inserted */ private void insert(T object, Map<T, Set<T>> dependencies, Set<T> alreadyInserted) { Set<T> objectDependencies = dependencies.get(object); // mark object as inserted to prevent cycle loops alreadyInserted.add(object); // initialize last index int lastIndex = -1; if (objectDependencies != null) { // find all dependencies that have not yet been inserted for (T dependency : objectDependencies) { if (!alreadyInserted.contains(dependency)) { // prevent cycle // loops int index = find(dependency); if (index < 0) { // insert dependency insert(dependency, dependencies, alreadyInserted); } } } // determine the index to insert the object at for (T dependency : objectDependencies) { int index = find(dependency); lastIndex = Math.max(lastIndex, index); } } // the minimum index the item has to be inserted at int minInsertIndex = lastIndex + 1; // insert the object list.add(minInsertIndex, object); } /** * Find an object in the list * * @param object the object to find * @return the object's index or <code>-1</code> if there is no such object * in the list */ private int find(T object) { return list.indexOf(object); } /** * Add an object where it is sure that none of the others depends on it * * @param object the object to append */ public void append(T object) { list.add(object); } /** * Get an {@link Iterable} over the list's items * * @return the list's items */ public Iterable<T> getItems() { return list; } /** * Get the internal list, there shouldn't be made any changes to this list. * * @return the internal list */ public List<T> getInternalList() { return list; } }