package eu.etaxonomy.taxeditor.model;
import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
import java.util.Collection;
-import java.util.Comparator;
import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.TreeMap;
+import java.util.List;
import java.util.TreeSet;
import org.apache.log4j.Logger;
* @return a map which holds the terms as keys and their string
* representation via {@link IEnumTerm#getMessage()} as values
*/
- public static <T extends IEnumTerm<?>> Map<T, String> orderTerms(Collection<T> terms) {
- Comparator<T> comparator = new Comparator<T>() {
- @Override
- public int compare(T t1, T t2) {
- return t1.getMessage().compareTo(t2.getMessage());
- }
- };
- Map<T, String> result = new LinkedHashMap<T, String>();
- Map<T, Set<T>> termHierarchy = new TreeMap<T, Set<T>>(comparator);
-
- for(T term : terms) {
- Set<T> childList = new TreeSet<T>(comparator);
- // add root element as keys
- if(term.getKindOf()==null){
- termHierarchy.put(term, childList);
+ public static <T extends IEnumTerm<T>> LinkedHashMap<T, String> orderTerms(Collection<T> terms) {
+// Comparator<TermNode<T>> comparator = new Comparator<TermNode<T>>() {
+// @Override
+// public int compare(TermNode<T> t1, TermNode<T> t2) {
+// return t1.getTerm().getMessage().compareTo(t2.getTerm().getMessage());
+// }
+// };
+
+ TreeSet<TermNode<T>> parentElements = new TreeSet<TermNode<T>>();
+ parentElements.addAll(getTermHierarchy(terms));
+
+ // create list according to the type hierarchy (root elements alphabetically with recursive children also alphabetically)
+ LinkedHashMap<T, String> result = new LinkedHashMap<T, String>();
+ parseTermTree(parentElements, result, -1);
+ return result;
+ }
+
+ private static<T extends IEnumTerm<T>> void parseTermTree(Collection<TermNode<T>> children, LinkedHashMap<T, String> result, int depth){
+ depth++;
+ for(TermNode<T> node:children){
+ String indentString = "";
+ for(int i=0;i<depth;i++){
+ indentString += " ";
}
- // add child element to topmost parent i.e. root
- else{
- T root = getRootFor(term);
- if(termHierarchy.containsKey(root)){
- termHierarchy.get(root).add(term);
- }
- else{
- childList.add(term);
- termHierarchy.put(root, childList);
+ result.put(node.term, indentString + node.term.getMessage());
+ parseTermTree(node.children, result, depth);
+ }
+ }
+
+ private static<T extends IEnumTerm<T>> void addToParents(List<TermNode<T>> parents, Collection<T> terms){
+ List<TermNode<T>> hasChildrenList = new ArrayList<TermNode<T>>();
+ for(T term:terms){
+ // only terms with parents
+ if(term.getKindOf()!=null){
+ TermNode<T> parentNode = new TermNode<T>(term.getKindOf());
+ TermNode<T> childNode = new TermNode<T>(term);
+ if(parents.contains(parentNode)){
+ // parent found in parent list -> add this term to parent's child list
+ parents.get(parents.indexOf(parentNode)).addChild(childNode);
+ if(!term.getGeneralizationOf().isEmpty()){
+ // has more children -> add to list which will be the parent for the next recursion
+ hasChildrenList.add(childNode);
+ }
}
}
}
+ if(!hasChildrenList.isEmpty()){
+ addToParents(hasChildrenList, terms);
+ }
+ }
- // create list according to the type hierarchy (root elements alphabetically with recursive children also alphabetically)
- for(Entry<T, Set<T>> entry:termHierarchy.entrySet()){
- T root = entry.getKey();
- result.put(root, root.getMessage());
- for(T child:entry.getValue()){
- result.put(child, " " + child.getMessage());
+ private static<T extends IEnumTerm<T>> List<TermNode<T>> getTermHierarchy(Collection<T> terms){
+ List<TermNode<T>> parents = new ArrayList<TermNode<T>>();
+ // get root elements
+ for(T term:terms){
+ T parentTerm = term.getKindOf();
+ if(parentTerm==null){
+ // root element
+ parents.add(new TermNode<T>(term));
}
}
- return result;
+ addToParents(parents, terms);
+ return parents;
}
@SuppressWarnings("unchecked")
* @param term The term for which the parent should be found
* @return the root terms of the term hierarchy
*/
- private static<T extends IEnumTerm<?>> T getRootFor(T term){
+ private static<T extends IEnumTerm<T>> T getParentFor(T term){
// PP: cast should be safe. Why is Eclipse complaining??
- T parent = (T) term.getKindOf();
+ T parent = term.getKindOf();
if(parent==null){
return term;
}
else{
- return getRootFor((T) term.getKindOf());
+ return getParentFor(term.getKindOf());
}
}
-
-// /**
-// * Orders a Collection of {@link IEnumTerm}s according to the term
-// * hierarchy. The hierarchy will be reduced to two layers: one layer being
-// * the root elements (that have no parents) and the other being their
-// * children and children's children recursively.<br>
-// * The returned map will be be ordered primarily by root elements and
-// * secondarily by the child elements, both ascending alphabetically. <br>
-// * <br>
-// * The reduced hierarchy could look like this:<br>
-// * <ul>
-// * <li>Root1
-// * <ul>
-// * <li>child1
-// * <li>child2
-// * <li>childOfChild2
-// * </ul>
-// * <li>root2
-// * <ul><li>child4</ul>
-// * </ul>
-// *
-// * @param terms
-// * A {@link Collection} of {@link IEnumTerm}s for which the term
-// * hierarchy should be created
-// * @return a map which holds the terms as keys and their string
-// * representation via {@link IEnumTerm#getMessage()} as values
-// */
-// public static <T extends IEnumTerm<?>> LinkedHashMap<T, String> orderTerms(Collection<T> terms) {
-// Comparator<TermNode<T>> comparator = new Comparator<TermNode<T>>() {
-// @Override
-// public int compare(TermNode<T> t1, TermNode<T> t2) {
-// return t1.getTerm().getMessage().compareTo(t2.getTerm().getMessage());
-// }
-// };
-// TreeSet<TermNode<T>> parentElements = new TreeSet<TermNode<T>>(comparator);
-// for(T term : terms) {
-// Set<T> childList = new TreeSet<T>(comparator);
-// // add root element as keys
-// if(term.getKindOf()==null){
-// parentElements.add(new TermNode<T>(term));
-// }
-// // add child element to parent
-// else{
-// T parent = getParentFor(term);
-// if(termHierarchy.containsKey(parent)){
-// termHierarchy.get(parent).add(term);
-// }
-// else{
-// childList.add(term);
-// termHierarchy.put(parent, childList);
-// }
-// }
-// }
-//
-// // create list according to the type hierarchy (root elements alphabetically with recursive children also alphabetically)
-// LinkedHashMap<T, String> result = new LinkedHashMap<T, String>();
-// for(Entry<T, Set<T>> entry:termHierarchy.entrySet()){
-// T root = entry.getKey();
-// result.put(root, root.getMessage());
-// for(T child:entry.getValue()){
-// result.put(child, " " + child.getMessage());
-// }
-// }
-// return result;
-// }
-//
-// private static addToParents(TreeSet<TermNode<T>> parents, Collection<T> terms){
-// for(T term:terms){
-//
-// }
-// }
-//
-// @SuppressWarnings("unchecked")
-// /**
-// * Recursively iterates over all term parents until no more parent is found i.e. the root node
-// * @param term The term for which the parent should be found
-// * @return the root terms of the term hierarchy
-// */
-// private static<T extends IEnumTerm<?>> T getParentFor(T term){
-// // PP: cast should be safe. Why is Eclipse complaining??
-// T parent = (T) term.getKindOf();
-// if(parent==null){
-// return term;
-// }
-// else{
-// return getParentFor((T) term.getKindOf());
-// }
-// }
-//
-// private class TermNode<T>{
-// private final T term;
-// private final TreeSet<TermNode<T>> children;
-//
-// /**
-// * @param term
-// * @param children
-// */
-// public TermNode(T term) {
-// super();
-// this.term = term;
-// this.children = new TreeSet<TermNode<T>>();
-// }
-//
-// public void addChild(TermNode<T> child){
-// this.children.add(child);
-// }
-//
-// /**
-// * @return the children
-// */
-// public TreeSet<TermNode<T>> getChildren() {
-// return children;
-// }
-//
-// /**
-// * @return the term
-// */
-// public T getTerm() {
-// return term;
-// }
-// }
+ private static class TermNode<T extends IEnumTerm<T>> implements Comparable<TermNode<T>>{
+ private final T term;
+ private final TreeSet<TermNode<T>> children;
+
+ /**
+ * @param term
+ * @param children
+ */
+ public TermNode(T term) {
+ super();
+ this.term = term;
+ this.children = new TreeSet<TermNode<T>>();
+ }
+
+ public void addChild(TermNode<T> child){
+ this.children.add(child);
+ }
+
+ /**
+ * @return the children
+ */
+ public TreeSet<TermNode<T>> getChildren() {
+ return children;
+ }
+
+ /**
+ * @return the term
+ */
+ public T getTerm() {
+ return term;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((term == null) ? 0 : term.hashCode());
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ TermNode other = (TermNode) obj;
+ if (term == null) {
+ if (other.term != null) {
+ return false;
+ }
+ } else if (!term.equals(other.term)) {
+ return false;
+ }
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ @Override
+ public int compareTo(TermNode<T> that) {
+ return this.term.getMessage().compareTo(that.term.getMessage());
+ }
+ }
}
--- /dev/null
+// $Id$
+/**
+* Copyright (C) 2013 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.taxeditor.store.utility;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+
+import org.junit.Test;
+
+import eu.etaxonomy.cdm.model.common.IEnumTerm;
+import eu.etaxonomy.cdm.model.common.OriginalSourceType;
+import eu.etaxonomy.cdm.model.common.TermType;
+import eu.etaxonomy.cdm.model.metadata.PreferencePredicate;
+import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
+import eu.etaxonomy.cdm.model.name.RankClass;
+import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationType;
+import eu.etaxonomy.cdm.model.reference.ReferenceType;
+import eu.etaxonomy.taxeditor.model.AbstractUtility;
+
+/**
+ * @author pplitzner
+ * @date 04.11.2013
+ *
+ */
+public class AbstractUtilityTest {
+
+ @Test
+ public void testOrderTerms(){
+ LinkedHashMap<? extends IEnumTerm<?>, String> orderedTerms;
+
+ orderedTerms = AbstractUtility.orderTerms(Arrays.asList(SpecimenOrObservationType.values()));
+ checkSize(orderedTerms, Arrays.asList(SpecimenOrObservationType.values()));
+ orderedTerms = AbstractUtility.orderTerms(Arrays.asList(NomenclaturalCode.values()));
+ checkSize(orderedTerms, Arrays.asList(NomenclaturalCode.values()));
+ orderedTerms = AbstractUtility.orderTerms(Arrays.asList(OriginalSourceType.values()));
+ checkSize(orderedTerms, Arrays.asList(OriginalSourceType.values()));
+ orderedTerms = AbstractUtility.orderTerms(Arrays.asList(PreferencePredicate.values()));
+ checkSize(orderedTerms, Arrays.asList(PreferencePredicate.values()));
+ orderedTerms = AbstractUtility.orderTerms(Arrays.asList(RankClass.values()));
+ checkSize(orderedTerms, Arrays.asList(RankClass.values()));
+ orderedTerms = AbstractUtility.orderTerms(Arrays.asList(ReferenceType.values()));
+ checkSize(orderedTerms, Arrays.asList(ReferenceType.values()));
+ orderedTerms = AbstractUtility.orderTerms(Arrays.asList(TermType.values()));
+ checkSize(orderedTerms, Arrays.asList(TermType.values()));
+ }
+
+ /**
+ * @param orderedTerms
+ * @param expectedTerms
+ */
+ private void checkSize(LinkedHashMap<? extends IEnumTerm<?>, String> orderedTerms, Collection<? extends IEnumTerm<?>> expectedTerms) {
+ assertEquals("Some terms got lost while ordering.", expectedTerms.size(), orderedTerms.size());
+ }
+
+}