Project

General

Profile

Download (64.7 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2007 EDIT
3
* European Distributed Institute of Taxonomy 
4
* http://www.e-taxonomy.eu
5
* 
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.
8
*/
9

    
10
package eu.etaxonomy.cdm.model.taxon;
11

    
12

    
13
import eu.etaxonomy.cdm.model.common.IRelated;
14
import eu.etaxonomy.cdm.model.common.RelationshipBase;
15
import eu.etaxonomy.cdm.model.description.TaxonDescription;
16
import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
17
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
18
import eu.etaxonomy.cdm.model.reference.ReferenceBase;
19
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
20
import eu.etaxonomy.cdm.strategy.cache.taxon.TaxonBaseDefaultCacheStrategy;
21

    
22
import org.apache.log4j.Logger;
23
import org.hibernate.annotations.Cascade;
24
import org.hibernate.annotations.CascadeType;
25
import org.hibernate.envers.Audited;
26
import org.hibernate.search.annotations.Indexed;
27
import org.springframework.beans.factory.annotation.Configurable;
28
import org.springframework.util.ReflectionUtils;
29

    
30
import java.lang.reflect.Field;
31
import java.util.ArrayList;
32
import java.util.Collections;
33
import java.util.HashMap;
34
import java.util.HashSet;
35
import java.util.Iterator;
36
import java.util.List;
37
import java.util.Map;
38
import java.util.Set;
39

    
40
import javax.persistence.Entity;
41
import javax.persistence.FetchType;
42
import javax.persistence.ManyToOne;
43
import javax.persistence.OneToMany;
44
import javax.persistence.Transient;
45
import javax.xml.bind.annotation.XmlAccessType;
46
import javax.xml.bind.annotation.XmlAccessorType;
47
import javax.xml.bind.annotation.XmlAttribute;
48
import javax.xml.bind.annotation.XmlElement;
49
import javax.xml.bind.annotation.XmlElementWrapper;
50
import javax.xml.bind.annotation.XmlIDREF;
51
import javax.xml.bind.annotation.XmlRootElement;
52
import javax.xml.bind.annotation.XmlSchemaType;
53
import javax.xml.bind.annotation.XmlType;
54

    
55
import org.apache.log4j.Logger;
56
import org.hibernate.annotations.Cascade;
57
import org.hibernate.annotations.CascadeType;
58
import org.hibernate.envers.Audited;
59
import org.hibernate.search.annotations.Indexed;
60
import org.springframework.util.ReflectionUtils;
61

    
62
import eu.etaxonomy.cdm.model.common.IRelated;
63
import eu.etaxonomy.cdm.model.common.RelationshipBase;
64
import eu.etaxonomy.cdm.model.description.DescriptionBase;
65
import eu.etaxonomy.cdm.model.description.TaxonDescription;
66
import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
67
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
68
import eu.etaxonomy.cdm.model.reference.ReferenceBase;
69

    
70
/**
71
 * The class for "accepted/correct" {@link TaxonBase taxa} (only these taxa according to
72
 * the opinion of the {@link eu.etaxonomy.cdm.model.reference.ReferenceBase reference} can build a taxonomic tree).
73
 * An {@link java.lang.Iterable interface} is supported to iterate through taxonomic children.<BR>
74
 * Splitting taxa in "accepted/correct" and {@link Synonym "synonyms"} makes it easier to handle
75
 * particular relationships between ("accepted/correct") taxa on the one hand
76
 * and between ("synonym") taxa and ("accepted/correct") taxa on the other.
77
 * 
78
 * @author m.doering
79
 * @version 1.0
80
 * @created 08-Nov-2007 13:06:56
81
 */
82
@XmlAccessorType(XmlAccessType.FIELD)
83
@XmlType(name = "Taxon", propOrder = {
84
    "taxonomicParentCache",
85
    "taxonNodes",
86
    "taxonomicChildrenCount",
87
    "synonymRelations",
88
    "relationsFromThisTaxon",
89
    "relationsToThisTaxon",
90
    "descriptions"
91
})
92
@XmlRootElement(name = "Taxon")
93
@Entity
94
@Indexed(index = "eu.etaxonomy.cdm.model.taxon.TaxonBase")
95
@Audited
96
@Configurable
97
public class Taxon extends TaxonBase<IIdentifiableEntityCacheStrategy<Taxon>> implements Iterable<Taxon>, IRelated<RelationshipBase>{
98
	private static final long serialVersionUID = -584946869762749006L;
99
	private static final Logger logger = Logger.getLogger(Taxon.class);
100

    
101
	@XmlElementWrapper(name = "Descriptions")
102
	@XmlElement(name = "Description")
103
	@OneToMany(mappedBy="taxon", fetch= FetchType.LAZY) 
104
	@Cascade({CascadeType.SAVE_UPDATE})
105
	private Set<TaxonDescription> descriptions = new HashSet<TaxonDescription>();
106

    
107
	// all related synonyms
108
	@XmlElementWrapper(name = "SynonymRelations")
109
	@XmlElement(name = "SynonymRelationship")
110
    @OneToMany(mappedBy="relatedTo", fetch=FetchType.LAZY)
111
	@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
112
	private Set<SynonymRelationship> synonymRelations = new HashSet<SynonymRelationship>();
113

    
114
	// all taxa relations with rel.fromTaxon==this
115
	@XmlElementWrapper(name = "RelationsFromThisTaxon")
116
	@XmlElement(name = "FromThisTaxonRelationship")
117
    @OneToMany(mappedBy="relatedFrom", fetch=FetchType.LAZY)
118
	@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
119
	private Set<TaxonRelationship> relationsFromThisTaxon = new HashSet<TaxonRelationship>();
120

    
121
	// all taxa relations with rel.toTaxon==this
122
	@XmlElementWrapper(name = "RelationsToThisTaxon")
123
	@XmlElement(name = "ToThisTaxonRelationship")
124
    @XmlIDREF
125
    @XmlSchemaType(name = "IDREF")
126
    @OneToMany(mappedBy="relatedTo", fetch=FetchType.LAZY)
127
	@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
128
	private Set<TaxonRelationship> relationsToThisTaxon = new HashSet<TaxonRelationship>();
129

    
130
	@XmlAttribute(name= "taxonStatusUnknown")
131
	private boolean taxonStatusUnknown = false;
132
	
133
	// shortcut to the taxonomicIncluded (parent) taxon. Managed by the taxonRelations setter
134
	@XmlElement(name = "TaxonomicParentCache")
135
	@XmlIDREF
136
	@XmlSchemaType(name = "IDREF")
137
	@ManyToOne(fetch = FetchType.LAZY)
138
	private Taxon taxonomicParentCache;
139
	
140
	
141
	@XmlElementWrapper(name = "taxonNodes")
142
	@XmlElement(name = "taxonNode")
143
    @XmlIDREF
144
    @XmlSchemaType(name = "IDREF")
145
    @OneToMany(mappedBy="taxon", fetch=FetchType.LAZY)
146
    @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
147
	private Set<TaxonNode> taxonNodes = new HashSet<TaxonNode>();
148

    
149
	//cached number of taxonomic children
150
	@XmlElement(name = "TaxonomicChildrenCount")
151
	private int taxonomicChildrenCount;
152
	
153
// ************* CONSTRUCTORS *************/	
154

    
155
	//TODO should be private, but still produces Spring init errors
156
	@Deprecated
157
	public Taxon(){
158
		this.cacheStrategy = new TaxonBaseDefaultCacheStrategy<Taxon>();
159
	}
160
	
161
	/** 
162
	 * Class constructor: creates a new (accepted/correct) taxon instance with
163
	 * the {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name} used and the {@link eu.etaxonomy.cdm.model.reference.ReferenceBase reference}
164
	 * using it.
165
	 * 
166
	 * @param  taxonNameBase	the taxon name used
167
	 * @param  sec				the reference using the taxon name
168
	 * @see    					TaxonBase#TaxonBase(TaxonNameBase, ReferenceBase)
169
	 */
170
	public Taxon(TaxonNameBase taxonNameBase, ReferenceBase sec){
171
		super(taxonNameBase, sec);
172
		this.cacheStrategy = new TaxonBaseDefaultCacheStrategy<Taxon>();
173
	}
174
	 
175
//********* METHODS **************************************/
176

    
177
	/** 
178
	 * Creates a new (accepted/correct) taxon instance with
179
	 * the {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name} used and the {@link eu.etaxonomy.cdm.model.reference.ReferenceBase reference}
180
	 * using it.
181
	 * 
182
	 * @param  taxonNameBase	the taxon name used
183
	 * @param  sec				the reference using the taxon name
184
	 * @see    					#Taxon(TaxonNameBase, ReferenceBase)
185
	 */
186
	public static Taxon NewInstance(TaxonNameBase taxonNameBase, ReferenceBase sec){
187
		Taxon result = new Taxon(taxonNameBase, sec);
188
		return result;
189
	}
190

    
191
	/** 
192
	 * Creates a new taxon instance with an unknown status (accepted/synonym) and with
193
	 * the {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name} used and the {@link eu.etaxonomy.cdm.model.reference.ReferenceBase reference}
194
	 * using it.
195
	 * 
196
	 * @param  taxonNameBase	the taxon name used
197
	 * @param  sec				the reference using the taxon name
198
	 * @see    					#Taxon(TaxonNameBase, ReferenceBase)
199
	 */
200
	public static Taxon NewUnknownStatusInstance(TaxonNameBase taxonNameBase, ReferenceBase sec){
201
		Taxon result = new Taxon(taxonNameBase, sec);
202
		result.setTaxonStatusUnknown(true);
203
		return result;
204
	}
205
	
206
	/** 
207
	 * Returns the set of {@link eu.etaxonomy.cdm.model.description.TaxonDescription taxon descriptions}
208
	 * concerning <i>this</i> taxon.
209
	 * 
210
	 * @see #removeDescription(TaxonDescription)
211
	 * @see #addDescription(TaxonDescription)
212
	 * @see eu.etaxonomy.cdm.model.description.TaxonDescription#getTaxon()
213
	 */
214
	public Set<TaxonDescription> getDescriptions() {
215
		return descriptions;
216
	}
217

    
218
	/** 
219
	 * Adds a new {@link eu.etaxonomy.cdm.model.description.TaxonDescription taxon description} to the set
220
	 * of taxon descriptions assigned to <i>this</i> (accepted/correct) taxon.
221
	 * Due to bidirectionality the content of the {@link eu.etaxonomy.cdm.model.description.TaxonDescription#getTaxon() taxon attribute} of the
222
	 * taxon description itself will be replaced with <i>this</i> taxon. The taxon
223
	 * description will also be removed from the set of taxon descriptions
224
	 * assigned to its previous taxon. 
225
	 *
226
	 * @param  description	the taxon description to be added for <i>this</i> taxon
227
	 * @see     		  	#getDescriptions()
228
	 * @see     		  	#removeDescription(TaxonDescription)
229
	 * @see 			  	eu.etaxonomy.cdm.model.description.TaxonDescription#getTaxon()
230
	 */
231
	public void addDescription(TaxonDescription description) {
232
		if (description.getTaxon() != null){
233
			description.getTaxon().removeDescription(description);
234
		}
235
		Field field = ReflectionUtils.findField(TaxonDescription.class, "taxon", Taxon.class);
236
		ReflectionUtils.makeAccessible(field);
237
		ReflectionUtils.setField(field, description, this);
238
		descriptions.add(description);
239
		
240
	}
241
	/** 
242
	 * Removes one element from the set of {@link eu.etaxonomy.cdm.model.description.TaxonDescription taxon descriptions} assigned
243
	 * to <i>this</i> (accepted/correct) taxon. Due to bidirectionality the content of
244
	 * the {@link eu.etaxonomy.cdm.model.description.TaxonDescription#getTaxon() taxon attribute} of the taxon description
245
	 * itself will be set to "null".
246
	 *
247
	 * @param  description  the taxon description which should be removed
248
	 * @see     		  	#getDescriptions()
249
	 * @see     		  	#addDescription(TaxonDescription)
250
	 * @see 			  	eu.etaxonomy.cdm.model.description.TaxonDescription#getTaxon()
251
	 */
252
	public void removeDescription(TaxonDescription description) {
253
		//description.setTaxon(null) for not visible method
254
		Field field = ReflectionUtils.findField(TaxonDescription.class, "taxon", Taxon.class);
255
		ReflectionUtils.makeAccessible(field);
256
		ReflectionUtils.setField(field, description, null);
257
		descriptions.remove(description);
258
	}
259

    
260
	
261
	public Set<TaxonNode> getTaxonNodes() {
262
		return taxonNodes;
263
	}
264
	//	protected void setTaxonNodes(Set<TaxonNode> taxonNodes) {
265
//		this.taxonNodes = taxonNodes;
266
//	}
267
	protected void addTaxonNode(TaxonNode taxonNode){
268
		taxonNodes.add(taxonNode);
269
	}
270
	protected void removeTaxonNode(TaxonNode taxonNode){
271
		taxonNodes.remove(taxonNode);
272
	}
273

    
274

    
275
	
276
	
277
	/** 
278
	 * Returns the set of all {@link SynonymRelationship synonym relationships}
279
	 * in which <i>this</i> ("accepted/correct") taxon is involved. <i>This</i> taxon can only
280
	 * be the target of these synonym relationships. 
281
	 *  
282
	 * @see    #addSynonymRelation(SynonymRelationship)
283
	 * @see    #removeSynonymRelation(SynonymRelationship)
284
	 * @see    #getSynonyms()
285
	 */
286
	public Set<SynonymRelationship> getSynonymRelations() {
287
		return synonymRelations;
288
	}
289
	
290
	/**
291
	 * Adds an existing {@link SynonymRelationship synonym relationship} to the set of
292
	 * {@link #getSynonymRelations() synonym relationships} assigned to <i>this</i> taxon. If
293
	 * the target of the synonym relationship does not match with <i>this</i> taxon
294
	 * no addition will be carried out.
295
	 * 
296
	 * @param synonymRelation	the synonym relationship to be added to <i>this</i> taxon's
297
	 * 							synonym relationships set
298
	 * @see    	   				#getSynonymRelations()
299
	 * @see    	   				#addSynonym(Synonym, SynonymRelationshipType)
300
	 * @see    	   				#addSynonym(Synonym, SynonymRelationshipType, ReferenceBase, String)
301
	 * @see    	   				#addSynonymName(TaxonNameBase, SynonymRelationshipType)
302
	 * @see    	   				#addSynonymName(TaxonNameBase, SynonymRelationshipType, ReferenceBase, String)
303
	 */
304
	protected void addSynonymRelation(SynonymRelationship synonymRelation) {
305
		this.synonymRelations.add(synonymRelation);
306
	}
307
	/** 
308
	 * Removes one element from the set of {@link SynonymRelationship synonym relationships} assigned
309
	 * to <i>this</i> (accepted/correct) taxon. Due to bidirectionality the given
310
	 * synonym relationship will also be removed from the set of synonym
311
	 * relationships assigned to the {@link Synonym#getSynonymRelations() synonym} involved in the
312
	 * relationship. Furthermore the content of
313
	 * the {@link SynonymRelationship#getAcceptedTaxon() accepted taxon} attribute and of the
314
	 * {@link SynonymRelationship#getSynonym() synonym} attribute within the synonym relationship
315
	 * itself will be set to "null".
316
	 *
317
	 * @param  synonymRelation  the synonym relationship which should be deleted
318
	 * @see     		  		#getSynonymRelations()
319
	 * @see     		  		#addSynonymRelation(SynonymRelationship)
320
	 * @see 			  		#removeSynonym(Synonym)
321
	 */
322
	public void removeSynonymRelation(SynonymRelationship synonymRelation) {
323
		synonymRelation.setAcceptedTaxon(null);
324
		Synonym synonym = synonymRelation.getSynonym();
325
		if (synonym != null){
326
			synonymRelation.setSynonym(null);
327
			synonym.removeSynonymRelation(synonymRelation);
328
		}
329
		this.synonymRelations.remove(synonymRelation);
330
	}
331

    
332
	
333
	/** 
334
	 * Returns the set of all {@link TaxonRelationship taxon relationships}
335
	 * between two taxa in which <i>this</i> taxon is involved as a source.
336
	 *  
337
	 * @see    #getRelationsToThisTaxon()
338
	 * @see    #getTaxonRelations()
339
	 */
340
	public Set<TaxonRelationship> getRelationsFromThisTaxon() {
341
		return relationsFromThisTaxon;
342
	}
343

    
344

    
345
	/** 
346
	 * Returns the set of all {@link TaxonRelationship taxon relationships}
347
	 * between two taxa in which <i>this</i> taxon is involved as a target.
348
	 *  
349
	 * @see    #getRelationsFromThisTaxon()
350
	 * @see    #getTaxonRelations()
351
	 */
352
	public Set<TaxonRelationship> getRelationsToThisTaxon() {
353
		return relationsToThisTaxon;
354
	}
355
	/** 
356
	 * @see    #getRelationsToThisTaxon()
357
	 */
358
	protected void setRelationsToThisTaxon(Set<TaxonRelationship> relationsToThisTaxon) {
359
		this.relationsToThisTaxon = relationsToThisTaxon;
360
	}
361

    
362
	/** 
363
	 * Returns the set of all {@link TaxonRelationship taxon relationships}
364
	 * between two taxa in which <i>this</i> taxon is involved either as a source or
365
	 * as a target.
366
	 *  
367
	 * @see    #getRelationsFromThisTaxon()
368
	 * @see    #getRelationsToThisTaxon()
369
	 */
370
	@Transient
371
	public Set<TaxonRelationship> getTaxonRelations() {
372
		Set<TaxonRelationship> rels = new HashSet<TaxonRelationship>();
373
		rels.addAll(getRelationsToThisTaxon());
374
		rels.addAll(getRelationsFromThisTaxon());
375
		return rels;
376
	}
377
	/** 
378
	 * Removes one {@link TaxonRelationship taxon relationship} from one of both sets of
379
	 * {@link #getTaxonRelations() taxon relationships} in which <i>this</i> taxon is involved
380
	 * either as a {@link #getRelationsFromThisTaxon() source} or as a {@link #getRelationsToThisTaxon() target}.
381
	 * The taxon relationship will also be removed from one of both sets
382
	 * belonging to the second taxon involved. Furthermore the inherited RelatedFrom and
383
	 * RelatedTo attributes of the given taxon relationship will be nullified.<P>
384
	 * If the taxon relationship concerns the taxonomic tree possible
385
	 * modifications of the {@link #getTaxonomicParent() parent taxon} or of the number of
386
	 * {@link #getTaxonomicChildrenCount() childrens} will be stored.
387
	 *
388
	 * @param  rel  the taxon relationship which should be removed from one
389
	 * 				of both sets
390
	 * @see    		#getTaxonRelations()
391
	 * @see    	    #getTaxonomicParent()
392
	 * @see    	    #getTaxonomicChildrenCount()
393
	 * @see    		eu.etaxonomy.cdm.model.common.RelationshipBase#getRelatedFrom()
394
	 * @see    		eu.etaxonomy.cdm.model.common.RelationshipBase#getRelatedTo()
395
	 * 
396
	 */
397
	public void removeTaxonRelation(TaxonRelationship rel) {
398
		logger.warn("remove TaxonRelation");  //for testing only 
399
		this.relationsToThisTaxon.remove(rel);
400
		this.relationsFromThisTaxon.remove(rel);
401
		Taxon fromTaxon = rel.getFromTaxon();
402
		Taxon toTaxon = rel.getToTaxon();
403
		// check if this removes the taxonomical parent. If so, also remove shortcut to the higher taxon
404
		if (rel.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN()) ){
405
			if (fromTaxon != null && fromTaxon.equals(this)){
406
				this.taxonomicParentCache = null;
407
			}else if (toTaxon != null && toTaxon.equals(this)){
408
				this.setTaxonomicChildrenCount(computeTaxonomicChildrenCount());	
409
			}
410
		}
411
		//delete Relationship from other related Taxon
412
		if (fromTaxon != null && fromTaxon != this){
413
			rel.setToTaxon(null);  //remove this Taxon from relationship
414
			fromTaxon.removeTaxonRelation(rel);
415
		}
416
		if (toTaxon != null && toTaxon != this){
417
			rel.setFromTaxon(null); //remove this Taxon from relationship
418
			toTaxon.removeTaxonRelation(rel);
419
		}
420
	}
421

    
422
	/**
423
	 * Adds an existing {@link TaxonRelationship taxon relationship} either to the set of
424
	 * {@link #getRelationsToThisTaxon() taxon relationships to <i>this</i> taxon} or to the set of
425
	 * {@link #getRelationsFromThisTaxon() taxon relationships from <i>this</i> taxon}. If neither the
426
	 * source nor the target of the taxon relationship match with <i>this</i> taxon
427
	 * no addition will be carried out. The taxon relationship will also be
428
	 * added to the second taxon involved in the given relationship.<P>
429
	 * If the taxon relationship concerns the taxonomic tree possible
430
	 * modifications of the {@link #getTaxonomicParent() parent taxon} or of the number of
431
	 * {@link #getTaxonomicChildrenCount() childrens} will be stored.
432
	 * 
433
	 * @param rel  the taxon relationship to be added to one of <i>this</i> taxon's taxon relationships sets
434
	 * @see    	   #addTaxonRelation(Taxon, TaxonRelationshipType, ReferenceBase, String)
435
	 * @see    	   #getTaxonRelations()
436
	 * @see    	   #getRelationsFromThisTaxon()
437
	 * @see    	   #getRelationsToThisTaxon()
438
	 * @see    	   #getTaxonomicParent()
439
	 * @see    	   #getTaxonomicChildrenCount()
440
	 */
441
	public void addTaxonRelation(TaxonRelationship rel) {
442
		if (rel!=null && rel.getType()!=null && !getTaxonRelations().contains(rel) ){
443
			Taxon toTaxon=rel.getToTaxon();
444
			Taxon fromTaxon=rel.getFromTaxon();
445
			if ( this.equals(toTaxon) || this.equals(fromTaxon) ){
446
				if (this.equals(fromTaxon)){
447
					relationsFromThisTaxon.add(rel);
448
					// also add relation to other taxon object
449
					if (toTaxon!=null){
450
						toTaxon.addTaxonRelation(rel);
451
					}
452
					// check if this sets the taxonomical parent. If so, remember a shortcut to this taxon
453
					if (rel.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN()) && toTaxon!=null ){
454
						this.taxonomicParentCache = toTaxon;
455
					}
456
				}else if (this.equals(toTaxon)){
457
					relationsToThisTaxon.add(rel);
458
					// also add relation to other taxon object
459
					if (fromTaxon!=null){
460
						fromTaxon.addTaxonRelation(rel);
461
					}
462
					if (rel.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN()) && fromTaxon!=null ){
463
						this.taxonomicChildrenCount++;
464
					}
465
					
466
				}
467
			}
468
		}	
469
	}
470
		
471
	/* (non-Javadoc)
472
	 * @see eu.etaxonomy.cdm.model.common.IRelated#addRelationship(eu.etaxonomy.cdm.model.common.RelationshipBase)
473
	 */
474
	@Deprecated //for inner use by RelationshipBase only
475
	public void addRelationship(RelationshipBase rel){
476
		if (rel instanceof TaxonRelationship){
477
			addTaxonRelation((TaxonRelationship)rel);
478
		}else if (rel instanceof SynonymRelationship){
479
			addSynonymRelation((SynonymRelationship)rel);
480
		}else{
481
			throw new ClassCastException("Wrong Relationsship type for Taxon.addRelationship");
482
		}
483
	}
484
	
485
	/**
486
	 * Creates a new {@link TaxonRelationship taxon relationship} instance where <i>this</i> taxon
487
	 * plays the source role and adds it to the set of
488
	 * {@link #getRelationsFromThisTaxon() "taxon relationships from"} belonging to <i>this</i> taxon.
489
	 * The taxon relationship will also be added to the set of taxon
490
	 * relationships to the second taxon involved in the created relationship.<P>
491
	 * If the taxon relationship concerns the taxonomic tree possible
492
	 * modifications of the {@link #getTaxonomicParent() parent taxon} or of the number of
493
	 * {@link #getTaxonomicChildrenCount() childrens} will be stored.
494
	 * 
495
	 * @param toTaxon		the taxon which plays the target role in the new taxon relationship
496
	 * @param type			the taxon relationship type for the new taxon relationship
497
	 * @param citation		the reference source for the new taxon relationship
498
	 * @param microcitation	the string with the details describing the exact localisation within the reference
499
	 * @see    	   			#addTaxonRelation(TaxonRelationship)
500
	 * @see    	   			#getTaxonRelations()
501
	 * @see    	   			#getRelationsFromThisTaxon()
502
	 * @see    	   			#getRelationsToThisTaxon()
503
	 * @see    	   			#getTaxonomicParent()
504
	 * @see    	   			#getTaxonomicChildrenCount()
505
	 */
506
	public void addTaxonRelation(Taxon toTaxon, TaxonRelationshipType type, ReferenceBase citation, String microcitation) {
507
		TaxonRelationship rel = new TaxonRelationship(this, toTaxon, type, citation, microcitation);
508
	}
509
	/**
510
	 * Creates a new {@link TaxonRelationship taxon relationship} (with {@link TaxonRelationshipType taxon relationship type}
511
	 * "misapplied name for") instance where <i>this</i> taxon plays the target role
512
	 * and adds it to the set of {@link #getRelationsToThisTaxon() taxon relationships to <i>this</i> taxon}.
513
	 * The taxon relationship will also be added to the set of taxon
514
	 * relationships to the other (misapplied name) taxon involved in the created relationship.
515
	 * 
516
	 * @param misappliedNameTaxon	the taxon which plays the target role in the new taxon relationship
517
	 * @param citation				the reference source for the new taxon relationship
518
	 * @param microcitation			the string with the details describing the exact localisation within the reference
519
	 * @see    	   					#getMisappliedNames()
520
	 * @see    	   					#addTaxonRelation(Taxon, TaxonRelationshipType, ReferenceBase, String)
521
	 * @see    	   					#addTaxonRelation(TaxonRelationship)
522
	 * @see    	   					#getTaxonRelations()
523
	 * @see    	   					#getRelationsFromThisTaxon()
524
	 * @see    	   					#getRelationsToThisTaxon()
525
	 */
526
	public void addMisappliedName(Taxon misappliedNameTaxon, ReferenceBase citation, String microcitation) {
527
		misappliedNameTaxon.addTaxonRelation(this, TaxonRelationshipType.MISAPPLIED_NAME_FOR(), citation, microcitation);
528
	}
529

    
530
//	public void removeMisappliedName(Taxon misappliedNameTaxon){
531
//		Set<TaxonRelationship> taxRels = this.getTaxonRelations();
532
//		for (TaxonRelationship taxRel : taxRels ){
533
//			if (taxRel.getType().equals(TaxonRelationshipType.MISAPPLIED_NAME_FOR()) 
534
//				&& taxRel.getFromTaxon().equals(misappliedNameTaxon)){
535
//				this.removeTaxonRelation(taxRel);
536
//			}
537
//		}
538
//	}
539
	
540
	/** 
541
	 * TODO update documentation 
542
	 * Removes one {@link TaxonRelationship taxon relationship} with {@link TaxonRelationshipType taxon relationship type}
543
	 * taxonRelType and with the given child taxon playing the
544
	 * source role from the set of {@link #getRelationsToThisTaxon() "taxon relationships to"} belonging
545
	 * to <i>this</i> taxon. The taxon relationship will also be removed from the set
546
	 * of {@link #getRelationsFromThisTaxon() "taxon relationships from"} belonging to the other side taxon.
547
	 * Furthermore, the inherited RelatedFrom and RelatedTo attributes of the
548
	 * taxon relationship will be nullified.<P>
549
	 *
550
	 * @param taxon			the taxon which plays the source role in the taxon relationship
551
	 * @param taxonRelType	the taxon relationship type
552
	 */
553
	public void removeTaxon(Taxon taxon, TaxonRelationshipType taxonRelType){
554
		Set<TaxonRelationship> taxRels = this.getTaxonRelations();
555
		for (TaxonRelationship taxRel : taxRels ){
556
			if (taxRel.getType().equals(taxonRelType) 
557
				&& taxRel.getFromTaxon().equals(taxon)){
558
				this.removeTaxonRelation(taxRel);
559
			}
560
		}
561
	}
562
	
563
	/**
564
	 * Creates a new {@link TaxonRelationship taxon relationship} (with {@link TaxonRelationshipType taxon relationship type}
565
	 * "taxonomically included in") instance where <i>this</i> taxon plays the target
566
	 * role (parent) and adds it to the set of
567
	 * {@link #getRelationsToThisTaxon() "taxon relationships to"} belonging to <i>this</i> taxon.
568
	 * The taxon relationship will also be added to the set of
569
	 * {@link #getRelationsFromThisTaxon() "taxon relationships from"} belonging to the second taxon
570
	 * (child) involved in the created relationship.<P>
571
	 * Since the taxon relationship concerns the modifications
572
	 * of the number of {@link #getTaxonomicChildrenCount() childrens} for <i>this</i> taxon and
573
	 * of the {@link #getTaxonomicParent() parent taxon} for the child taxon will be stored.
574
	 * The {@link name.Rank rank} of the taxon name used as a parent taxon must be higher
575
	 * than the rank of the taxon name used as a child taxon.
576
	 * 
577
	 * @param child			the taxon which plays the source role (child) in the new taxon relationship
578
	 * @param citation		the reference source for the new taxon relationship
579
	 * @param microcitation	the string with the details describing the exact localisation within the reference
580
	 * @see    	   			#setTaxonomicParent(Taxon, ReferenceBase, String)
581
	 * @see    	   			#addTaxonRelation(Taxon, TaxonRelationshipType, ReferenceBase, String)
582
	 * @see    	   			#addTaxonRelation(TaxonRelationship)
583
	 * @see    	   			#getTaxonRelations()
584
	 * @see    	   			#getRelationsFromThisTaxon()
585
	 * @see    	   			#getRelationsToThisTaxon()
586
	 * @see    	   			#getTaxonomicParent()
587
	 * @see    	   			#getTaxonomicChildrenCount()
588
	 */
589
	public void addTaxonomicChild(Taxon child, ReferenceBase citation, String microcitation){
590
		if (child == null){
591
			throw new NullPointerException("Child Taxon is 'null'");
592
		}else{
593
			child.setTaxonomicParent(this, citation, microcitation);
594
		}
595
	}
596
	
597
	/** 
598
	 * Removes one {@link TaxonRelationship taxon relationship} with {@link TaxonRelationshipType taxon relationship type}
599
	 * "taxonomically included in" and with the given child taxon playing the
600
	 * source role from the set of {@link #getRelationsToThisTaxon() "taxon relationships to"} belonging
601
	 * to <i>this</i> taxon. The taxon relationship will also be removed from the set
602
	 * of {@link #getRelationsFromThisTaxon() "taxon relationships from"} belonging to the child taxon.
603
	 * Furthermore the inherited RelatedFrom and RelatedTo attributes of the
604
	 * taxon relationship will be nullified.<P>
605
	 * Since the taxon relationship concerns the taxonomic tree modifications
606
	 * of the number of {@link #getTaxonomicChildrenCount() childrens} for <i>this</i> taxon and
607
	 * of the {@link #getTaxonomicParent() parent taxon} for the child taxon will be stored.
608
	 *
609
	 * @param  child	the taxon playing the source role in the relationship to be removed
610
	 * @see    	    	#removeTaxonRelation(TaxonRelationship)
611
	 * @see    			#getRelationsToThisTaxon()
612
	 * @see    			#getRelationsFromThisTaxon()
613
	 * @see    	    	#getTaxonomicParent()
614
	 * @see    	    	#getTaxonomicChildrenCount()
615
	 * @see    			eu.etaxonomy.cdm.model.common.RelationshipBase#getRelatedFrom()
616
	 * @see    			eu.etaxonomy.cdm.model.common.RelationshipBase#getRelatedTo()
617
	 * 
618
	 */
619
	public void removeTaxonomicChild(Taxon child){
620
		Set<TaxonRelationship> taxRels = this.getTaxonRelations();
621
		for (TaxonRelationship taxRel : taxRels ){
622
			if (taxRel.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN()) 
623
				&& taxRel.getFromTaxon().equals(child)){
624
				this.removeTaxonRelation(taxRel);
625
			}
626
		}
627
	}
628
	
629
	/** 
630
	 * Returns the taxon which is the next higher taxon (parent) of <i>this</i> taxon
631
	 * within the taxonomic tree and which is stored in the
632
	 * TaxonomicParentCache attribute. Each taxon can have only one parent taxon.
633
	 * The child taxon and the parent taxon play the source respectively the
634
	 * target role in one {@link TaxonRelationship taxon relationship} with
635
	 * {@link TaxonRelationshipType taxon relationship type} "taxonomically included in".
636
	 * The {@link name.Rank rank} of the taxon name used as a parent taxon must be higher
637
	 * than the rank of the taxon name used as a child taxon.
638
	 * 
639
	 * @see  #setTaxonomicParent(Taxon, ReferenceBase, String)
640
	 * @see  #getTaxonomicChildren()
641
	 * @see  #getTaxonomicChildrenCount()
642
	 * @see  #getRelationsFromThisTaxon()
643
	 */
644
	public Taxon getTaxonomicParent() {
645
		return this.taxonomicParentCache;
646
	}
647

    
648
	/** 
649
	 * Sets the taxononomic parent of <i>this</i> taxon to null.
650
	 * Note that this method does not handle taxonomic relationships.
651
	 */
652
	public void nullifyTaxonomicParent() {
653
		this.taxonomicParentCache = null;
654
	}
655
		
656
	/**
657
	 * Replaces both the taxonomic parent cache with the given new parent taxon
658
	 * and the corresponding taxon relationship with a new {@link TaxonRelationship taxon relationship}
659
	 * (with {@link TaxonRelationshipType taxon relationship type} "taxonomically included in") instance.
660
	 * In the new taxon relationship <i>this</i> taxon plays the source role (child).
661
	 * This method creates and adds the new taxon relationship to the set of
662
	 * {@link #getRelationsFromThisTaxon() "taxon relationships from"} belonging to <i>this</i> taxon.
663
	 * The taxon relationship will also be added to the set of
664
	 * {@link #getRelationsToThisTaxon() "taxon relationships to"} belonging to the second taxon
665
	 * (parent) involved in the new relationship.<P>
666
	 * Since the taxon relationship concerns the taxonomic tree modifications
667
	 * of the {@link #getTaxonomicParent() parent taxon} for <i>this</i> taxon and of the number of
668
	 * {@link #getTaxonomicChildrenCount() childrens} for the child taxon will be stored.
669
	 * 
670
	 * @param newParent		the taxon which plays the target role (parent) in the new taxon relationship
671
	 * @param citation		the reference source for the new taxon relationship
672
	 * @param microcitation	the string with the details describing the exact localisation within the reference
673
	 * @see    	   			#removeTaxonRelation(TaxonRelationship)
674
	 * @see    	   			#getTaxonomicParent()
675
	 * @see    	   			#addTaxonRelation(Taxon, TaxonRelationshipType, ReferenceBase, String)
676
	 * @see    	   			#addTaxonRelation(TaxonRelationship)
677
	 * @see    	   			#getTaxonRelations()
678
	 * @see    	   			#getRelationsFromThisTaxon()
679
	 * @see    	   			#getRelationsToThisTaxon()
680
	 * @see    	   			#getTaxonomicChildrenCount()
681
	 */
682
	public void setTaxonomicParent(Taxon newParent, ReferenceBase citation, String microcitation){
683
		//remove previously existing parent relationship!!!
684
		Taxon oldParent = this.getTaxonomicParent();
685
		Set<TaxonRelationship> taxRels = this.getTaxonRelations();
686
		for (TaxonRelationship taxRel : taxRels ){
687
			if (taxRel.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN()) && taxRel.getToTaxon().equals(oldParent)){
688
				this.removeTaxonRelation(taxRel);
689
			}
690
		}
691
		//add new parent
692
		if (newParent != null){
693
			addTaxonRelation(newParent, TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN(),citation,microcitation);
694
		}
695
	}
696

    
697
	/** 
698
	 * Returns the set of taxa which have <i>this</i> taxon as next higher taxon
699
	 * (parent) within the taxonomic tree. Each taxon can have several child
700
	 * taxa. The child taxon and the parent taxon play the source respectively
701
	 * the target role in one {@link TaxonRelationship taxon relationship} with
702
	 * {@link TaxonRelationshipType taxon relationship type} "taxonomically included in".
703
	 * The {@link name.Rank rank} of the taxon name used as a parent taxon must be higher
704
	 * than the rank of the taxon name used as a child taxon.
705
	 * 
706
	 * @see  #getTaxonomicParent()
707
	 * @see  #addTaxonomicChild(Taxon, ReferenceBase, String)
708
	 * @see  #getTaxonomicChildrenCount()
709
	 * @see  #getRelationsToThisTaxon()
710
	 */
711
	@Transient
712
	public Set<Taxon> getTaxonomicChildren() {
713
		Set<Taxon> taxa = new HashSet<Taxon>();
714
		Set<TaxonRelationship> rels = this.getRelationsToThisTaxon();
715
		for (TaxonRelationship rel: rels){
716
			TaxonRelationshipType tt = rel.getType();
717
			TaxonRelationshipType incl = TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN(); 
718
			if (tt.equals(incl)){
719
				taxa.add(rel.getFromTaxon());
720
			}
721
		}
722
		return taxa;
723
	}
724
	
725
	/** 
726
	 * Returns the number of taxa which have <i>this</i> taxon as next higher taxon
727
	 * (parent) within the taxonomic tree and the number of which is stored in
728
	 * the TaxonomicChildrenCount attribute. Each taxon can have several child
729
	 * taxa. The child taxon and the parent taxon play the source respectively
730
	 * the target role in one {@link TaxonRelationship taxon relationship} with
731
	 * {@link TaxonRelationshipType taxon relationship type} "taxonomically included in".
732
	 * The {@link name.Rank rank} of the taxon name used as a parent taxon must be higher
733
	 * than the rank of the taxon name used as a child taxon.
734
	 * 
735
	 * @see  #getTaxonomicChildren()
736
	 * @see  #getRelationsToThisTaxon()
737
	 */
738
	public int getTaxonomicChildrenCount(){
739
		return taxonomicChildrenCount;
740
	}	
741
	
742
	/**
743
	 * @see  #getTaxonomicChildrenCount()
744
	 */
745
	public void setTaxonomicChildrenCount(int taxonomicChildrenCount) {
746
		this.taxonomicChildrenCount = taxonomicChildrenCount;
747
	}
748

    
749
	/**
750
	 * Returns the boolean value indicating whether <i>this</i> taxon has at least one
751
	 * taxonomic child taxon within the taxonomic tree (true) or not (false).
752
	 * 
753
	 * @see  #getTaxonomicChildrenCount()
754
	 * @see  #getTaxonomicChildren()
755
	 */
756
	public boolean hasTaxonomicChildren(){
757
		return this.taxonomicChildrenCount > 0;
758
	}
759

    
760
	private int computeTaxonomicChildrenCount(){
761
		int count = 0;
762
		for (TaxonRelationship rel: this.getRelationsToThisTaxon()){
763
			if (rel.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN())){
764
				count++;
765
			}
766
		}
767
		return count;
768
	}
769
	
770
	/**
771
	 * Returns the boolean value indicating whether <i>this</i> taxon is a misaplication
772
	 * (misapplied name) for at least one other taxon. 
773
	 */
774
	// TODO cache as for #hasTaxonomicChildren
775
	@Transient
776
	public boolean isMisappliedName(){
777
		return computeMisapliedNameRelations() > 0;
778
	}
779
	
780
	/**
781
	 * Counts the number of misaplied names relationships where this taxon represents the
782
	 * misaplied name for another taxon.
783
	 * @return
784
	 */
785
	private int computeMisapliedNameRelations(){
786
		int count = 0;
787
		for (TaxonRelationship rel: this.getRelationsFromThisTaxon()){
788
			if (rel.getType().equals(TaxonRelationshipType.MISAPPLIED_NAME_FOR())){
789
				count++;
790
			}
791
		}
792
		return count;
793
	}
794
	
795
	/**
796
	 * Returns the boolean value indicating whether <i>this</i> taxon has at least one
797
	 * {@link Synonym synonym} (true) or not (false). If true the {@link #getSynonymRelations() set of synonym relationships}
798
	 * belonging to <i>this</i> ("accepted/correct") taxon is not empty .
799
	 * 
800
	 * @see  #getSynonymRelations()
801
	 * @see  #getSynonyms()
802
	 * @see  #getSynonymNames()
803
	 * @see  #removeSynonym(Synonym)
804
	 * @see  SynonymRelationship
805
	 */
806
	public boolean hasSynonyms(){
807
		return this.getSynonymRelations().size() > 0;
808
	}
809

    
810
	
811
	/**
812
	 * Returns the boolean value indicating whether <i>this</i> taxon is at least
813
	 * involved in one {@link #getTaxonRelations() taxon relationship} between
814
	 * two taxa (true), either as a source or as a target, or not (false).
815
	 * 
816
	 * @see  #getTaxonRelations()
817
	 * @see  #getRelationsToThisTaxon()
818
	 * @see  #getRelationsFromThisTaxon()
819
	 * @see  #removeTaxonRelation(TaxonRelationship)
820
	 * @see  TaxonRelationship
821
	 */
822
	public boolean hasTaxonRelationships(){
823
		return this.getTaxonRelations().size() > 0;
824
	}
825

    
826
	/*
827
	 * MISAPPLIED NAMES
828
	 */
829
	/** 
830
	 * Returns the set of taxa playing the source role in {@link TaxonRelationship taxon relationships}
831
	 * (with {@link TaxonRelationshipType taxon relationship type} "misapplied name for") where
832
	 * <i>this</i> taxon plays the target role. A misapplied name is a taxon the
833
	 * {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name} of which has been erroneously used
834
	 * by its {@link TaxonBase#getSec() taxon reference} to denominate the same real taxon
835
	 * as the one meant by <i>this</i> ("accepted/correct") taxon. 
836
	 * 
837
	 * @see  #getTaxonRelations()
838
	 * @see  #getRelationsToThisTaxon()
839
	 * @see  #addMisappliedName(Taxon, ReferenceBase, String)
840
	 */
841
	@Transient
842
	public Set<Taxon> getMisappliedNames(){
843
		Set<Taxon> taxa = new HashSet<Taxon>();
844
		Set<TaxonRelationship> rels = this.getRelationsToThisTaxon();
845
		for (TaxonRelationship rel: rels){
846
			TaxonRelationshipType tt = rel.getType();
847
			TaxonRelationshipType incl = TaxonRelationshipType.MISAPPLIED_NAME_FOR(); 
848
			if (tt.equals(incl)){
849
				taxa.add(rel.getFromTaxon());
850
			}
851
		}
852
		return taxa;
853
	}
854
		
855
	
856
	/*
857
	 * DEALING WITH SYNONYMS
858
	 */
859
	/** 
860
	 * Returns the set of all {@link Synonym synonyms} of <i>this</i> ("accepted/correct") taxon.
861
	 * Each synonym is the source and <i>this</i> taxon is the target of a {@link SynonymRelationship synonym relationship}
862
	 * belonging to the {@link #getSynonymRelations() set of synonym relationships} assigned to <i>this</i> taxon.
863
	 * For a particular synonym and for a particular ("accepted/correct") taxon
864
	 * there can be several synonym relationships (if two or more
865
	 * {@link SynonymRelationshipType synonym relationship types} - for instance
866
	 * "pro parte synonym of" and "is homotypic synonym of" - must be combined). 
867
	 *  
868
	 * @see    #getSynonymsSortedByType()
869
	 * @see    #getSynonymNames()
870
	 * @see    #getSynonymRelations()
871
	 * @see    #addSynonym(Synonym, SynonymRelationshipType)
872
	 * @see    #addSynonym(Synonym, SynonymRelationshipType, ReferenceBase, String)
873
	 * @see    #removeSynonymRelation(SynonymRelationship)
874
	 * @see    #removeSynonym(Synonym)
875
	 */
876
	@Transient
877
	public Set<Synonym> getSynonyms(){
878
		Set<Synonym> syns = new HashSet<Synonym>();
879
		for (SynonymRelationship rel: this.getSynonymRelations()){
880
			syns.add(rel.getSynonym());
881
		}
882
		return syns;
883
	}
884
	/** 
885
	 * Returns the set of all {@link Synonym synonyms} of <i>this</i> ("accepted/correct") taxon
886
	 * sorted by the different {@link SynonymRelationshipType categories of synonym relationships}.
887
	 * Each synonym is the source and <i>this</i> taxon is the target of a {@link SynonymRelationship synonym relationship}
888
	 * belonging to the {@link #getSynonymRelations() set of synonym relationships} assigned to <i>this</i> taxon.
889
	 *  
890
	 * @see    #getSynonyms()
891
	 * @see    #getSynonymNames()
892
	 * @see    #getSynonymRelations()
893
	 * @see    #addSynonym(Synonym, SynonymRelationshipType)
894
	 * @see    #addSynonym(Synonym, SynonymRelationshipType, ReferenceBase, String)
895
	 * @see    #removeSynonymRelation(SynonymRelationship)
896
	 * @see    #removeSynonym(Synonym)
897
	 */
898
	@Transient
899
	public Set<Synonym> getSynonymsSortedByType(){
900
		// FIXME: need to sort synonyms according to type!!!
901
		logger.warn("getSynonymsSortedByType() not yet implemented");
902
		return getSynonyms();
903
	}
904
	/** 
905
	 * Returns the set of all {@link name.TaxonNameBase taxon names} used as {@link Synonym synonyms}
906
	 * of <i>this</i> ("accepted/correct") taxon. Each synonym is the source and
907
	 * <i>this</i> taxon is the target of a {@link SynonymRelationship synonym relationship} belonging
908
	 * to the {@link #getSynonymRelations() set of synonym relationships} assigned to <i>this</i> taxon.
909
	 *  
910
	 * @see    #getSynonyms()
911
	 * @see    #getSynonymsSortedByType()
912
	 * @see    #getSynonymRelations()
913
	 * @see    #addSynonymName(TaxonNameBase, SynonymRelationshipType)
914
	 * @see    #addSynonym(Synonym, SynonymRelationshipType, ReferenceBase, String)
915
	 * @see    #removeSynonymRelation(SynonymRelationship)
916
	 * @see    #removeSynonym(Synonym)
917
	 */
918
	@Transient
919
	public Set<TaxonNameBase> getSynonymNames(){
920
		Set<TaxonNameBase> names = new HashSet<TaxonNameBase>();
921
		for (SynonymRelationship rel: this.getSynonymRelations()){
922
			names.add(rel.getSynonym().getName());
923
		}
924
		return names;
925
	}
926
	/**
927
	 * Creates a new {@link SynonymRelationship synonym relationship} (with the given {@link Synonym synonym}
928
	 * and with the given {@link SynonymRelationshipType synonym relationship type}), returns it and adds it
929
	 * to the set of {@link #getSynonymRelations() synonym relationships} assigned to <i>this</i> taxon.
930
	 * The new synonym relationship will also be added to the set of
931
	 * {@link Synonym#getSynonymRelations() synonym relationships} belonging to the synonym
932
	 * involved in this synonym relationship.<BR>
933
	 * The returned synonym relationship allows to add further information to it.
934
	 * 
935
	 * @param synonym		the synonym involved in the relationship to be created
936
	 * 						and added to <i>this</i> taxon's synonym relationships set
937
	 * @param synonymType	the synonym relationship category of the synonym
938
	 * 						relationship to be added
939
	 * @return 				the created synonym relationship
940
	 * @see    	   			#addSynonymRelation(SynonymRelationship)
941
	 * @see    	   			#addSynonym(Synonym, SynonymRelationshipType, ReferenceBase, String)
942
	 * @see    	   			#addSynonymName(TaxonNameBase, SynonymRelationshipType)
943
	 * @see    	   			#addSynonymName(TaxonNameBase, SynonymRelationshipType, ReferenceBase, String)
944
	 * @see    	   			#addHomotypicSynonym(Synonym, ReferenceBase, String)
945
	 * @see    	   			#addHomotypicSynonymName(TaxonNameBase, ReferenceBase, String)
946
	 * @see    	   			#addHeterotypicSynonymName(TaxonNameBase)
947
	 * @see    	   			#addHeterotypicSynonymName(TaxonNameBase, HomotypicalGroup, ReferenceBase, String)
948
	 * @see    	   			#getSynonymRelations()
949
	 * @see    				#removeSynonym(Synonym)
950
	 * @see    	   			Synonym#getSynonymRelations()
951
	 */
952
	public SynonymRelationship addSynonym(Synonym synonym, SynonymRelationshipType synonymType){
953
		return addSynonym(synonym, synonymType, null, null);
954
	}
955
	/**
956
	 * Creates a new {@link SynonymRelationship synonym relationship} (with the given {@link Synonym synonym},
957
	 * with the given {@link SynonymRelationshipType synonym relationship type} and with the
958
	 * {@link eu.etaxonomy.cdm.model.reference.ReferenceBase reference source} on which the relationship assertion is based),
959
	 * returns it and adds it to the set of {@link #getSynonymRelations() synonym relationships}
960
	 * assigned to <i>this</i> taxon. The new synonym relationship will also be
961
	 * added to the set of {@link Synonym#getSynonymRelations() synonym relationships} belonging to the synonym
962
	 * involved in this synonym relationship.<BR>
963
	 * The returned synonym relationship allows to add further information to it.
964
	 * 
965
	 * @param synonym		the synonym involved in the relationship to be created
966
	 * 						and added to <i>this</i> taxon's synonym relationships set
967
	 * @param synonymType	the synonym relationship category of the synonym
968
	 * 						relationship to be added
969
	 * @param citation		the reference source for the new synonym relationship
970
	 * @param microcitation	the string with the details describing the exact localisation within the reference
971
	 * @return 				the created synonym relationship
972
	 * @see    	   			#addSynonymRelation(SynonymRelationship)
973
	 * @see    	   			#addSynonym(Synonym, SynonymRelationshipType, ReferenceBase, String)
974
	 * @see    	   			#addSynonymName(TaxonNameBase, SynonymRelationshipType)
975
	 * @see    	   			#addSynonymName(TaxonNameBase, SynonymRelationshipType, ReferenceBase, String)
976
	 * @see    	   			#addHomotypicSynonym(Synonym, ReferenceBase, String)
977
	 * @see    	   			#addHomotypicSynonymName(TaxonNameBase, ReferenceBase, String)
978
	 * @see    	   			#addHeterotypicSynonymName(TaxonNameBase)
979
	 * @see    	   			#addHeterotypicSynonymName(TaxonNameBase, HomotypicalGroup, ReferenceBase, String)
980
	 * @see    	   			#getSynonymRelations()
981
	 * @see    				#removeSynonym(Synonym)
982
	 * @see    	   			Synonym#getSynonymRelations()
983
	 */
984
	public SynonymRelationship addSynonym(Synonym synonym, SynonymRelationshipType synonymType, ReferenceBase citation, String citationMicroReference){
985
		SynonymRelationship synonymRelationship = new SynonymRelationship(synonym, this, synonymType, citation, citationMicroReference);
986
		return synonymRelationship;
987
	}
988
	
989
	/**
990
	 * Creates a new {@link Synonym synonym} (with the given {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name}),
991
	 * a new {@link SynonymRelationship synonym relationship} (with the new synonym and with the given 
992
	 * {@link SynonymRelationshipType synonym relationship type}), returns the relationship and adds it
993
	 * to the set of {@link #getSynonymRelations() synonym relationships} assigned to <i>this</i> taxon.
994
	 * The new synonym will have the same {@link TaxonBase#getSec() concept reference}
995
	 * as <i>this</i> taxon. The new synonym relationship will also be added to 
996
	 * the set of {@link Synonym#getSynonymRelations() synonym relationships} belonging
997
	 * to the created synonym.<BR>
998
	 * The returned synonym relationship allows to add further information to it.
999
	 * 
1000
	 * @param synonymName	the taxon name to be used as a synonym to be added
1001
	 * 						to <i>this</i> taxon's set of synonyms
1002
	 * @param synonymType	the synonym relationship category of the synonym
1003
	 * 						relationship to be added
1004
	 * @return 				the created synonym relationship
1005
	 * @see    	   			#addSynonymName(TaxonNameBase, SynonymRelationshipType, ReferenceBase, String)
1006
	 * @see    	   			#addSynonym(Synonym, SynonymRelationshipType)
1007
	 * @see    	   			#addSynonym(Synonym, SynonymRelationshipType, ReferenceBase, String)
1008
	 * @see    	   			#addSynonymRelation(SynonymRelationship)
1009
	 * @see    	   			#addHomotypicSynonym(Synonym, ReferenceBase, String)
1010
	 * @see    	   			#addHomotypicSynonymName(TaxonNameBase, ReferenceBase, String)
1011
	 * @see    	   			#addHeterotypicSynonymName(TaxonNameBase)
1012
	 * @see    	   			#addHeterotypicSynonymName(TaxonNameBase, HomotypicalGroup, ReferenceBase, String)
1013
	 * @see    	   			#getSynonymRelations()
1014
	 * @see    				#removeSynonym(Synonym)
1015
	 * @see    	   			Synonym#getSynonymRelations()
1016
	 */
1017
	public SynonymRelationship addSynonymName(TaxonNameBase synonymName, SynonymRelationshipType synonymType){
1018
		return addSynonymName(synonymName, synonymType, null, null);
1019
	}
1020
	/**
1021
	 * Creates a new {@link Synonym synonym} (with the given {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name}),
1022
	 * a new {@link SynonymRelationship synonym relationship} (with the new synonym, with the given 
1023
	 * {@link SynonymRelationshipType synonym relationship type} and with the {@link eu.etaxonomy.cdm.model.reference.ReferenceBase reference source}
1024
	 * on which the relationship assertion is based), returns the relationship
1025
	 * and adds it to the set of {@link #getSynonymRelations() synonym relationships} assigned
1026
	 * to <i>this</i> taxon. The new synonym will have the same {@link TaxonBase#getSec() concept reference}
1027
	 * as <i>this</i> taxon. The new synonym relationship will also be added to 
1028
	 * the set of {@link Synonym#getSynonymRelations() synonym relationships} belonging
1029
	 * to the created synonym.<BR>
1030
	 * The returned synonym relationship allows to add further information to it.
1031
	 * 
1032
	 * @param synonymName	the taxon name to be used as a synonym to be added
1033
	 * 						to <i>this</i> taxon's set of synonyms
1034
	 * @param synonymType	the synonym relationship category of the synonym
1035
	 * 						relationship to be added
1036
	 * @param citation		the reference source for the new synonym relationship
1037
	 * @param microcitation	the string with the details describing the exact localisation within the reference
1038
	 * @return 				the created synonym relationship
1039
	 * @see    	   			#addSynonymName(TaxonNameBase, SynonymRelationshipType, ReferenceBase, String)
1040
	 * @see    	   			#addSynonym(Synonym, SynonymRelationshipType)
1041
	 * @see    	   			#addSynonym(Synonym, SynonymRelationshipType, ReferenceBase, String)
1042
	 * @see    	   			#addSynonymRelation(SynonymRelationship)
1043
	 * @see    	   			#addHomotypicSynonym(Synonym, ReferenceBase, String)
1044
	 * @see    	   			#addHomotypicSynonymName(TaxonNameBase, ReferenceBase, String)
1045
	 * @see    	   			#addHeterotypicSynonymName(TaxonNameBase)
1046
	 * @see    	   			#addHeterotypicSynonymName(TaxonNameBase, HomotypicalGroup, ReferenceBase, String)
1047
	 * @see    	   			#getSynonymRelations()
1048
	 * @see    				#removeSynonym(Synonym)
1049
	 * @see    	   			Synonym#getSynonymRelations()
1050
	 */
1051
	public SynonymRelationship addSynonymName(TaxonNameBase synonymName, SynonymRelationshipType synonymType, ReferenceBase citation, String citationMicroReference){
1052
		Synonym synonym = Synonym.NewInstance(synonymName, this.getSec());
1053
		return addSynonym(synonym, synonymType, citation, citationMicroReference);
1054
	}
1055

    
1056
	/**
1057
	 * Creates a new {@link Synonym synonym} (with the given {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name}),
1058
	 * a new {@link SynonymRelationship synonym relationship} (with the new synonym and with the 
1059
	 * {@link SynonymRelationshipType#HETEROTYPIC_SYNONYM_OF() "is heterotypic synonym of" relationship type}),
1060
	 * returns the relationship and adds it to the set of
1061
	 * {@link #getSynonymRelations() synonym relationships} assigned to <i>this</i> taxon.
1062
	 * The new synonym will have the same {@link TaxonBase#getSec() concept reference}
1063
	 * as <i>this</i> taxon. The new synonym relationship will also be added to 
1064
	 * the set of {@link Synonym#getSynonymRelations() synonym relationships} belonging
1065
	 * to the created synonym.<BR>
1066
	 * The returned synonym relationship allows to add further information to it.
1067
	 * 
1068
	 * @param synonymName	the taxon name to be used as an heterotypic synonym
1069
	 * 						to be added to <i>this</i> taxon's set of synonyms
1070
	 * @return 				the created synonym relationship
1071
	 * @see    	   			#addHeterotypicSynonymName(TaxonNameBase, HomotypicalGroup, ReferenceBase, String)
1072
	 * @see    	   			#addSynonymName(TaxonNameBase, SynonymRelationshipType)
1073
	 * @see    	   			#addSynonymName(TaxonNameBase, SynonymRelationshipType, ReferenceBase, String)
1074
	 * @see    	   			#addSynonym(Synonym, SynonymRelationshipType)
1075
	 * @see    	   			#addSynonym(Synonym, SynonymRelationshipType, ReferenceBase, String)
1076
	 * @see    	   			#addSynonymRelation(SynonymRelationship)
1077
	 * @see    	   			#addHomotypicSynonym(Synonym, ReferenceBase, String)
1078
	 * @see    	   			#addHomotypicSynonymName(TaxonNameBase, ReferenceBase, String)
1079
	 * @see    	   			#getSynonymRelations()
1080
	 * @see    				#removeSynonym(Synonym)
1081
	 * @see    	   			Synonym#getSynonymRelations()
1082
	 */
1083
	public SynonymRelationship addHeterotypicSynonymName(TaxonNameBase synonymName){
1084
		return addHeterotypicSynonymName(synonymName, null, null, null);
1085
	}
1086
	
1087
	/**
1088
	 * Creates a new {@link Synonym synonym} (with the given {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name}),
1089
	 * a new {@link SynonymRelationship synonym relationship} (with the new synonym, with the 
1090
	 * {@link SynonymRelationshipType#HETEROTYPIC_SYNONYM_OF() "is heterotypic synonym of" relationship type}
1091
	 * and with the {@link eu.etaxonomy.cdm.model.reference.ReferenceBase reference source}
1092
	 * on which the relationship assertion is based), returns the relationship
1093
	 * and adds it to the set of {@link #getSynonymRelations() synonym relationships} assigned
1094
	 * to <i>this</i> taxon. The new synonym will have the same {@link TaxonBase#getSec() concept reference}
1095
	 * as <i>this</i> taxon. Furthermore the new synonym relationship will be 
1096
	 * added to the set of {@link Synonym#getSynonymRelations() synonym relationships} belonging
1097
	 * to the created synonym and the taxon name used as synonym will be added
1098
	 * to the given {@link name.HomotypicalGroup homotypical group}.<BR>
1099
	 * The returned synonym relationship allows to add further information to it.
1100
	 * 
1101
	 * @param synonymName		the taxon name to be used as an heterotypic synonym
1102
	 * 							to be added to <i>this</i> taxon's set of synonyms
1103
	 * @param homotypicalGroup	the homotypical group to which the taxon name
1104
	 * 							of the synonym will be added
1105
	 * @param citation			the reference source for the new synonym relationship
1106
	 * @param microcitation		the string with the details describing the exact localisation
1107
	 * 							within the reference
1108
	 * @return 					the created synonym relationship
1109
	 * @see    	   				#addHeterotypicSynonymName(TaxonNameBase)
1110
	 * @see    	   				#addSynonymName(TaxonNameBase, SynonymRelationshipType, ReferenceBase, String)
1111
	 * @see    	   				#addSynonymName(TaxonNameBase, SynonymRelationshipType)
1112
	 * @see    	   				#addSynonym(Synonym, SynonymRelationshipType)
1113
	 * @see    	   				#addSynonym(Synonym, SynonymRelationshipType, ReferenceBase, String)
1114
	 * @see    	   				#addSynonymRelation(SynonymRelationship)
1115
	 * @see    	   				#addHomotypicSynonym(Synonym, ReferenceBase, String)
1116
	 * @see    	   				#addHomotypicSynonymName(TaxonNameBase, ReferenceBase, String)
1117
	 * @see    	   				#getSynonymRelations()
1118
	 * @see    					#removeSynonym(Synonym)
1119
	 * @see    	   				Synonym#getSynonymRelations()
1120
	 */
1121
	public SynonymRelationship addHeterotypicSynonymName(TaxonNameBase synonymName, HomotypicalGroup homotypicalGroup, ReferenceBase citation, String microCitation){
1122
		Synonym synonym = Synonym.NewInstance(synonymName, this.getSec());
1123
		if (homotypicalGroup != null){
1124
			homotypicalGroup.addTypifiedName(synonymName);
1125
		}
1126
		return addSynonym(synonym, SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF(), citation, microCitation);
1127
	}
1128
	
1129
	/**
1130
	 * Creates a new {@link Synonym synonym} (with the given {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name}),
1131
	 * a new {@link SynonymRelationship synonym relationship} (with the new synonym, with the 
1132
	 * {@link SynonymRelationshipType#HOMOTYPIC_SYNONYM_OF() "is homotypic synonym of" relationship type})
1133
	 * and with the {@link eu.etaxonomy.cdm.model.reference.ReferenceBase reference source}
1134
	 * on which the relationship assertion is based), returns the relationship
1135
	 * and adds it to the set of {@link #getSynonymRelations() synonym relationships} assigned
1136
	 * to <i>this</i> taxon. The new synonym will have the same {@link TaxonBase#getSec() concept reference}
1137
	 * as <i>this</i> taxon. Furthermore the new synonym relationship will be 
1138
	 * added to the set of {@link Synonym#getSynonymRelations() synonym relationships} belonging
1139
	 * to the created synonym and the taxon name used as synonym will be added
1140
	 * to the same {@link eu.etaxonomy.cdm.model.name.HomotypicalGroup homotypical group} to which the taxon name
1141
	 * of <i>this</i> taxon belongs.<BR>
1142
	 * The returned synonym relationship allows to add further information to it.
1143
	 * 
1144
	 * @param synonymName	the taxon name to be used as an homotypic synonym
1145
	 * 						to be added to <i>this</i> taxon's set of synonyms
1146
	 * @param citation		the reference source for the new synonym relationship
1147
	 * @param microcitation	the string with the details describing the exact localisation
1148
	 * 						within the reference
1149
	 * @return 				the created synonym relationship
1150
	 * @see    	   			#addHomotypicSynonym(Synonym, ReferenceBase, String)
1151
	 * @see    	   			#addSynonymName(TaxonNameBase, SynonymRelationshipType, ReferenceBase, String)
1152
	 * @see    	   			#addSynonymName(TaxonNameBase, SynonymRelationshipType)
1153
	 * @see    	   			#addSynonym(Synonym, SynonymRelationshipType)
1154
	 * @see    	   			#addSynonym(Synonym, SynonymRelationshipType, ReferenceBase, String)
1155
	 * @see    	   			#addSynonymRelation(SynonymRelationship)
1156
	 * @see    	   			#addHeterotypicSynonymName(TaxonNameBase)
1157
	 * @see    	   			#addHeterotypicSynonymName(TaxonNameBase, HomotypicalGroup, ReferenceBase, String)
1158
	 * @see    	   			#getSynonymRelations()
1159
	 * @see    				#removeSynonym(Synonym)
1160
	 * @see    	   			Synonym#getSynonymRelations()
1161
	 */
1162
	public SynonymRelationship addHomotypicSynonymName(TaxonNameBase synonymName, ReferenceBase citation, String microCitation){
1163
		Synonym synonym = Synonym.NewInstance(synonymName, this.getSec());
1164
		return addHomotypicSynonym(synonym, citation, microCitation);
1165
	}
1166
	
1167
	/**
1168
	 * Creates a new {@link SynonymRelationship synonym relationship} (with the given {@link Synonym synonym},
1169
	 * with the {@link SynonymRelationshipType#HOMOTYPIC_SYNONYM_OF() "is homotypic synonym of" relationship type}
1170
	 * and with the {@link eu.etaxonomy.cdm.model.reference.ReferenceBase reference source} on which the relationship
1171
	 * assertion is based), returns it and adds it to the set of
1172
	 * {@link #getSynonymRelations() synonym relationships} assigned to <i>this</i> taxon.
1173
	 * Furthermore the new synonym relationship will be added to the set of
1174
	 * {@link Synonym#getSynonymRelations() synonym relationships} belonging to the synonym
1175
	 * involved in this synonym relationship and the {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon name}
1176
	 * used as synonym will be added to the same {@link eu.etaxonomy.cdm.model.name.HomotypicalGroup homotypical group}
1177
	 * to which the taxon name of <i>this</i> taxon belongs.<BR>
1178
	 * The returned synonym relationship allows to add further information to it.
1179
	 * 
1180
	 * @param synonym		the synonym involved in the "is homotypic synonym of" relationship to be created
1181
	 * 						and added to <i>this</i> taxon's synonym relationships set
1182
	 * @param citation		the reference source for the new synonym relationship
1183
	 * @param microcitation	the string with the details describing the exact localisation within the reference
1184
	 * @return 				the created synonym relationship
1185
	 * @see    	   			#addHomotypicSynonymName(TaxonNameBase, ReferenceBase, String)
1186
	 * @see    	   			#addSynonym(Synonym, SynonymRelationshipType)
1187
	 * @see    	   			#addSynonym(Synonym, SynonymRelationshipType, ReferenceBase, String)
1188
	 * @see    	   			#addSynonymName(TaxonNameBase, SynonymRelationshipType, ReferenceBase, String)
1189
	 * @see    	   			#addSynonymName(TaxonNameBase, SynonymRelationshipType)
1190
	 * @see    	   			#addSynonymRelation(SynonymRelationship)
1191
	 * @see    	   			#addHeterotypicSynonymName(TaxonNameBase)
1192
	 * @see    	   			#addHeterotypicSynonymName(TaxonNameBase, HomotypicalGroup, ReferenceBase, String)
1193
	 * @see    	   			#getSynonymRelations()
1194
	 * @see    				#removeSynonym(Synonym)
1195
	 * @see    	   			Synonym#getSynonymRelations()
1196
	 */
1197
	public SynonymRelationship addHomotypicSynonym(Synonym synonym, ReferenceBase citation, String microCitation){
1198
		if (this.getName() != null){
1199
			this.getName().getHomotypicalGroup().addTypifiedName(synonym.getName());
1200
		}
1201
		SynonymRelationship synRel = addSynonym(synonym, SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF(), citation, microCitation);
1202
		return synRel;
1203
	}
1204
	
1205
	/** 
1206
	 * Removes the element(s) from the set of {@link SynonymRelationship synonym relationships}
1207
	 * assigned to <i>this</i> ("accepted/correct") taxon in which the given synonym is involved.
1208
	 * Due to bidirectionality the same synonym relationships will also be
1209
	 * removed from the set of synonym relationships assigned to the
1210
	 * {@link Synonym#getSynonymRelations() synonym} involved in the relationship. Furthermore the content of
1211
	 * the {@link SynonymRelationship#getAcceptedTaxon() accepted taxon} attribute and of the
1212
	 * {@link SynonymRelationship#getSynonym() synonym} attribute within the synonym relationships
1213
	 * themselves will be set to "null".
1214
	 *
1215
	 * @param  synonym  the synonym involved in the synonym relationship which should be deleted
1216
	 * @see     		#getSynonymRelations()
1217
	 * @see     		#addSynonym(Synonym, SynonymRelationshipType)
1218
	 * @see     		#addSynonym(Synonym, SynonymRelationshipType, ReferenceBase, String)
1219
	 * @see 			#removeSynonymRelation(SynonymRelationship)
1220
	 */
1221
	public void removeSynonym(Synonym synonym){
1222
		Set<SynonymRelationship> synonymRelationships = new HashSet<SynonymRelationship>();
1223
		synonymRelationships.addAll(this.getSynonymRelations());
1224
		for(SynonymRelationship synonymRelationship : synonymRelationships){
1225
			if (synonymRelationship.getAcceptedTaxon().equals(this) && synonymRelationship.getSynonym().equals(synonym)){
1226
				this.removeSynonymRelation(synonymRelationship);
1227
			}
1228
		}
1229
	}
1230
	
1231
	/** 
1232
	 * Returns an {@link java.lang.Iterable#iterator() iterator} over the set of taxa which
1233
	 * are {@link #getTaxonomicChildren() taxonomic children} of <i>this</i> taxon.
1234
	 * 
1235
	 * @see #getTaxonomicChildren()
1236
	 * @see java.lang.Iterable#iterator()
1237
	 */
1238
	public Iterator<Taxon> iterator() {
1239
		return new TaxonIterator(this.getTaxonomicChildren());
1240
	}
1241
	/**
1242
	 * inner iterator class for the iterable interface
1243
	 * @author m.doering
1244
	 *
1245
	 */
1246
	private class TaxonIterator implements Iterator<Taxon> {
1247
		   private Taxon[] items;
1248
		   private int i= 0;
1249
		   public TaxonIterator(Set<Taxon> items) {
1250
		      // check for null being passed in etc.
1251
		      this.items= items.toArray(new Taxon[0]);
1252
		   }
1253
		   // interface implementation
1254
		   public boolean hasNext() { return i < items.length; }
1255
		   public Taxon next() { return items[i++]; }
1256
		   public void remove() { throw new UnsupportedOperationException(); }
1257
	}
1258
	
1259
	/**
1260
	 * Retrieves the ordered list (depending on the date of publication) of
1261
	 * homotypic {@link Synonym synonyms} (according to the same {@link eu.etaxonomy.cdm.model.reference.ReferenceBase reference}
1262
	 * as for <i>this</i> taxon) under the condition that the {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon names}
1263
	 * of these synonyms and the taxon name of <i>this</i> taxon belong to the
1264
	 * same {@link eu.etaxonomy.cdm.model.name.HomotypicalGroup homotypical group}.
1265
	 * 
1266
	 * @return		the ordered list of homotypic synonyms
1267
	 * @see			#getHomotypicSynonymsByHomotypicRelationship()
1268
	 * @see			#getSynonyms()
1269
	 * @see			#getHomotypicSynonymyGroups()
1270
	 * @see			eu.etaxonomy.cdm.model.name.HomotypicalGroup
1271
	 * @see			eu.etaxonomy.cdm.model.name.HomotypicalGroup#getSynonymsInGroup(ReferenceBase)
1272
	 */
1273
	@Transient
1274
	public List<Synonym> getHomotypicSynonymsByHomotypicGroup(){
1275
		if (this.getHomotypicGroup() == null){
1276
			return null;
1277
		}else{
1278
			return this.getHomotypicGroup().getSynonymsInGroup(this.getSec());
1279
		}
1280
	}
1281
	
1282
	/**
1283
	 * Retrieves the ordered list (depending on the date of publication) of
1284
	 * homotypic {@link Synonym synonyms} (according to the same {@link eu.etaxonomy.cdm.model.reference.ReferenceBase reference}
1285
	 * as for <i>this</i> taxon) under the condition that these synonyms and
1286
	 * <i>this</i> taxon are involved in {@link SynonymRelationship synonym relationships} with an
1287
	 * "is homotypic synonym of" {@link SynonymRelationshipType#HOMOTYPIC_SYNONYM_OF() synonym relationship type}.
1288
	 * 
1289
	 * @return		the ordered list of homotypic synonyms
1290
	 * @see			#getHomotypicSynonymsByHomotypicGroup()
1291
	 * @see			#getSynonyms()
1292
	 * @see			#getHomotypicSynonymyGroups()
1293
	 * @see			SynonymRelationshipType
1294
	 */
1295
	@Transient
1296
	public List<Synonym> getHomotypicSynonymsByHomotypicRelationship(){
1297
		Set<SynonymRelationship> synonymRelations = this.getSynonymRelations(); 
1298
		List<Synonym> result = new ArrayList<Synonym>();
1299
		for(SynonymRelationship synonymRelation : synonymRelations) {
1300
    		if(synonymRelation.getType().equals(SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF())){
1301
				result.add(synonymRelation.getSynonym());
1302
    		}
1303
		}
1304
		return result;
1305
	}
1306
	
1307
	/**
1308
	 * Returns the ordered list of all {@link eu.etaxonomy.cdm.model.name.HomotypicalGroup homotypical groups} {@link Synonym synonyms} of
1309
	 * <i>this</i> taxon belongs to. {@link eu.etaxonomy.cdm.model.name.TaxonNameBase Taxon names} of homotypic synonyms
1310
	 * belong to the same homotypical group as the taxon name of <i>this</i>
1311
	 * taxon. Taxon names of heterotypic synonyms belong to at least one other
1312
	 * homotypical group. <BR>
1313
	 * The list returned is ordered according to the date of publication of the
1314
	 * first published name within each homotypical group.
1315
	 * 
1316
	 * @see			#getHeterotypicSynonymyGroups()
1317
	 * @see			#getSynonyms()
1318
	 * @see			eu.etaxonomy.cdm.model.name.HomotypicalGroup
1319
	 */
1320
	@Transient
1321
	public List<HomotypicalGroup> getHomotypicSynonymyGroups(){
1322
		List<HomotypicalGroup> result = new ArrayList<HomotypicalGroup>();
1323
		result.add(this.getHomotypicGroup());
1324
		for (TaxonNameBase taxonNameBase :this.getSynonymNames()){
1325
			if (taxonNameBase != null) {
1326
				if (!result.contains(taxonNameBase.getHomotypicalGroup())){
1327
					result.add(taxonNameBase.getHomotypicalGroup());
1328
				}
1329
			} // TODO: give error message to user
1330
		}
1331
		// TODO: sort list according to date of first published name within each group
1332
		return result;
1333
	}
1334
	
1335
	
1336
	
1337
	/**
1338
	 * @return the taxonStatusUnknown
1339
	 */
1340
	public boolean isTaxonStatusUnknown() {
1341
		return taxonStatusUnknown;
1342
	}
1343

    
1344
	/**
1345
	 * @param taxonStatusUnknown the taxonStatusUnknown to set
1346
	 */
1347
	public void setTaxonStatusUnknown(boolean taxonStatusUnknown) {
1348
		this.taxonStatusUnknown = taxonStatusUnknown;
1349
	}
1350

    
1351
	/**
1352
	 * Returns the List of all homotypic groups heterotypic synonyms of this taxon belongs too.
1353
	 * This does not include the homotypic group of <i>this</i> taxon.
1354
	 * @return
1355
	 */
1356
	/**
1357

    
1358
	 * Returns the ordered list of all {@link eu.etaxonomy.cdm.model.name.HomotypicalGroup homotypical groups} heterotypic
1359
	 * {@link Synonym synonyms} of <i>this</i> taxon belongs to.
1360
	 * {@link eu.etaxonomy.cdm.model.name.TaxonNameBase Taxon names} of heterotypic synonyms belong to at least
1361
	 * one homotypical group which cannot be the homotypical group to which the
1362
	 * taxon name of <i>this</i> taxon belongs. This method returns the same
1363
	 * list as the {@link #getHomotypicSynonymyGroups() getHomotypicSynonymyGroups} method
1364
	 * but the homotypical group to which the taxon name of <i>this</i> taxon
1365
	 * belongs.<BR>
1366
	 * The list returned is ordered according to the date of publication of the
1367
	 * first published name within each homotypical group.
1368
	 * 
1369
	 * @see			#getHeterotypicSynonymyGroups()
1370
	 * @see			#getSynonyms()
1371
	 * @see			SynonymRelationshipType#HETEROTYPIC_SYNONYM_OF()
1372
	 * @see			eu.etaxonomy.cdm.model.name.HomotypicalGroup
1373
	 */
1374
	@Transient
1375
	public List<HomotypicalGroup> getHeterotypicSynonymyGroups(){
1376
		List<HomotypicalGroup> list = getHomotypicSynonymyGroups();
1377
		list.remove(this.getHomotypicGroup());
1378
		//sort
1379
		Map<Synonym, HomotypicalGroup> map = new HashMap<Synonym, HomotypicalGroup>();
1380
		for (HomotypicalGroup homoGroup: list){
1381
			if (homoGroup != null) {
1382
				List<Synonym> synonymList = homoGroup.getSynonymsInGroup(getSec());
1383
				if (synonymList.size() > 0){
1384
					map.put(synonymList.get(0), homoGroup);
1385
				}
1386
			} // else { TODO: error message
1387
		}
1388
		List<Synonym> keyList = new ArrayList<Synonym>();
1389
		keyList.addAll(map.keySet());
1390
		Collections.sort(keyList, new TaxonComparator());
1391
		
1392
		List<HomotypicalGroup> result = new ArrayList<HomotypicalGroup>();
1393
		for(Synonym synonym: keyList){
1394
			result.add(map.get(synonym));
1395
		}
1396
		//sort end
1397
		return result;
1398
	}
1399

    
1400
}
(5-5/13)