Project

General

Profile

« Previous | Next » 

Revision eda85815

Added by Andreas Müller almost 8 years ago

Fix sorting problem for subareas in CubaCondensedDistribution and refactor the whole class #5682

View differences:

cdmlib-ext/src/main/java/eu/etaxonomy/cdm/ext/geo/FloraCubaCondensedDistributionComposer.java
11 11

  
12 12
import java.util.ArrayList;
13 13
import java.util.Collection;
14
import java.util.Collections;
15
import java.util.Comparator;
14 16
import java.util.HashMap;
15
import java.util.HashSet;
16 17
import java.util.List;
17
import java.util.Set;
18
import java.util.Map;
18 19
import java.util.UUID;
19 20

  
20 21
import org.apache.commons.lang.StringUtils;
......
22 23

  
23 24
import eu.etaxonomy.cdm.api.service.dto.CondensedDistribution;
24 25
import eu.etaxonomy.cdm.common.UTF8;
25
import eu.etaxonomy.cdm.model.common.CdmBase;
26
import eu.etaxonomy.cdm.model.common.DefinedTermBase;
27 26
import eu.etaxonomy.cdm.model.common.Language;
28
import eu.etaxonomy.cdm.model.common.OrderedTermVocabulary;
29 27
import eu.etaxonomy.cdm.model.description.Distribution;
30 28
import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
31 29
import eu.etaxonomy.cdm.model.location.NamedArea;
......
40 38
    @SuppressWarnings("unused")
41 39
    private static final Logger logger = Logger.getLogger(FloraCubaCondensedDistributionComposer.class);
42 40

  
43
    private static Set<UUID> foreignStatusUuids;
41
//    private static Set<UUID> foreignStatusUuids;
44 42

  
43
    //preliminary for Cuba, needs to be parameterized
45 44
    private UUID uuidInternalArea = UUID.fromString("d0144a6e-0e17-4a1d-bce5-d464a2aa7229");  //Cuba
46 45

  
47 46
    private String internalAreaSeparator = UTF8.EN_DASH.toString() + " ";
48 47

  
49 48

  
50
    // these status uuids are special for EuroPlusMed and might also be used
51
    private final static UUID REPORTED_IN_ERROR_UUID =  UUID.fromString("38604788-cf05-4607-b155-86db456f7680");
49
//    // these status uuids are special for EuroPlusMed and might also be used
50
//    private final static UUID REPORTED_IN_ERROR_UUID =  UUID.fromString("38604788-cf05-4607-b155-86db456f7680");
52 51

  
53 52
    static {
54 53

  
......
61 60

  
62 61
    }
63 62

  
63
// ***************************** GETTER/SETTER ***********************************/
64
    public String getInternalAreaSeparator() {
65
        return internalAreaSeparator;
66
    }
67

  
68
    public void setInternalAreaSeparator(String internalAreaSeparator) {
69
        this.internalAreaSeparator = internalAreaSeparator;
70
    }
71

  
72
// ***********************************************************************
73

  
64 74
    /**
65 75
     * {@inheritDoc}
66 76
     * @return
67 77
     */
68 78
    @Override
69 79
    public CondensedDistribution createCondensedDistribution(Collection<Distribution> filteredDistributions,
70
            List<Language> langs) {
80
            List<Language> languages) {
71 81

  
72
        CondensedDistribution condensedDistribution = new CondensedDistribution();
82
        CondensedDistribution result = new CondensedDistribution();
83
//        Collection<NamedArea> allAreas = new HashSet<NamedArea>();
84
        //we expect every area only to have 1 status  (multiple status should have been filtered beforehand)
85
        Map<NamedArea, PresenceAbsenceTerm> areaToStatusMap = new HashMap<>();
73 86

  
74
        //empty
75
        if (filteredDistributions == null || filteredDistributions.isEmpty()){
76
            return condensedDistribution;
77
        }
78 87

  
79
        OrderedTermVocabulary<NamedArea> areaVocabulary = CdmBase.deproxy(filteredDistributions.iterator().next().getArea().getVocabulary(), OrderedTermVocabulary.class);
88
        //1. compute all areas and their status
89
        for(Distribution d : filteredDistributions) {
90
            PresenceAbsenceTerm status = d.getStatus();
91
            //TODO needed? Do we only want to have areas with status?
92
            if(status == null) {
93
                continue;
94
            }
80 95

  
81
        //deproxy and reverse order
82
        List<NamedArea> areaList = new ArrayList<NamedArea>();
83
        for (DefinedTermBase<NamedArea> dtb : areaVocabulary.getOrderedTerms()){
84
            areaList.add(0, (NamedArea)CdmBase.deproxy(dtb));
96
            NamedArea area = d.getArea();
97
            areaToStatusMap.put(area, status);
85 98
        }
86 99

  
87 100

  
88
        boolean isFirstAfterInternalArea = false;
89
        for (NamedArea area : areaList){
101
        //2. build the area hierarchy
102
        Map<NamedArea, AreaNode> areaNodeMap = new HashMap<>();
90 103

  
91
            if (area.getPartOf() != null){
92
                continue;  //subarea are handled later
104
        for(NamedArea area : areaToStatusMap.keySet()) {
105
            AreaNode node;
106
            if(!areaNodeMap.containsKey(area)) {
107
                // putting area into hierarchy as node
108
                node = new AreaNode(area);
109
                areaNodeMap.put(area, node);
110
            } else {
111
                //  is parent of another and thus already has a node
112
                node = areaNodeMap.get(area);
93 113
            }
94 114

  
95
            StringBuilder areaStatusString = new StringBuilder();
115
            NamedArea parent = findParentIn(area, areaToStatusMap.keySet());
116
            if(parent != null) {
117
                AreaNode parentNode;
118
                if(!areaNodeMap.containsKey(parent)) {
119
                    parentNode = new AreaNode(parent);
120
                    areaNodeMap.put(parent, parentNode);
121
                } else {
122
                    parentNode = areaNodeMap.get(parent);
123
                }
124
                parentNode.addSubArea(node);
125
            }
126
        }
96 127

  
128
        //3. find root nodes
129
        List<AreaNode>topLevelNodes = new ArrayList<AreaNode>();
130
        for(AreaNode node : areaNodeMap.values()) {
131
            if(!node.hasParent() && ! topLevelNodes.contains(node)) {
132
                topLevelNodes.add(node);
133
            }
134
        }
97 135

  
136
        //4. replace the area by the abbreviated representation and add symbols
137
        boolean isFirstAfterAreaOfScope = false;
138
        AreaNodeComparator areaNodeComparator = new AreaNodeComparator();
98 139

  
99
            Distribution distribution = getDistribution(area, filteredDistributions);
100
            if (distribution == null){
101
                continue;
102
            }
140
        Collections.sort(topLevelNodes, areaNodeComparator);
103 141

  
142
        for(AreaNode topLevelNode : topLevelNodes) {
143

  
144
            StringBuilder areaStatusString = new StringBuilder();
145

  
146
            NamedArea area = topLevelNode.area;
104 147
            if (area.getUuid().equals(uuidInternalArea)){
105
                isFirstAfterInternalArea = true;
106
            }else if(isFirstAfterInternalArea && !area.getUuid().equals(uuidInternalArea)){
148
                isFirstAfterAreaOfScope = true;
149
            }else if(isFirstAfterAreaOfScope && !area.getUuid().equals(uuidInternalArea)){
107 150
                areaStatusString.append(internalAreaSeparator);
108
                isFirstAfterInternalArea = false;
151
                isFirstAfterAreaOfScope = false;
109 152
            }
110 153

  
111
            PresenceAbsenceTerm status = distribution.getStatus();
112 154

  
113
            String statusSymbol = statusSymbol(status);
155
            PresenceAbsenceTerm status = areaToStatusMap.get(area);
156
            String statusSymbol = statusSymbol(areaToStatusMap.get(area));
114 157
            areaStatusString.append(statusSymbol);
115 158

  
116
            String areaLabel = makeAreaLabel(langs, area);
159
            String areaLabel = makeAreaLabel(languages, area);
117 160
            areaStatusString.append(areaLabel);
118 161

  
119
            if(!area.getIncludes().isEmpty()) {
120
//                areaStatusString.append('(');
121
                subAreaLabels(langs, area.getIncludes(), areaStatusString, statusSymbol, areaLabel, filteredDistributions);
122
//                areaStatusString.append(')');
162
            if(!topLevelNode.subAreas.isEmpty()) {
163
                areaStatusString.append('(');
164
                subAreaLabels(languages, topLevelNode.subAreas, areaStatusString, statusSymbol,
165
                        areaLabel, areaToStatusMap, areaNodeComparator);
166
                areaStatusString.append(')');
123 167
            }
124 168

  
125

  
126 169
//            if(isForeignStatus(status)) {
127 170
//                condensedDistribution.addForeignDistributionItem(status, areaStatusString.toString(), areaLabel);
128 171
//            } else {
129
                condensedDistribution.addIndigenousDistributionItem(status, areaStatusString.toString(), areaLabel);
172
                result.addIndigenousDistributionItem(status, areaStatusString.toString(), areaLabel);
130 173
//            }
131

  
132 174
        }
133 175

  
134
//        }
135
//        //5. order the condensedDistributions alphabetically
136
//        // FIXME
137
//        condensedDistribution.sortForeign();
138
//        condensedDistribution.sortIndigenous();
139

  
140
        return condensedDistribution;
176
        return result;
141 177
    }
142 178

  
143 179
    /**
144
     * @param area
145
     * @param filteredDistributions
146
     * @return
180
     * Recursive call to create sub area label strings
181
     * @param areaNodeComparator
147 182
     */
148
    private Distribution getDistribution(NamedArea area, Collection<Distribution> filteredDistributions) {
149
        for (Distribution dist : filteredDistributions){
150
            if (dist.getArea() != null && dist.getArea().equals(area)){
151
                return dist;
152
            }
153
        }
154
        return null;
155
    }
183
    private void subAreaLabels(List<Language> languages, Collection<AreaNode> nodes, StringBuilder totalStringBuilder,
184
            String parentStatusSymbol, String parentLabel,
185
            Map<NamedArea, PresenceAbsenceTerm> areaToStatusMap, AreaNodeComparator areaNodeComparator) {
156 186

  
157

  
158
//    private boolean isForeignStatus(PresenceAbsenceTerm status) {
159
//        return foreignStatusUuids.contains(status.getUuid());
160
//    }
161

  
162
    /**
163
     * @param langs
164
     * @param node
165
     * @param areaString
166
     * @param statusSymbol
167
     */
168
    private void subAreaLabels(List<Language> langs, Collection<NamedArea> subAreas, StringBuilder areaString,
169
            String statusSymbol, String parentLabel,
170
            Collection<Distribution> filteredDistributions) {
171
        //TODO very redundant with main method
172 187
        List<String> subAreaLabels = new ArrayList<String>();
173 188

  
174
        //deproxy and reverse order
175
        List<NamedArea> areaList = new ArrayList<NamedArea>();
176
        for (DefinedTermBase<NamedArea> dtb : subAreas){
177
            areaList.add(0, (NamedArea)CdmBase.deproxy(dtb));
178
        }
189
        List<AreaNode> areaNodes = new ArrayList<>(nodes);
190
        Collections.sort(areaNodes, areaNodeComparator);
179 191

  
180
        for(NamedArea area : areaList) {
192
        for(AreaNode node : areaNodes) {
181 193

  
182 194
            StringBuilder subAreaString = new StringBuilder();
183
            Distribution distribution = getDistribution(area, filteredDistributions);
184
            if (distribution == null){
185
                continue;
186
            }
187 195

  
188

  
189
            PresenceAbsenceTerm status = distribution.getStatus();
196
            NamedArea area = node.area;
197
            PresenceAbsenceTerm status = areaToStatusMap.get(area);
190 198
            String subAreaStatusSymbol = statusSymbol(status);
191
            if (subAreaStatusSymbol != null && !subAreaStatusSymbol.equals(statusSymbol)){
199
            if (subAreaStatusSymbol != null && !subAreaStatusSymbol.equals(parentStatusSymbol)){
192 200
                subAreaString.append(subAreaStatusSymbol);
193 201
            }
194 202

  
195
            String areaLabel = makeAreaLabel(langs, area);
196
//            String cleanSubAreaLabel = StringUtils.replaceEach(areaLabel, new String[] {parentLabel, "(", ")"}, new String[] {"", "", ""});
197
            String cleanSubAreaLabel = areaLabel;
198
            subAreaString.append(cleanSubAreaLabel);
203
            String areaLabel = makeAreaLabel(languages, area);
204
            if(replaceCommonAreaLabelStart){
205
                String cleanSubAreaLabel = StringUtils.replaceEach(areaLabel, new String[] {parentLabel, "(", ")"}, new String[] {"", "", ""});
206
                subAreaString.append(cleanSubAreaLabel);
207
            }else{
208
                subAreaString.append(areaLabel);
209
            }
199 210

  
200
            if(!area.getIncludes().isEmpty()) {
201
//                subAreaString.append('(');
202
                subAreaLabels(langs, area.getIncludes(), subAreaString, subAreaStatusSymbol, areaLabel, filteredDistributions);
203
//                subAreaString.append(')');
211
            if(!node.subAreas.isEmpty()) {
212
                subAreaString.append('(');
213
                subAreaLabels(languages, node.subAreas, subAreaString, subAreaStatusSymbol, areaLabel,
214
                        areaToStatusMap, areaNodeComparator);
215
                subAreaString.append(')');
204 216
            }
205 217

  
206 218
            subAreaLabels.add(subAreaString.toString());
207 219
        }
208

  
209
//      Collections.sort(subAreaLabels);
210
        if (!subAreaLabels.isEmpty()){
211
            areaString.append("(" + StringUtils.join(subAreaLabels, " ") + ")");
212
        }
213

  
214
    }
215

  
216
    /**
217
     * @param langs
218
     * @param area
219
     * @return
220
     */
221
    private String makeAreaLabel(List<Language> langs, NamedArea area) {
222
        String result = area.getIdInVocabulary() != null ? area.getIdInVocabulary() :area.getPreferredRepresentation(langs).getAbbreviatedLabel();
223
        return areaPreTag + result + areaPostTag;
220
//        Collections.sort(subAreaLabels);
221
        totalStringBuilder.append(StringUtils.join(subAreaLabels, " "));
224 222
    }
225 223

  
226

  
227

  
228
    public String getInternalAreaSeparator() {
229
        return internalAreaSeparator;
230
    }
231

  
232
    public void setInternalAreaSeparator(String internalAreaSeparator) {
233
        this.internalAreaSeparator = internalAreaSeparator;
234
    }
235

  
236
    /**
237
     * Searches for the parent are of the area given as parameter in
238
     * the Collection of areas.
239
     *
240
     * @parent area
241
     *      The area whose parent area is to be searched
242
     * @param collection
243
     *      The areas to search in.
244
     *
245
     * @return
246
     *      Either the parent if it has been found or null.
247
     */
248
    private NamedArea findParentIn(NamedArea area, Collection<NamedArea> areas) {
249
        NamedArea parent = area.getPartOf();
250
        if(parent != null && areas.contains(parent)){
251
            return parent;
252
        }
253
        return null;
254
    }
255

  
256
    class AreaNode {
257

  
258
        private final NamedArea area;
259
        private AreaNode parent = null;
260
        private final Set<AreaNode> subAreas = new HashSet<AreaNode>();
261

  
262
        /**
263
         * @param area
264
         */
265
        public AreaNode(NamedArea area) {
266
            this.area = area;
267
        }
268

  
269
        public void addSubArea(AreaNode subArea) {
270
            subAreas.add(subArea);
271
            subArea.parent = this;
272
        }
273

  
274
        public AreaNode getParent() {
275
            return parent;
276
        }
277

  
278
        public boolean hasParent() {
279
            return getParent() != null;
280
        }
281

  
282
        public Collection<NamedArea> getSubareas() {
283
            Collection<NamedArea> areas = new HashSet<NamedArea>();
284
            for(AreaNode node : subAreas) {
285
                areas.add(node.area);
224
    private class AreaNodeComparator implements Comparator<AreaNode>{
225

  
226
        @Override
227
        public int compare(AreaNode areaNode1, AreaNode areaNode2) {
228
            NamedArea area1 = areaNode1.area;
229
            NamedArea area2 = areaNode2.area;
230

  
231
            if (area1 == null && area2 == null){
232
                return 0;
233
            }else if (area1 == null){
234
                return -1;
235
            }else if (area2 == null){
236
                return 1;
237
            }else{
238
                //- due to wrong ordering behavior in DefinedTerms
239
                return - area1.compareTo(area2);
286 240
            }
287
            return areas;
288 241
        }
289
    }
290

  
291 242

  
243
    }
292 244

  
293 245
}

Also available in: Unified diff