updated to trunk
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / utility / DescriptionUtility.java
1 // $Id$
2 /**
3 * Copyright (C) 2013 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
6 *
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
9 */
10 package eu.etaxonomy.cdm.api.utility;
11
12 import java.util.ArrayList;
13 import java.util.Collection;
14 import java.util.HashMap;
15 import java.util.HashSet;
16 import java.util.Map;
17 import java.util.Set;
18
19 import eu.etaxonomy.cdm.model.common.CdmBase;
20 import eu.etaxonomy.cdm.model.common.MarkerType;
21 import eu.etaxonomy.cdm.model.description.Distribution;
22 import eu.etaxonomy.cdm.model.location.NamedArea;
23
24 /**
25 * @author a.kohlbecker
26 * @date Apr 18, 2013
27 *
28 */
29 public class DescriptionUtility {
30
31 /**
32 * <b>NOTE: This method must only be used in a transactional context.</b>
33 *
34 * Filters the given set of {@link Distribution}s for publication.
35 * Computed elements are preferred over entered or imported elements.
36 * Computed description elements are identified by the {@link MarkerType.COMPUTED()}.
37 *
38 * The following rules are respected during the filtering:
39 * <ol>
40 * <li>If a entered or imported status information exist for the same area for which computed
41 * data is available, the computed data has to be given preference over other data.</li>
42 * <li>If there is an area with a sub area and both areas have the same computed status only the subarea
43 * status should be shown in the map, whereas the super area should be ignored.</li>
44 * </ol>
45 *
46 * @param distributions
47 * @return the filtered collection of distribution elements.
48 */
49 public static Collection<Distribution> filterDistributions(Collection<Distribution> distributions) {
50
51 Map<String, Set<Distribution>> computedDistributions = new HashMap<String, Set<Distribution>>(distributions.size());
52 Map<String, Set<Distribution>> otherDistributions = new HashMap<String, Set<Distribution>>(distributions.size());
53 Set<Distribution> removeCandidates = new HashSet<Distribution>();
54
55 // 1. sort by computed / not computed
56 for(Distribution distribution : distributions){
57 if(distribution.hasMarker(MarkerType.COMPUTED(), true)){
58 if(!computedDistributions.containsKey(areaKey(distribution))){
59 computedDistributions.put(areaKey(distribution), new HashSet<Distribution>());
60 }
61 computedDistributions.get(areaKey(distribution)).add(distribution);
62 } else {
63 if(!otherDistributions.containsKey(areaKey(distribution))){
64 otherDistributions.put(areaKey(distribution), new HashSet<Distribution>());
65 }
66 otherDistributions.get(areaKey(distribution)).add(distribution);
67 }
68 }
69
70 // if there are computed elements apply the filter rules
71 if(computedDistributions.size() > 0){
72
73 // 2. apply the filter rules
74 // prepare removal of all not computed areas for which a computed area exists
75 for(String keyComputed : computedDistributions.keySet()){
76 otherDistributions.remove(otherDistributions);
77 }
78
79 for(Distribution distribution : valuesOfAllInnerSets(computedDistributions.values())){
80 if(distribution.getArea() != null){
81 NamedArea parentArea = distribution.getArea().getPartOf();
82 while(parentArea != null){
83 Set<Distribution> computedDistributionSet = computedDistributions.get(areaKey(parentArea));
84 if(computedDistributionSet != null){
85 for(Distribution parentDistribution : computedDistributionSet) {
86 if(parentDistribution != null && parentDistribution.getStatus().equals(distribution.getStatus())){
87 removeCandidates.add(parentDistribution);
88 }
89 }
90 }
91 parentArea = parentArea.getPartOf();
92 }
93 }
94 }
95 }
96
97 // finally remove computed distributions if necessary and combine computed and non computed distributions again
98 Set<Distribution> filteredDistributions = new HashSet<Distribution>(otherDistributions.size() + computedDistributions.size());
99 filteredDistributions.addAll(valuesOfAllInnerSets(computedDistributions.values()));
100 for(Distribution distribution : removeCandidates){
101 computedDistributions.remove(areaKey(distribution));
102 }
103
104 filteredDistributions.addAll(valuesOfAllInnerSets(otherDistributions.values()));
105
106 return filteredDistributions;
107
108 }
109
110 private static <T extends CdmBase> Collection<T> valuesOfAllInnerSets(Collection<Set<T>> collectionOfSets){
111 Collection<T> allValues = new ArrayList<T>();
112 for(Set<T> set : collectionOfSets){
113 allValues.addAll(set);
114 }
115 return allValues;
116 }
117
118 private static String areaKey(NamedArea area){
119 return String.valueOf(area.getUuid());
120 }
121
122 private static String areaKey(Distribution distribution){
123 StringBuilder keyBuilder = new StringBuilder();
124
125 if(distribution.getArea() != null){
126 keyBuilder.append(distribution.getArea().getUuid());
127 } else {
128 keyBuilder.append("NULL");
129 }
130
131 return keyBuilder.toString();
132 }
133
134 }