3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
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.
11 package eu
.etaxonomy
.cdm
.ext
.geo
;
13 import java
.awt
.Color
;
14 import java
.io
.UnsupportedEncodingException
;
15 import java
.net
.URLEncoder
;
16 import java
.util
.ArrayList
;
17 import java
.util
.Collection
;
18 import java
.util
.HashMap
;
19 import java
.util
.HashSet
;
20 import java
.util
.List
;
23 import java
.util
.UUID
;
25 import javax
.persistence
.Transient
;
27 import org
.apache
.commons
.lang
.StringUtils
;
28 import org
.apache
.log4j
.Logger
;
30 import eu
.etaxonomy
.cdm
.api
.utility
.DescriptionUtility
;
31 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
32 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
33 import eu
.etaxonomy
.cdm
.model
.common
.Representation
;
34 import eu
.etaxonomy
.cdm
.model
.common
.TermVocabulary
;
35 import eu
.etaxonomy
.cdm
.model
.description
.Distribution
;
36 import eu
.etaxonomy
.cdm
.model
.description
.PresenceAbsenceTermBase
;
37 import eu
.etaxonomy
.cdm
.model
.description
.PresenceTerm
;
38 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
39 import eu
.etaxonomy
.cdm
.model
.location
.NamedAreaLevel
;
40 import eu
.etaxonomy
.cdm
.model
.location
.Point
;
41 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationType
;
42 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IDefinedTermDao
;
45 * Class implementing the business logic for creating the map service string for
46 * a given set of distributions. See {@link EditGeoService} as API for the given functionality.
53 public class EditGeoServiceUtilities
{
54 private static final Logger logger
= Logger
.getLogger(EditGeoServiceUtilities
.class);
56 private static PresenceAbsenceTermBase
<?
> defaultStatus
= PresenceTerm
.PRESENT();
58 private static IDefinedTermDao termDao
;
65 public static void setTermDao(IDefinedTermDao termDao
) {
66 EditGeoServiceUtilities
.termDao
= termDao
;
69 private static HashMap
<SpecimenOrObservationType
, Color
> defaultSpecimenOrObservationTypeColors
= null;
71 private static HashMap
<SpecimenOrObservationType
, Color
> getDefaultSpecimenOrObservationTypeColors() {
72 if(defaultSpecimenOrObservationTypeColors
== null){
73 defaultSpecimenOrObservationTypeColors
= new HashMap
<SpecimenOrObservationType
, Color
>();
74 defaultSpecimenOrObservationTypeColors
.put(SpecimenOrObservationType
.FieldUnit
, Color
.ORANGE
);
75 defaultSpecimenOrObservationTypeColors
.put(SpecimenOrObservationType
.DerivedUnit
, Color
.RED
);
76 defaultSpecimenOrObservationTypeColors
.put(SpecimenOrObservationType
.LivingSpecimen
, Color
.GREEN
);
77 defaultSpecimenOrObservationTypeColors
.put(SpecimenOrObservationType
.Observation
, Color
.ORANGE
);
78 defaultSpecimenOrObservationTypeColors
.put(SpecimenOrObservationType
.PreservedSpecimen
, Color
.GRAY
);
79 defaultSpecimenOrObservationTypeColors
.put(SpecimenOrObservationType
.Media
, Color
.BLUE
);
81 return defaultSpecimenOrObservationTypeColors
;
85 private static HashMap
<PresenceAbsenceTermBase
<?
>, Color
> defaultPresenceAbsenceTermBaseColors
= null;
87 private static HashMap
<PresenceAbsenceTermBase
<?
>, Color
> getDefaultPresenceAbsenceTermBaseColors() {
88 if(defaultPresenceAbsenceTermBaseColors
== null){
89 defaultPresenceAbsenceTermBaseColors
= new HashMap
<PresenceAbsenceTermBase
<?
>, Color
>();
90 defaultPresenceAbsenceTermBaseColors
.put(PresenceTerm
.PRESENT(), Color
.decode("0x4daf4a"));
91 defaultPresenceAbsenceTermBaseColors
.put(PresenceTerm
.NATIVE(), Color
.decode("0x4daf4a"));
92 defaultPresenceAbsenceTermBaseColors
.put(PresenceTerm
.NATIVE_DOUBTFULLY_NATIVE(), Color
.decode("0x377eb8"));
93 defaultPresenceAbsenceTermBaseColors
.put(PresenceTerm
.CULTIVATED(), Color
.decode("0x984ea3"));
94 defaultPresenceAbsenceTermBaseColors
.put(PresenceTerm
.INTRODUCED(), Color
.decode("0xff7f00"));
95 defaultPresenceAbsenceTermBaseColors
.put(PresenceTerm
.INTRODUCED_ADVENTITIOUS(), Color
.decode("0xffff33"));
96 defaultPresenceAbsenceTermBaseColors
.put(PresenceTerm
.INTRODUCED_CULTIVATED(), Color
.decode("0xa65628"));
97 defaultPresenceAbsenceTermBaseColors
.put(PresenceTerm
.INTRODUCED_NATURALIZED(), Color
.decode("0xf781bf"));
100 * and now something very hacky ...
101 * ONLY-A-TEST is set by the Test class EditGeoServiceTest
103 * TODO remove according line from
104 * EditGeoServiceTest.setUp() when the hardcoded colors for flora of
105 * cyprus are no further needed !!
107 String onlyTest
= System
.getProperty("ONLY-A-TEST"); //
108 if(onlyTest
!= null && onlyTest
.equals("TRUE")){
109 return defaultPresenceAbsenceTermBaseColors
;
111 //special colors for flora of cyprus !!! see HACK above !!!
112 UUID indigenousUuid
= UUID
.fromString("b325859b-504b-45e0-9ef0-d5c1602fcc0f");
113 UUID indigenousQUuid
= UUID
.fromString("17bc601f-53eb-4997-a4bc-c03ce5bfd1d3");
115 UUID cultivatedQUuid
= UUID
.fromString("4f31bfc8-3058-4d83-aea5-3a1fe9773f9f");
117 UUID casualUuid
= UUID
.fromString("5e81353c-38a3-4ca6-b979-0d9abc93b877");
118 UUID casualQUuid
= UUID
.fromString("73f75493-1185-4a3e-af1e-9a1f2e8dadb7");
120 UUID naturalizedNonInvasiveUuid
= UUID
.fromString("1b025e8b-901a-42e8-9739-119b410c6f03");
121 UUID naturalizedNonInvasiveQUuid
= UUID
.fromString("11f56e2f-c16c-4b3d-a870-bb5d3b20e624");
123 UUID naturalizedInvasiveUuid
= UUID
.fromString("faf2d271-868a-4bf7-b0b8-a1c5ab309de2");
124 UUID naturalizedInvasiveQUuid
= UUID
.fromString("ac429d5f-e8ad-49ae-a41c-e4779b58b96a");
126 UUID questionablelUuid
= UUID
.fromString("4b48f675-a6cf-49f3-a5ba-77e2c2979eb3");
127 UUID questionableQUuid
= UUID
.fromString("914e7393-1314-4632-bc45-5eff3dc1e424");
129 UUID reportedInErrorUuid
= UUID
.fromString("38604788-cf05-4607-b155-86db456f7680");
131 defaultPresenceAbsenceTermBaseColors
.put((PresenceAbsenceTermBase
<?
>) termDao
.load(indigenousUuid
), Color
.decode("0x339966"));
132 defaultPresenceAbsenceTermBaseColors
.put((PresenceAbsenceTermBase
<?
>) termDao
.load(indigenousQUuid
), Color
.decode("0x339966"));
134 defaultPresenceAbsenceTermBaseColors
.put((PresenceAbsenceTermBase
<?
>) termDao
.load(cultivatedQUuid
), Color
.decode("0xbdb76b"));
136 defaultPresenceAbsenceTermBaseColors
.put((PresenceAbsenceTermBase
<?
>) termDao
.load(casualUuid
), Color
.decode("0xffff00"));
137 defaultPresenceAbsenceTermBaseColors
.put((PresenceAbsenceTermBase
<?
>) termDao
.load(casualQUuid
), Color
.decode("0xffff00"));
139 defaultPresenceAbsenceTermBaseColors
.put((PresenceAbsenceTermBase
<?
>) termDao
.load(naturalizedNonInvasiveUuid
), Color
.decode("0xff9900"));
140 defaultPresenceAbsenceTermBaseColors
.put((PresenceAbsenceTermBase
<?
>) termDao
.load(naturalizedNonInvasiveQUuid
), Color
.decode("0xff9900"));
142 defaultPresenceAbsenceTermBaseColors
.put((PresenceAbsenceTermBase
<?
>) termDao
.load(naturalizedInvasiveUuid
), Color
.decode("0xff0000"));
143 defaultPresenceAbsenceTermBaseColors
.put((PresenceAbsenceTermBase
<?
>) termDao
.load(naturalizedInvasiveQUuid
), Color
.decode("0xff0000"));
145 defaultPresenceAbsenceTermBaseColors
.put((PresenceAbsenceTermBase
<?
>) termDao
.load(questionablelUuid
), Color
.decode("0x00ccff"));
146 defaultPresenceAbsenceTermBaseColors
.put((PresenceAbsenceTermBase
<?
>) termDao
.load(questionableQUuid
), Color
.decode("0x00ccff"));
148 defaultPresenceAbsenceTermBaseColors
.put((PresenceAbsenceTermBase
<?
>) termDao
.load(reportedInErrorUuid
), Color
.decode("0xcccccc"));
151 return defaultPresenceAbsenceTermBaseColors
;
156 private static final String SUBENTRY_DELIMITER
= ",";
157 private static final String ENTRY_DELIMITER
= ";";
158 static final String ID_FROM_VALUES_SEPARATOR
= ":";
159 static final String VALUE_LIST_ENTRY_SEPARATOR
= "|";
160 static final String VALUE_SUPER_LIST_ENTRY_SEPARATOR
= "||";
164 //preliminary implementation for TDWG areas
166 * Returns the parameter String for the EDIT geo webservice to create a
169 * @param distributions
170 * A set of distributions that should be shown on the map
171 * @param presenceAbsenceTermColors
172 * A map that defines the colors of PresenceAbsenceTerms. The
173 * PresenceAbsenceTerms are defined by their uuid. If a
174 * PresenceAbsenceTerm is not included in this map, it's default
175 * color is taken instead. If the map == null all terms are
176 * colored by their default color.
182 * The maps bounding box (e.g. "-180,-90,180,90" for the whole
184 * @param projectToLayer
185 * name of a layer which is representing a specific
186 * {@link NamedAreaLevel} Supply this parameter if you to project
187 * all other distribution area levels to this layer.
189 * The layer that is responsible for background borders and
190 * colors. Use the name for the layer. If null 'earth' is taken
192 * @return the parameter string or an empty string if the
193 * <code>distributions</code> set was null or empty.
196 public static String
getDistributionServiceRequestParameterString(
197 Set
<Distribution
> distributions
,
198 IGeoServiceAreaMapping mapping
,
199 Map
<PresenceAbsenceTermBase
<?
>,Color
> presenceAbsenceTermColors
,
203 String baseLayerName
,
204 String projectToLayer
,
205 List
<Language
> languages
){
209 * generateMultipleAreaDataParameters switches between the two possible styles:
210 * 1. ad=layername1:area-data||layername2:area-data
211 * 2. ad=layername1:area-data&ad=layername2:area-data
213 boolean generateMultipleAreaDataParameters
= false;
215 List
<String
> perLayerAreaData
= new ArrayList
<String
>();
216 List
<String
> areaStyles
= new ArrayList
<String
>();
217 List
<String
> legendLabels
= new ArrayList
<String
>();
220 String borderWidth
= "0.1";
221 String borderColorRgb
= "";
222 String borderDashingPattern
= "";
226 if(distributions
== null || distributions
.size() == 0){
230 Collection
<Distribution
> filteredDistributions
= DescriptionUtility
.filterDistributions(distributions
);
232 Map
<String
, Map
<Integer
, Set
<Distribution
>>> layerMap
= new HashMap
<String
, Map
<Integer
, Set
<Distribution
>>>();
233 List
<PresenceAbsenceTermBase
<?
>> statusList
= new ArrayList
<PresenceAbsenceTermBase
<?
>>();
235 groupStylesAndLayers(filteredDistributions
, layerMap
, statusList
, mapping
);
237 presenceAbsenceTermColors
= mergeMaps(getDefaultPresenceAbsenceTermBaseColors(), presenceAbsenceTermColors
);
239 Map
<String
, String
> parameters
= new HashMap
<String
, String
>();
243 parameters
.put("bbox", bbox
);
246 String ms
= compileMapSizeParameterValue(width
, height
);
248 parameters
.put("ms", ms
);
251 if (StringUtils
.isBlank(baseLayerName
)){
252 baseLayerName
= "earth";
254 parameters
.put("l", baseLayerName
);
258 for (PresenceAbsenceTermBase
<?
> status
: statusList
){
260 char styleId
= getStyleAbbrev(i
);
262 //getting the area title
263 if (languages
== null){
264 languages
= new ArrayList
<Language
>();
266 if (languages
.size() == 0){
267 languages
.add(Language
.DEFAULT());
269 Representation representation
= status
.getPreferredRepresentation(languages
);
270 String statusLabel
= representation
.getLabel();
271 //statusLabel.replace('introduced: ', '');
272 statusLabel
= statusLabel
.replace("introduced: ", "introduced, ");
273 statusLabel
= statusLabel
.replace("native: ", "native, ");
275 //getting the area color
276 Color statusColor
= presenceAbsenceTermColors
.get(status
);
278 if (statusColor
!= null){
279 fillColorRgb
= Integer
.toHexString(statusColor
.getRGB()).substring(2);
282 fillColorRgb
= status
.getDefaultColor(); //TODO
284 fillColorRgb
= defaultStatus
.getDefaultColor();
287 String styleValues
= StringUtils
.join(new String
[]{fillColorRgb
, borderColorRgb
, borderWidth
, borderDashingPattern
}, ',');
289 areaStyles
.add(styleId
+ ID_FROM_VALUES_SEPARATOR
+ styleValues
);
290 legendLabels
.add(styleId
+ ID_FROM_VALUES_SEPARATOR
+ encode(statusLabel
));
294 if(areaStyles
.size() > 0){
295 parameters
.put("as", StringUtils
.join(areaStyles
.iterator(), VALUE_LIST_ENTRY_SEPARATOR
));
297 if(legendLabels
.size() > 0){
298 parameters
.put("title", StringUtils
.join(legendLabels
.iterator(), VALUE_LIST_ENTRY_SEPARATOR
));
302 List
<String
> stylesPerLayer
;
303 List
<String
> areasPerStyle
;
304 for (String layerString
: layerMap
.keySet()){
306 stylesPerLayer
= new ArrayList
<String
>();
307 Map
<Integer
, Set
<Distribution
>> styleMap
= layerMap
.get(layerString
);
308 for (int style
: styleMap
.keySet()){
310 char styleChar
= getStyleAbbrev(style
);
311 Set
<Distribution
> distributionSet
= styleMap
.get(style
);
312 areasPerStyle
= new ArrayList
<String
>();
313 for (Distribution distribution
: distributionSet
){
315 areasPerStyle
.add(encode(getAreaAbbrev(distribution
, mapping
)));
317 stylesPerLayer
.add(styleChar
+ ID_FROM_VALUES_SEPARATOR
+ StringUtils
.join(areasPerStyle
.iterator(), SUBENTRY_DELIMITER
));
319 perLayerAreaData
.add(encode(layerString
) + ID_FROM_VALUES_SEPARATOR
+ StringUtils
.join(stylesPerLayer
.iterator(), VALUE_LIST_ENTRY_SEPARATOR
));
323 if(generateMultipleAreaDataParameters
){
324 // not generically possible since parameters can not contain duplicate keys with value "ad"
326 parameters
.put("ad", StringUtils
.join(perLayerAreaData
.iterator(), VALUE_SUPER_LIST_ENTRY_SEPARATOR
));
329 String queryString
= makeQueryString(parameters
);
330 logger
.debug("getDistributionServiceRequestParameterString(): " + queryString
);
337 * Fills the layerMap and the statusList
339 * @param distributions
340 * @param layerMap see {@link #addAreaToLayerMap(Map, List, Distribution, NamedArea, IGeoServiceAreaMapping)}
343 private static void groupStylesAndLayers(Collection
<Distribution
> distributions
,
344 Map
<String
, Map
<Integer
,Set
<Distribution
>>> layerMap
,
345 List
<PresenceAbsenceTermBase
<?
>> statusList
,
346 IGeoServiceAreaMapping mapping
) {
349 //iterate through distributions and group styles and layers
350 //and collect necessary information
351 for (Distribution distribution
: distributions
){
353 PresenceAbsenceTermBase
<?
> status
= distribution
.getStatus();
355 status
= defaultStatus
;
357 if (! statusList
.contains(status
)){
358 statusList
.add(status
);
360 //group areas by layers and styles
361 NamedArea area
= distribution
.getArea();
363 addAreaToLayerMap(layerMap
, statusList
, distribution
, area
, mapping
);
368 * A layer map holds the following information:
371 * <li><b>String</b>: the WMSLayerName which matches the level of the
372 * contained distributions areas</li>
373 * <li><b>StyleMap</b>:</li>
375 * <li><b>Integer</b>: the index of the status in the
376 * <code>statusList</code></li>
377 * <li><b>Set{@code<Distribution>}</b>: the set of distributions having the
378 * same Status, the status list is populated in {@link #groupStylesAndLayers(Set, Map, List, IGeoServiceAreaMapping)}</li>
384 * @param distribution
387 private static void addAreaToLayerMap(Map
<String
, Map
<Integer
,
388 Set
<Distribution
>>> layerMap
,
389 List
<PresenceAbsenceTermBase
<?
>> statusList
,
390 Distribution distribution
,
392 IGeoServiceAreaMapping mapping
) {
395 String geoLayerString
= getWMSLayerName(area
, mapping
);
397 if(geoLayerString
== null){
399 // if no layer is mapped this area descend into sub areas in order to project
400 // the distribution to those
401 for(NamedArea subArea
: area
.getIncludes()){
402 addAreaToLayerMap(layerMap
, statusList
, distribution
, subArea
, mapping
);
407 Map
<Integer
, Set
<Distribution
>> styleMap
= layerMap
.get(geoLayerString
);
408 if (styleMap
== null) {
409 styleMap
= new HashMap
<Integer
, Set
<Distribution
>>();
410 layerMap
.put(geoLayerString
, styleMap
);
412 addDistributionToStyleMap(distribution
, styleMap
, statusList
);
419 private static String
compileMapSizeParameterValue(int width
, int height
) {
421 String widthStr
= "";
422 String heightStr
= "";
425 widthStr
= "" + width
;
428 heightStr
= SUBENTRY_DELIMITER
+ height
;
430 String ms
= widthStr
+ heightStr
;
431 if(ms
.length() == 0){
438 * URI encode the given String
442 private static String
encode(String string
) {
443 String encoded
= string
;
445 encoded
= URLEncoder
.encode(string
, "UTF-8");
446 } catch (UnsupportedEncodingException e
) {
453 * combine parameter into a URI query string fragment. The values will be
457 * @return a URI query string fragment
459 private static String
makeQueryString(Map
<String
, String
> parameters
){
460 StringBuilder queryString
= new StringBuilder();
461 for (String key
: parameters
.keySet()) {
462 if(queryString
.length() > 0){
463 queryString
.append('&');
465 if(key
.equals("od") || key
.equals("os") || key
.equals("ms") || key
.equals("ad") || key
.equals("as") || key
.equals("title") || key
.equals("bbox")){
466 queryString
.append(key
).append('=').append(parameters
.get(key
));
468 queryString
.append(key
).append('=').append(encode(parameters
.get(key
)));
471 return queryString
.toString();
474 private static String
getAreaAbbrev(Distribution distribution
, IGeoServiceAreaMapping mapping
){
475 NamedArea area
= distribution
.getArea();
476 TermVocabulary
<NamedArea
> voc
= area
.getVocabulary();
477 String result
= null;
478 if (voc
!= null && voc
.getUuid().equals(NamedArea
.uuidTdwgAreaVocabulary
) || voc
.getUuid().equals(uuidCyprusDivisionsVocabulary
) ){
479 Representation representation
= area
.getRepresentation(Language
.DEFAULT());
480 result
= representation
.getAbbreviatedLabel();
481 if (area
.getLevel() != null && area
.getLevel().equals(NamedAreaLevel
.TDWG_LEVEL4())){
482 result
= result
.replace("-", "");
486 GeoServiceArea areas
=mapping
.valueOf(area
);
487 if ((areas
!= null) && areas
.size()>0){
488 //FIXME multiple layers
489 List
<String
> values
= areas
.getAreasMap().values().iterator().next().values().iterator().next();
490 for (String value
: values
){
491 result
= CdmUtils
.concat(SUBENTRY_DELIMITER
, result
, value
);
496 return CdmUtils
.Nz(result
, "-");
502 //Preliminary as long as user defined areas are not fully implemented
503 public static final UUID uuidCyprusDivisionsVocabulary
= UUID
.fromString("2119f610-1f93-4d87-af28-40aeefaca100");
505 private static List
<String
> projectToWMSSubLayer(NamedArea area
){
507 List
<String
> layerNames
= new ArrayList
<String
>();
508 String matchedLayerName
= null;
509 TermVocabulary
<NamedArea
> voc
= area
.getVocabulary();
511 if (voc
.getUuid().equals(NamedArea
.uuidTdwgAreaVocabulary
)){
512 NamedAreaLevel level
= area
.getLevel();
514 //TODO integrate into CDM
515 if (level
.equals(NamedAreaLevel
.TDWG_LEVEL1())) {
516 matchedLayerName
= "tdwg1" ;
517 } else if (level
.equals(NamedAreaLevel
.TDWG_LEVEL2())) {
518 matchedLayerName
= "tdwg2";
519 }else if (level
.equals(NamedAreaLevel
.TDWG_LEVEL3())) {
520 matchedLayerName
= "tdwg3";
521 }else if (level
.equals(NamedAreaLevel
.TDWG_LEVEL4())) {
522 matchedLayerName
= "tdwg4";
525 //unrecognized tdwg area
528 //TODO hardcoded for cyprus (as long as user defined areas are not fully implemented). Remove afterwards.
529 if (voc
.getUuid().equals(uuidCyprusDivisionsVocabulary
)){
530 matchedLayerName
= "cyprusdivs:bdcode";
533 // check if the matched layer equals the layer to project to
534 // if not: recurse into the sub-level in order to find the specified one.
535 String
[] matchedLayerNameTokens
= StringUtils
.split(matchedLayerName
, ':');
536 // if(matchedLayerNameTokens.length > 0 && matchedLayerNameTokens[0] != projectToLayer){
537 // for (NamedArea subArea : area.getIncludes()){
547 private static String
getWMSLayerName(NamedArea area
, IGeoServiceAreaMapping mapping
){
548 TermVocabulary
<NamedArea
> voc
= area
.getVocabulary();
550 if (voc
.getUuid().equals(NamedArea
.uuidTdwgAreaVocabulary
)){
551 NamedAreaLevel level
= area
.getLevel();
553 //TODO integrate into CDM
554 if (level
.equals(NamedAreaLevel
.TDWG_LEVEL1())) {
556 } else if (level
.equals(NamedAreaLevel
.TDWG_LEVEL2())) {
558 }else if (level
.equals(NamedAreaLevel
.TDWG_LEVEL3())) {
560 }else if (level
.equals(NamedAreaLevel
.TDWG_LEVEL4())) {
564 //unrecognized tdwg area
568 //hardcoded for cyprus (as long as user defined areas are not fully implemented). Remove afterwards.
569 if (voc
.getUuid().equals(uuidCyprusDivisionsVocabulary
)){
570 return "cyprusdivs:bdcode";
573 GeoServiceArea areas
= mapping
.valueOf(area
);
574 if (areas
!= null && areas
.getAreasMap().size() > 0){
575 //FIXME multiple layers
576 String layer
= areas
.getAreasMap().keySet().iterator().next();
577 Map
<String
, List
<String
>> fields
= areas
.getAreasMap().get(layer
);
578 String field
= fields
.keySet().iterator().next();
579 return layer
+ ":" + field
;
586 private static void addDistributionToStyleMap(Distribution distribution
, Map
<Integer
, Set
<Distribution
>> styleMap
,
587 List
<PresenceAbsenceTermBase
<?
>> statusList
) {
588 PresenceAbsenceTermBase
<?
> status
= distribution
.getStatus();
589 if (status
== null) {
590 status
= defaultStatus
;
592 int style
= statusList
.indexOf(status
);
593 Set
<Distribution
> distributionSet
= styleMap
.get(style
);
594 if (distributionSet
== null) {
595 distributionSet
= new HashSet
<Distribution
>();
596 styleMap
.put(style
, distributionSet
);
598 distributionSet
.add(distribution
);
602 * @param fieldUnitPoints
603 * @param derivedUnitPoints
604 * @param specimenOrObservationTypeColors
605 * @param doReturnImage TODO
618 * &od=1%3A44.29481%2C6.82161|44.29252%2C6.822873|44.29247%2C6.82346|44.29279%2C6.823678|44.29269%2C6.82394|44.28482%2C6.887252|44.11469%2C7.287144|44.11468%2C7.289168
619 * &os=1%3Ac%2FFFD700%2F10%2FAporrectodea caliginosa
621 public static String
getOccurrenceServiceRequestParameterString(
622 List
<Point
> fieldUnitPoints
,
623 List
<Point
> derivedUnitPoints
,
624 Map
<SpecimenOrObservationType
, Color
> specimenOrObservationTypeColors
,
625 Boolean doReturnImage
, Integer width
, Integer height
, String bbox
, String backLayer
) {
627 specimenOrObservationTypeColors
= mergeMaps(getDefaultSpecimenOrObservationTypeColors(), specimenOrObservationTypeColors
);
629 Map
<String
, String
> parameters
= new HashMap
<String
, String
>();
630 parameters
.put("legend", "0");
631 parameters
.put("image", doReturnImage
!= null && doReturnImage ?
"true" : "false");
632 parameters
.put("recalculate", "false"); // TODO add parameter to method
634 parameters
.put("bbox", bbox
);
636 if(width
!= null || height
!= null){
637 parameters
.put("ms", compileMapSizeParameterValue(width
, height
));
640 Map
<String
, String
> styleAndData
= new HashMap
<String
, String
>();
642 addToStyleAndData(fieldUnitPoints
, SpecimenOrObservationType
.FieldUnit
, specimenOrObservationTypeColors
, styleAndData
);
643 addToStyleAndData(derivedUnitPoints
, SpecimenOrObservationType
.DerivedUnit
, specimenOrObservationTypeColors
, styleAndData
);
645 parameters
.put("os", StringUtils
.join(styleAndData
.keySet().iterator(), "||"));
646 parameters
.put("od", StringUtils
.join(styleAndData
.values().iterator(), "||"));
648 String queryString
= makeQueryString(parameters
);
650 logger
.info(queryString
);
662 private static <T
, S
> Map
<T
, S
> mergeMaps(Map
<T
, S
> defaultMap
, Map
<T
, S
> overrideMap
) {
663 Map
<T
, S
> tmpMap
= new HashMap
<T
, S
>();
664 tmpMap
.putAll(defaultMap
);
665 if(overrideMap
!= null){
666 tmpMap
.putAll(overrideMap
);
671 private static void addToStyleAndData(
673 SpecimenOrObservationType specimenOrObservationType
,
674 Map
<SpecimenOrObservationType
, Color
> specimenOrObservationTypeColors
, Map
<String
, String
> styleAndData
) {
676 //TODO add markerShape and size and Label to specimenOrObservationTypeColors -> Map<Class<SpecimenOrObservationBase<?>>, MapStyle>
678 if(points
!= null && points
.size()>0){
679 String style
= "c/" + Integer
.toHexString(specimenOrObservationTypeColors
.get(specimenOrObservationType
).getRGB()).substring(2) + "/10/noLabel";
680 StringBuilder data
= new StringBuilder();
681 for(Point point
: points
){
682 if(data
.length() > 0){
685 data
.append(point
.getLatitude() + "," + point
.getLongitude());
687 int index
= styleAndData
.size() + 1;
688 styleAndData
.put(index
+ ":" +style
, index
+ ":" +data
.toString());
694 * transform an integer (style counter) into a valid character representing a style.
697 * i not in {0,...,51} is undefined
701 private static char getStyleAbbrev(int i
){