2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
10 package eu
.etaxonomy
.cdm
.model
.description
;
12 import java
.awt
.Color
;
13 import java
.awt
.color
.ColorSpace
;
14 import java
.text
.DecimalFormat
;
15 import java
.util
.ArrayList
;
16 import java
.util
.HashMap
;
17 import java
.util
.HashSet
;
18 import java
.util
.List
;
21 import java
.util
.UUID
;
23 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
24 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
25 import eu
.etaxonomy
.cdm
.model
.common
.Representation
;
26 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
27 import eu
.etaxonomy
.cdm
.model
.location
.NamedAreaLevel
;
28 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
30 import org
.apache
.log4j
.Logger
;
31 import org
.hibernate
.annotations
.Cascade
;
32 import org
.hibernate
.annotations
.CascadeType
;
33 import javax
.persistence
.*;
34 import javax
.xml
.bind
.annotation
.XmlAccessType
;
35 import javax
.xml
.bind
.annotation
.XmlAccessorType
;
36 import javax
.xml
.bind
.annotation
.XmlElement
;
37 import javax
.xml
.bind
.annotation
.XmlIDREF
;
38 import javax
.xml
.bind
.annotation
.XmlRootElement
;
39 import javax
.xml
.bind
.annotation
.XmlSchemaType
;
40 import javax
.xml
.bind
.annotation
.XmlType
;
43 * This class represents elementary distribution data for a {@link Taxon taxon}.
44 * Only {@link TaxonDescription taxon descriptions} may contain distributions.
45 * A distribution instance consist of a {@link NamedArea named area} and of a {@link PresenceAbsenceTermBase status}
46 * describing the absence or the presence of a taxon (like "extinct"
47 * or "introduced") in this named area.
49 * This class corresponds partially to: <ul>
50 * <li> CodedDescriptionType according to the the SDD schema
51 * <li> Distribution according to the TDWG ontology
56 * @created 08-Nov-2007 13:06:21
58 @XmlAccessorType(XmlAccessType
.FIELD
)
59 @XmlType(name
= "Distribution", propOrder
= {
63 @XmlRootElement(name
= "Distribution")
65 public class Distribution
extends DescriptionElementBase
{
66 static Logger logger
= Logger
.getLogger(Distribution
.class);
68 @XmlElement(name
= "NamedArea")
70 @XmlSchemaType(name
= "IDREF")
71 private NamedArea area
;
73 @XmlElement(name
= "PresenceAbsenceStatus")
74 private PresenceAbsenceTermBase
<?
> status
;
78 * Class constructor: creates a new empty distribution instance.
79 * The corresponding {@link Feature feature} is set to {@link Feature#DISTRIBUTION() DISTRIBUTION}.
81 protected Distribution(){
82 super(Feature
.DISTRIBUTION());
87 * Creates an empty distribution instance. The corresponding {@link Feature feature}
88 * is set to {@link Feature#DISTRIBUTION() DISTRIBUTION}.
90 * @see #NewInstance(NamedArea, PresenceAbsenceTermBase)
92 public static Distribution
NewInstance(){
93 Distribution result
= new Distribution();
98 * Creates a distribution instance with the given {@link NamedArea named area} and {@link PresenceAbsenceTermBase status}.
99 * The corresponding {@link Feature feature} is set to {@link Feature#DISTRIBUTION() DISTRIBUTION}.
101 * @param area the named area for the new distribution
102 * @param status the presence or absence term for the new distribution
103 * @see #NewInstance()
105 public static Distribution
NewInstance(NamedArea area
, PresenceAbsenceTermBase
<?
> status
){
106 Distribution result
= new Distribution();
107 result
.setArea(area
);
108 result
.setStatus(status
);
116 * Deprecated because {@link Feature feature} should always be {@link Feature#DISTRIBUTION() DISTRIBUTION}
117 * for all distribution instances.
120 * @see eu.etaxonomy.cdm.model.description.DescriptionElementBase#setFeature(eu.etaxonomy.cdm.model.description.Feature)
124 public void setFeature(Feature feature
) {
125 super.setFeature(feature
);
129 * Returns the {@link NamedArea named area} <i>this</i> distribution applies to.
132 @Cascade({CascadeType
.SAVE_UPDATE
})
133 public NamedArea
getArea(){
139 public void setArea(NamedArea area
){
144 * Returns the {@link PresenceAbsenceTermBase presence or absence term} for <i>this</i> distribution.
147 public PresenceAbsenceTermBase
<?
> getStatus(){
153 public void setStatus(PresenceAbsenceTermBase
<?
> status
){
154 this.status
= status
;
157 //preliminary implementation for TDWG areas
159 * Returns the parameter String for the EDIT geo webservice to create a map.
160 * @param distributions A set of distributions that should be shown on the map
161 * @param presenceAbsenceTermColors A map that defines the colors of PresenceAbsenceTerms.
162 * The PresenceAbsenceTerms are defined by their uuid. If a PresenceAbsenceTerm is not included in
163 * this map, it's default color is taken instead. If the map == null all terms are colored by their default color.
164 * @param width The maps width
165 * @param height The maps height
166 * @param bbox The maps bounding box (e.g. "-180,-90,180,90" for the whole world)
167 * @param layer The layer that is responsible for background borders and colors. Use the name for the layer.
168 * If null 'earth' is taken as default.
171 //TODO move to an other place -> e.g. service layer
173 public static String
getEditGeoServiceUrlParameterString(Set
<Distribution
> distributions
, Map
<PresenceAbsenceTermBase
<?
>, Color
> presenceAbsenceTermColors
, int width
, int height
, String bbox
, String backLayer
){
176 String areaData
= "";
177 String areaStyle
= "";
178 String widthStr
= "";
179 String heightStr
= "";
180 String adLayerSeparator
= "/";
181 String msSeparator
= "x";
185 if (presenceAbsenceTermColors
== null) {
186 presenceAbsenceTermColors
= new HashMap
<PresenceAbsenceTermBase
<?
>, Color
>();
189 //List<String> layerStrings = new ArrayList<String>();
190 Map
<String
, Map
<Integer
, Set
<Distribution
>>> layerMap
= new HashMap
<String
, Map
<Integer
, Set
<Distribution
>>>();
191 List
<PresenceAbsenceTermBase
<?
>> statusList
= new ArrayList
<PresenceAbsenceTermBase
<?
>>();
195 // FIXME uncommented this as it can not be desirable to have default values in this method
196 // we need a parameterString that consists of essential parameters only
197 // defaults should be implemented in the geoservice itself.
198 //bbox ="bbox=-180,-90,180,90"; //earth is default
200 bbox
= "bbox=" + bbox
;
203 widthStr
= "" + width
;
206 heightStr
= msSeparator
+ height
;
208 String ms
= "ms=" + widthStr
+ heightStr
;
209 if (ms
.equals("ms=")){
213 //iterate through distributions and group styles and layers
214 //and collect necessary information
215 for (Distribution distribution
:distributions
){
217 PresenceAbsenceTermBase
<?
> status
= distribution
.getStatus();
218 if (! statusList
.contains(status
)){
219 statusList
.add(status
);
221 //group by layers and styles
222 NamedArea area
= distribution
.getArea();
224 NamedAreaLevel level
= area
.getLevel();
225 String geoLayerString
= getGeoServiceLayer(level
);
226 //Set<Distribution> layerDistributionSet;
227 //int index = layerStrings.indexOf(geoLayerString);
228 Map
<Integer
, Set
<Distribution
>> styleMap
= layerMap
.get(geoLayerString
);
229 if (styleMap
== null){
230 styleMap
= new HashMap
<Integer
, Set
<Distribution
>>();
231 layerMap
.put(geoLayerString
, styleMap
);
233 addDistributionToMap(distribution
, styleMap
, statusList
);
238 if (backLayer
== null || "".equals(layer
.trim())){
241 layer
= "l="+backLayer
;
242 // for (String layerString : layerMap.keySet()){
243 // layer += "," + layerString;
245 //layer = "l=" + layer.substring(1); //remove first |
250 Map
<PresenceAbsenceTermBase
<?
>, Character
> styleCharMap
= new HashMap
<PresenceAbsenceTermBase
<?
>, Character
>();
252 for (PresenceAbsenceTermBase
<?
> status
: statusList
){
253 char style
= getStyleAbbrev(i
);
254 Color statusColor
= presenceAbsenceTermColors
.get(status
);
256 if (statusColor
!= null){
257 rgb
= Integer
.toHexString(statusColor
.getRGB()).substring(2);
259 rgb
= status
.getDefaultColor(); //TODO
261 areaStyle
+= "|" + style
+ ":" + rgb
;
263 areaStyle
+= ",," + borderWidth
;
265 styleCharMap
.put(status
, style
);
269 areaStyle
= "as=" + areaStyle
.substring(1); //remove first |
273 boolean isFirstLayer
= true;
274 for (String layerString
: layerMap
.keySet()){
275 //Set<Distribution> layerDistributions = layerData.get(layerIndex);
276 //int distributionListIndex = 1;
277 areaData
+= (isFirstLayer?
"" : "||") + layerString
+ adLayerSeparator
;
278 Map
<Integer
, Set
<Distribution
>> styleMap
= layerMap
.get(layerString
);
279 boolean isFirstStyle
= true;
280 for (int style
: styleMap
.keySet()){
281 char styleChar
= getStyleAbbrev(style
);
282 areaData
+= (isFirstStyle?
"" : "|") + styleChar
+ ":";
283 Set
<Distribution
> distributionSet
= styleMap
.get(style
);
284 boolean isFirstDistribution
= true;
285 for (Distribution distribution
: distributionSet
){
286 String areaAbbrev
= getAreaAbbrev(distribution
);
287 areaData
+= (isFirstDistribution ?
"" : ",") + areaAbbrev
;
288 isFirstDistribution
= false;
290 isFirstStyle
= false;
292 isFirstLayer
= false;
295 areaData
= "ad=" + areaData
.substring(0); //remove first |
298 result
+= CdmUtils
.concat("&", new String
[] {layer
, areaData
, areaStyle
, bbox
, ms
});
302 private static String
getAreaAbbrev(Distribution distribution
){
303 NamedArea area
= distribution
.getArea();
304 Representation representation
= area
.getRepresentation(Language
.DEFAULT());
305 String areaAbbrev
= representation
.getAbbreviatedLabel();
306 if (area
.getLevel() != null && area
.getLevel().equals(NamedAreaLevel
.TDWG_LEVEL4())){
307 areaAbbrev
= areaAbbrev
.replace("-", "");
312 private static void addDistributionToMap(Distribution distribution
, Map
<Integer
, Set
<Distribution
>> styleMap
, List
<PresenceAbsenceTermBase
<?
>> statusList
){
313 int style
= statusList
.indexOf(distribution
.getStatus());
314 Set
<Distribution
> distributionSet
= styleMap
.get(style
);
315 if (distributionSet
== null){
316 distributionSet
= new HashSet
<Distribution
>();
317 styleMap
.put(style
, distributionSet
);
319 distributionSet
.add(distribution
);
324 * transform an integer (style counter) into a valid character representing a style.
327 * i not in {0,...,51} is undefined
331 private static char getStyleAbbrev(int i
){
340 private static String
getGeoServiceLayer(NamedAreaLevel level
){
341 //TODO integrate into CDM
342 if (level
.equals(NamedAreaLevel
.TDWG_LEVEL1())){
344 }else if (level
.equals(NamedAreaLevel
.TDWG_LEVEL2())){
346 }if (level
.equals(NamedAreaLevel
.TDWG_LEVEL3())){
348 }if (level
.equals(NamedAreaLevel
.TDWG_LEVEL4())){