Project

General

Profile

Download (59.4 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.NameRelationship;
18
import eu.etaxonomy.cdm.model.name.NameRelationshipType;
19
import eu.etaxonomy.cdm.model.name.NameTypeDesignation;
20
import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
21
import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
22
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
23
import eu.etaxonomy.cdm.model.name.TypeDesignationStatus;
24
import eu.etaxonomy.cdm.model.occurrence.Specimen;
25
import eu.etaxonomy.cdm.model.reference.ReferenceBase;
26

    
27
import org.apache.log4j.Logger;
28
import org.hibernate.annotations.Cascade;
29
import org.hibernate.annotations.CascadeType;
30

    
31
import java.lang.reflect.Method;
32
import java.util.*;
33

    
34
import javax.persistence.*;
35
import javax.xml.bind.annotation.XmlAccessType;
36
import javax.xml.bind.annotation.XmlAccessorType;
37
import javax.xml.bind.annotation.XmlElement;
38
import javax.xml.bind.annotation.XmlElementWrapper;
39
import javax.xml.bind.annotation.XmlIDREF;
40
import javax.xml.bind.annotation.XmlRootElement;
41
import javax.xml.bind.annotation.XmlSchemaType;
42
import javax.xml.bind.annotation.XmlTransient;
43
import javax.xml.bind.annotation.XmlType;
44

    
45
/**
46
 * The class for "accepted/correct" {@link TaxonBase taxa} (only these taxa according to
47
 * the opinion of the {@link reference.ReferenceBase reference} can build a taxonomic tree).
48
 * An {@link java.lang.Iterable interface} is supported to iterate through taxonomic children.<BR>
49
 * Splitting taxa in "accepted/correct" and {@link Synonym "synonyms"} makes it easier to handle
50
 * particular relationships between ("accepted/correct") taxa on the one hand
51
 * and between ("synonym") taxa and ("accepted/correct") taxa on the other.
52
 * 
53
 * @author m.doering
54
 * @version 1.0
55
 * @created 08-Nov-2007 13:06:56
56
 */
57
@XmlAccessorType(XmlAccessType.FIELD)
58
@XmlType(name = "Taxon", propOrder = {
59
    "taxonomicParentCache",
60
    "taxonomicChildrenCount",
61
    "synonymRelations",
62
    "relationsFromThisTaxon",
63
    "relationsToThisTaxon",
64
    "descriptions"
65
})
66
@XmlRootElement(name = "Taxon")
67
@Entity
68
public class Taxon extends TaxonBase implements Iterable<Taxon>, IRelated<RelationshipBase>{
69

    
70
	static Logger logger = Logger.getLogger(Taxon.class);
71

    
72
	@XmlElementWrapper(name = "Descriptions")
73
	@XmlElement(name = "Description")
74
	private Set<TaxonDescription> descriptions = new HashSet<TaxonDescription>();
75

    
76
	// all related synonyms
77
	@XmlElementWrapper(name = "SynonymRelations")
78
	@XmlElement(name = "SynonymRelationship")
79
	private Set<SynonymRelationship> synonymRelations = new HashSet<SynonymRelationship>();
80

    
81
	// all taxa relations with rel.fromTaxon==this
82
	@XmlElementWrapper(name = "RelationsFromThisTaxon")
83
	@XmlElement(name = "FromThisTaxonRelationship")
84
	private Set<TaxonRelationship> relationsFromThisTaxon = new HashSet<TaxonRelationship>();
85

    
86
	// all taxa relations with rel.toTaxon==this
87
	@XmlElementWrapper(name = "RelationsToThisTaxon")
88
	@XmlElement(name = "ToThisTaxonRelationship")
89
	private Set<TaxonRelationship> relationsToThisTaxon = new HashSet<TaxonRelationship>();
90

    
91
	// shortcut to the taxonomicIncluded (parent) taxon. Managed by the taxonRelations setter
92
	@XmlElement(name = "TaxonomicParentCache")
93
	@XmlIDREF
94
	@XmlSchemaType(name = "IDREF")
95
	private Taxon taxonomicParentCache;
96

    
97
	//cached number of taxonomic children
98
	@XmlElement(name = "TaxonomicChildrenCount")
99
	private int taxonomicChildrenCount;
100

    
101
	private static Method methodDescriptionSetTaxon;
102
	
103
	
104
// ************* CONSTRUCTORS *************/	
105

    
106
	//TODO should be private, but still produces Spring init errors
107
	@Deprecated
108
	public Taxon(){
109
	}
110
	
111
	/** 
112
	 * Class constructor: creates a new (accepted/correct) taxon instance with
113
	 * the {@link name.TaxonNameBase taxon name} used and the {@link reference.ReferenceBase reference}
114
	 * using it.
115
	 * 
116
	 * @param  taxonNameBase	the taxon name used
117
	 * @param  sec				the reference using the taxon name
118
	 * @see    					TaxonBase#TaxonBase(TaxonNameBase, ReferenceBase)
119
	 */
120
	public Taxon(TaxonNameBase taxonNameBase, ReferenceBase sec){
121
		super(taxonNameBase, sec);
122
	}
123
	 
124
//********* METHODS **************************************/
125

    
126
	/** 
127
	 * Creates a new (accepted/correct) taxon instance with
128
	 * the {@link name.TaxonNameBase taxon name} used and the {@link reference.ReferenceBase reference}
129
	 * using it.
130
	 * 
131
	 * @param  taxonNameBase	the taxon name used
132
	 * @param  sec				the reference using the taxon name
133
	 * @see    					#Taxon(TaxonNameBase, ReferenceBase)
134
	 */
135
	public static Taxon NewInstance(TaxonNameBase taxonNameBase, ReferenceBase sec){
136
		Taxon result = new Taxon(taxonNameBase, sec);
137
		return result;
138
	}
139
	
140
	 
141
	/** 
142
	 * Returns the set of {@link description.TaxonDescription taxon descriptions}
143
	 * concerning <i>this</i> taxon.
144
	 * 
145
	 * @see #removeDescription(TaxonDescription)
146
	 * @see #addDescription(TaxonDescription)
147
	 * @see description.TaxonDescription#getTaxon()
148
	 */
149
	@OneToMany(mappedBy="taxon", fetch= FetchType.LAZY) 
150
	@Cascade({CascadeType.SAVE_UPDATE})
151
	public Set<TaxonDescription> getDescriptions() {
152
		return descriptions;
153
	}
154
	/** 
155
	 * @see #getDescriptions()
156
	 */
157
	protected void setDescriptions(Set<TaxonDescription> descriptions) {
158
		this.descriptions = descriptions;
159
	}
160
	/** 
161
	 * Adds a new {@link description.TaxonDescription taxon description} to the set
162
	 * of taxon descriptions assigned to <i>this</i> (accepted/correct) taxon.
163
	 * Due to bidirectionality the content of the {@link description.TaxonDescription#getTaxon() taxon attribute} of the
164
	 * taxon description itself will be replaced with <i>this</i> taxon. The taxon
165
	 * description will also be removed from the set of taxon descriptions
166
	 * assigned to its previous taxon. 
167
	 *
168
	 * @param  description	the taxon description to be added for <i>this</i> taxon
169
	 * @see     		  	#getDescriptions()
170
	 * @see     		  	#removeDescription(TaxonDescription)
171
	 * @see 			  	description.TaxonDescription#getTaxon()
172
	 */
173
	public void addDescription(TaxonDescription description) {
174
		initMethods();
175
		if (description.getTaxon() != null){
176
			description.getTaxon().removeDescription(description);
177
		}
178
		//description.setTaxon(this) for not visible method
179
		this.invokeSetMethod(methodDescriptionSetTaxon, description);
180
		descriptions.add(description);
181
		
182
	}
183
	/** 
184
	 * Removes one element from the set of {@link description.TaxonDescription taxon descriptions} assigned
185
	 * to <i>this</i> (accepted/correct) taxon. Due to bidirectionality the content of
186
	 * the {@link description.TaxonDescription#getTaxon() taxon attribute} of the taxon description
187
	 * itself will be set to "null".
188
	 *
189
	 * @param  description  the taxon description which should be removed
190
	 * @see     		  	#getDescriptions()
191
	 * @see     		  	#addDescription(TaxonDescription)
192
	 * @see 			  	description.TaxonDescription#getTaxon()
193
	 */
194
	public void removeDescription(TaxonDescription description) {
195
		initMethods();
196
		//description.setTaxon(null) for not visible method
197
		this.invokeSetMethodWithNull(methodDescriptionSetTaxon, description);
198
		descriptions.remove(description);
199
	}
200

    
201
	private void initMethods(){
202
		if (methodDescriptionSetTaxon == null){
203
			try {
204
				methodDescriptionSetTaxon = TaxonDescription.class.getDeclaredMethod("setTaxon", Taxon.class);
205
				methodDescriptionSetTaxon.setAccessible(true);
206
			} catch (Exception e) {
207
				e.printStackTrace();
208
				//TODO handle exception
209
			}
210
		}
211
	}
212

    
213

    
214
	/** 
215
	 * Returns the set of all {@link SynonymRelationship synonym relationships}
216
	 * in which <i>this</i> ("accepted/correct") taxon is involved. <i>This</i> taxon can only
217
	 * be the target of these synonym relationships. 
218
	 *  
219
	 * @see    #addSynonymRelation(SynonymRelationship)
220
	 * @see    #removeSynonymRelation(SynonymRelationship)
221
	 * @see    #getSynonyms()
222
	 */
223
	@OneToMany(mappedBy="relatedTo", fetch=FetchType.LAZY)
224
	@Cascade({CascadeType.SAVE_UPDATE})
225
	public Set<SynonymRelationship> getSynonymRelations() {
226
		return synonymRelations;
227
	}
228
	/** 
229
	 * @see    #getSynonymRelations()
230
	 * @see    #addSynonymRelation(SynonymRelationship)
231
	 */
232
	protected void setSynonymRelations(Set<SynonymRelationship> synonymRelations) {
233
		this.synonymRelations = synonymRelations;
234
	}
235
	/**
236
	 * Adds an existing {@link SynonymRelationship synonym relationship} to the set of
237
	 * {@link #getSynonymRelations() synonym relationships} assigned to <i>this</i> taxon. If
238
	 * the target of the synonym relationship does not match with <i>this</i> taxon
239
	 * no addition will be carried out.
240
	 * 
241
	 * @param synonymRelation	the synonym relationship to be added to <i>this</i> taxon's
242
	 * 							synonym relationships set
243
	 * @see    	   				#getSynonymRelations()
244
	 * @see    	   				#addSynonym(Synonym, SynonymRelationshipType)
245
	 * @see    	   				#addSynonym(Synonym, SynonymRelationshipType, ReferenceBase, String)
246
	 * @see    	   				#addSynonymName(TaxonNameBase, SynonymRelationshipType)
247
	 * @see    	   				#addSynonymName(TaxonNameBase, SynonymRelationshipType, ReferenceBase, String)
248
	 */
249
	protected void addSynonymRelation(SynonymRelationship synonymRelation) {
250
		this.synonymRelations.add(synonymRelation);
251
	}
252
	/** 
253
	 * Removes one element from the set of {@link SynonymRelationship synonym relationships} assigned
254
	 * to <i>this</i> (accepted/correct) taxon. Due to bidirectionality the given
255
	 * synonym relationship will also be removed from the set of synonym
256
	 * relationships assigned to the {@link Synonym#getSynonymRelations() synonym} involved in the
257
	 * relationship. Furthermore the content of
258
	 * the {@link SynonymRelationship#getAcceptedTaxon() accepted taxon attribute} and of the
259
	 * {@link SynonymRelationship#getSynonym() synonym attribute} within the synonym relationship
260
	 * itself will be set to "null".
261
	 *
262
	 * @param  synonymRelation  the synonym relationship which should be deleted
263
	 * @see     		  		#getSynonymRelations()
264
	 * @see     		  		#addSynonymRelation(SynonymRelationship)
265
	 * @see 			  		#removeSynonym(Synonym)
266
	 */
267
	public void removeSynonymRelation(SynonymRelationship synonymRelation) {
268
		synonymRelation.setAcceptedTaxon(null);
269
		Synonym synonym = synonymRelation.getSynonym();
270
		if (synonym != null){
271
			synonymRelation.setSynonym(null);
272
			synonym.removeSynonymRelation(synonymRelation);
273
		}
274
		this.synonymRelations.remove(synonymRelation);
275
	}
276

    
277
	
278
	/** 
279
	 * Returns the set of all {@link TaxonRelationship taxon relationships}
280
	 * between two taxa in which <i>this</i> taxon is involved as a source.
281
	 *  
282
	 * @see    #getRelationsToThisTaxon()
283
	 * @see    #getTaxonRelations()
284
	 */
285
	@OneToMany(mappedBy="relatedFrom", fetch=FetchType.LAZY)
286
	@Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE_ORPHAN})
287
	public Set<TaxonRelationship> getRelationsFromThisTaxon() {
288
		return relationsFromThisTaxon;
289
	}
290
	/** 
291
	 * @see    #getRelationsFromThisTaxon()
292
	 */
293
	protected void setRelationsFromThisTaxon(
294
			Set<TaxonRelationship> relationsFromThisTaxon) {
295
		this.relationsFromThisTaxon = relationsFromThisTaxon;
296
	}
297

    
298

    
299
	/** 
300
	 * Returns the set of all {@link TaxonRelationship taxon relationships}
301
	 * between two taxa in which <i>this</i> taxon is involved as a target.
302
	 *  
303
	 * @see    #getRelationsFromThisTaxon()
304
	 * @see    #getTaxonRelations()
305
	 */
306
	@OneToMany(mappedBy="relatedTo", fetch=FetchType.LAZY)
307
	@Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE_ORPHAN})
308
	public Set<TaxonRelationship> getRelationsToThisTaxon() {
309
		return relationsToThisTaxon;
310
	}
311
	/** 
312
	 * @see    #getRelationsToThisTaxon()
313
	 */
314
	protected void setRelationsToThisTaxon(Set<TaxonRelationship> relationsToThisTaxon) {
315
		this.relationsToThisTaxon = relationsToThisTaxon;
316
	}
317

    
318
	@ManyToOne
319
	// used by hibernate only...
320
	private Taxon getTaxonomicParentCache() {
321
		return taxonomicParentCache;
322
	}
323
	private void setTaxonomicParentCache(Taxon taxonomicParent) {
324
		this.taxonomicParentCache = taxonomicParent;
325
	}
326

    
327
	/** 
328
	 * Returns the set of all {@link TaxonRelationship taxon relationships}
329
	 * between two taxa in which <i>this</i> taxon is involved either as a source or
330
	 * as a target.
331
	 *  
332
	 * @see    #getRelationsFromThisTaxon()
333
	 * @see    #getRelationsToThisTaxon()
334
	 */
335
	@Transient
336
	public Set<TaxonRelationship> getTaxonRelations() {
337
		Set<TaxonRelationship> rels = new HashSet<TaxonRelationship>();
338
		rels.addAll(getRelationsToThisTaxon());
339
		rels.addAll(getRelationsFromThisTaxon());
340
		return rels;
341
	}
342
	/** 
343
	 * Removes one {@link TaxonRelationship taxon relationship} from one of both sets of
344
	 * {@link #getTaxonRelations() taxon relationships} in which <i>this</i> taxon is involved
345
	 * either as a {@link #getRelationsFromThisTaxon() source} or as a {@link #getRelationsToThisTaxon() target}.
346
	 * The taxon relationship will also be removed from one of both sets
347
	 * belonging to the second taxon involved. Furthermore the inherited RelatedFrom and
348
	 * RelatedTo attributes of the given taxon relationship will be nullified.<P>
349
	 * If the taxon relationship concerns the taxonomic tree possible
350
	 * modifications of the {@link #getTaxonomicParent() parent taxon} or of the number of
351
	 * {@link #getTaxonomicChildrenCount() childrens} will be stored.
352
	 *
353
	 * @param  rel  the taxon relationship which should be removed from one
354
	 * 				of both sets
355
	 * @see    		#getTaxonRelations()
356
	 * @see    	    #getTaxonomicParent()
357
	 * @see    	    #getTaxonomicChildrenCount()
358
	 * @see    		common.RelationshipBase#getRelatedFrom()
359
	 * @see    		common.RelationshipBase#getRelatedTo()
360
	 * 
361
	 */
362
	public void removeTaxonRelation(TaxonRelationship rel) {
363
		logger.warn("remove TaxonRelation");  //for testing only 
364
		this.relationsToThisTaxon.remove(rel);
365
		this.relationsFromThisTaxon.remove(rel);
366
		Taxon fromTaxon = rel.getFromTaxon();
367
		Taxon toTaxon = rel.getToTaxon();
368
		// check if this removes the taxonomical parent. If so, also remove shortcut to the higher taxon
369
		if (rel.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN()) ){
370
			if (fromTaxon != null && fromTaxon.equals(this)){
371
				this.setTaxonomicParentCache(null);
372
			}else if (toTaxon != null && toTaxon.equals(this)){
373
				this.setTaxonomicChildrenCount(computeTaxonomicChildrenCount());	
374
			}
375
		}
376
		//delete Relationship from other related Taxon
377
		if (fromTaxon != null && fromTaxon != this){
378
			rel.setToTaxon(null);  //remove this Taxon from relationship
379
			fromTaxon.removeTaxonRelation(rel);
380
		}
381
		if (toTaxon != null && toTaxon != this){
382
			rel.setFromTaxon(null); //remove this Taxon from relationship
383
			toTaxon.removeTaxonRelation(rel);
384
		}
385
	}
386

    
387
	/**
388
	 * Adds an existing {@link TaxonRelationship taxon relationship} either to the set of
389
	 * {@link #getRelationsToThisTaxon() taxon relationships to <i>this</i> taxon} or to the set of
390
	 * {@link #getRelationsFromThisTaxon() taxon relationships from <i>this</i> taxon}. If neither the
391
	 * source nor the target of the taxon relationship match with <i>this</i> taxon
392
	 * no addition will be carried out. The taxon relationship will also be
393
	 * added to the second taxon involved in the given relationship.<P>
394
	 * If the taxon relationship concerns the taxonomic tree possible
395
	 * modifications of the {@link #getTaxonomicParent() parent taxon} or of the number of
396
	 * {@link #getTaxonomicChildrenCount() childrens} will be stored.
397
	 * 
398
	 * @param rel  the taxon relationship to be added to one of <i>this</i> taxon's taxon relationships sets
399
	 * @see    	   #addTaxonRelation(Taxon, TaxonRelationshipType, ReferenceBase, String)
400
	 * @see    	   #getTaxonRelations()
401
	 * @see    	   #getRelationsFromThisTaxon()
402
	 * @see    	   #getRelationsToThisTaxon()
403
	 * @see    	   #getTaxonomicParent()
404
	 * @see    	   #getTaxonomicChildrenCount()
405
	 */
406
	public void addTaxonRelation(TaxonRelationship rel) {
407
		if (rel!=null && rel.getType()!=null && !getTaxonRelations().contains(rel) ){
408
			Taxon toTaxon=rel.getToTaxon();
409
			Taxon fromTaxon=rel.getFromTaxon();
410
			if ( this.equals(toTaxon) || this.equals(fromTaxon) ){
411
				if (this.equals(fromTaxon)){
412
					relationsFromThisTaxon.add(rel);
413
					// also add relation to other taxon object
414
					if (toTaxon!=null){
415
						toTaxon.addTaxonRelation(rel);
416
					}
417
					// check if this sets the taxonomical parent. If so, remember a shortcut to this taxon
418
					if (rel.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN()) && toTaxon!=null ){
419
						this.setTaxonomicParentCache(toTaxon);
420
					}
421
				}else if (this.equals(toTaxon)){
422
					relationsToThisTaxon.add(rel);
423
					// also add relation to other taxon object
424
					if (fromTaxon!=null){
425
						fromTaxon.addTaxonRelation(rel);
426
					}
427
					if (rel.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN()) && fromTaxon!=null ){
428
						this.taxonomicChildrenCount++;
429
					}
430
					
431
				}
432
			}
433
		}	
434
	}
435
		
436
	/* (non-Javadoc)
437
	 * @see eu.etaxonomy.cdm.model.common.IRelated#addRelationship(eu.etaxonomy.cdm.model.common.RelationshipBase)
438
	 */
439
	@Deprecated //for inner use by RelationshipBase only
440
	public void addRelationship(RelationshipBase rel){
441
		if (rel instanceof TaxonRelationship){
442
			addTaxonRelation((TaxonRelationship)rel);
443
		}else if (rel instanceof SynonymRelationship){
444
			addSynonymRelation((SynonymRelationship)rel);
445
		}else{
446
			throw new ClassCastException("Wrong Relationsship type for Taxon.addRelationship");
447
		}
448
	}
449
	
450
	/**
451
	 * Creates a new {@link TaxonRelationship taxon relationship} instance where <i>this</i> taxon
452
	 * plays the source role and adds it to the set of
453
	 * {@link #getRelationsFromThisTaxon() "taxon relationships from"} belonging to <i>this</i> taxon.
454
	 * The taxon relationship will also be added to the set of taxon
455
	 * relationships to the second taxon involved in the created relationship.<P>
456
	 * If the taxon relationship concerns the taxonomic tree possible
457
	 * modifications of the {@link #getTaxonomicParent() parent taxon} or of the number of
458
	 * {@link #getTaxonomicChildrenCount() childrens} will be stored.
459
	 * 
460
	 * @param toTaxon		the taxon which plays the target role in the new taxon relationship
461
	 * @param type			the taxon relationship type for the new taxon relationship
462
	 * @param citation		the reference source for the new taxon relationship
463
	 * @param microcitation	the string with the details describing the exact localisation within the reference
464
	 * @see    	   			#addTaxonRelation(TaxonRelationship)
465
	 * @see    	   			#getTaxonRelations()
466
	 * @see    	   			#getRelationsFromThisTaxon()
467
	 * @see    	   			#getRelationsToThisTaxon()
468
	 * @see    	   			#getTaxonomicParent()
469
	 * @see    	   			#getTaxonomicChildrenCount()
470
	 */
471
	public void addTaxonRelation(Taxon toTaxon, TaxonRelationshipType type, ReferenceBase citation, String microcitation) {
472
		TaxonRelationship rel = new TaxonRelationship(this, toTaxon, type, citation, microcitation);
473
	}
474
	/**
475
	 * Creates a new {@link TaxonRelationship taxon relationship} (with {@link TaxonRelationshipType taxon relationship type}
476
	 * "misapplied name for") instance where <i>this</i> taxon plays the target role
477
	 * and adds it to the set of {@link #getRelationsToThisTaxon() taxon relationships to <i>this</i> taxon}.
478
	 * The taxon relationship will also be added to the set of taxon
479
	 * relationships to the other (misapplied name) taxon involved in the created relationship.
480
	 * 
481
	 * @param misappliedNameTaxon	the taxon which plays the target role in the new taxon relationship
482
	 * @param citation				the reference source for the new taxon relationship
483
	 * @param microcitation			the string with the details describing the exact localisation within the reference
484
	 * @see    	   					#getMisappliedNames()
485
	 * @see    	   					#addTaxonRelation(Taxon, TaxonRelationshipType, ReferenceBase, String)
486
	 * @see    	   					#addTaxonRelation(TaxonRelationship)
487
	 * @see    	   					#getTaxonRelations()
488
	 * @see    	   					#getRelationsFromThisTaxon()
489
	 * @see    	   					#getRelationsToThisTaxon()
490
	 */
491
	public void addMisappliedName(Taxon misappliedNameTaxon, ReferenceBase citation, String microcitation) {
492
		misappliedNameTaxon.addTaxonRelation(this, TaxonRelationshipType.MISAPPLIEDNAMEFOR(), citation, microcitation);
493
	}
494

    
495
	
496
	/**
497
	 * Creates a new {@link TaxonRelationship taxon relationship} (with {@link TaxonRelationshipType taxon relationship type}
498
	 * "taxonomically included in") instance where <i>this</i> taxon plays the target
499
	 * role (parent) and adds it to the set of
500
	 * {@link #getRelationsToThisTaxon() "taxon relationships to"} belonging to <i>this</i> taxon.
501
	 * The taxon relationship will also be added to the set of
502
	 * {@link #getRelationsFromThisTaxon() "taxon relationships from"} belonging to the second taxon
503
	 * (child) involved in the created relationship.<P>
504
	 * Since the taxon relationship concerns the modifications
505
	 * of the number of {@link #getTaxonomicChildrenCount() childrens} for <i>this</i> taxon and
506
	 * of the {@link #getTaxonomicParent() parent taxon} for the child taxon will be stored.
507
	 * The {@link name.Rank rank} of the taxon name used as a parent taxon must be higher
508
	 * than the rank of the taxon name used as a child taxon.
509
	 * 
510
	 * @param child			the taxon which plays the source role (child) in the new taxon relationship
511
	 * @param citation		the reference source for the new taxon relationship
512
	 * @param microcitation	the string with the details describing the exact localisation within the reference
513
	 * @see    	   			#setTaxonomicParent(Taxon, ReferenceBase, String)
514
	 * @see    	   			#addTaxonRelation(Taxon, TaxonRelationshipType, ReferenceBase, String)
515
	 * @see    	   			#addTaxonRelation(TaxonRelationship)
516
	 * @see    	   			#getTaxonRelations()
517
	 * @see    	   			#getRelationsFromThisTaxon()
518
	 * @see    	   			#getRelationsToThisTaxon()
519
	 * @see    	   			#getTaxonomicParent()
520
	 * @see    	   			#getTaxonomicChildrenCount()
521
	 */
522
	@Transient
523
	public void addTaxonomicChild(Taxon child, ReferenceBase citation, String microcitation){
524
		if (child == null){
525
			throw new NullPointerException("Child Taxon is 'null'");
526
		}else{
527
			child.setTaxonomicParent(this, citation, microcitation);
528
		}
529
	}
530
	/** 
531
	 * Removes one {@link TaxonRelationship taxon relationship} with {@link TaxonRelationshipType taxon relationship type}
532
	 * "taxonomically included in" and with the given child taxon playing the
533
	 * source role from the set of {@link #getRelationsToThisTaxon() "taxon relationships to"} belonging
534
	 * to <i>this</i> taxon. The taxon relationship will also be removed from the set
535
	 * of {@link #getRelationsFromThisTaxon() "taxon relationships from"} belonging to the child taxon.
536
	 * Furthermore the inherited RelatedFrom and RelatedTo attributes of the
537
	 * taxon relationship will be nullified.<P>
538
	 * Since the taxon relationship concerns the taxonomic tree modifications
539
	 * of the number of {@link #getTaxonomicChildrenCount() childrens} for <i>this</i> taxon and
540
	 * of the {@link #getTaxonomicParent() parent taxon} for the child taxon will be stored.
541
	 *
542
	 * @param  child	the taxon playing the source role in the relationship to be removed
543
	 * @see    	    	#removeTaxonRelation(TaxonRelationship)
544
	 * @see    			#getRelationsToThisTaxon()
545
	 * @see    			#getRelationsFromThisTaxon()
546
	 * @see    	    	#getTaxonomicParent()
547
	 * @see    	    	#getTaxonomicChildrenCount()
548
	 * @see    			common.RelationshipBase#getRelatedFrom()
549
	 * @see    			common.RelationshipBase#getRelatedTo()
550
	 * 
551
	 */
552
	@Transient
553
	public void removeTaxonomicChild(Taxon child){
554
		Set<TaxonRelationship> taxRels = this.getTaxonRelations();
555
		for (TaxonRelationship taxRel : taxRels ){
556
			if (taxRel.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN()) && taxRel.getFromTaxon().equals(child)){
557
				this.removeTaxonRelation(taxRel);
558
			}
559
		}
560
	}
561
	
562
	/** 
563
	 * Returns the taxon which is the next higher taxon (parent) of <i>this</i> taxon
564
	 * within the taxonomic tree and which is stored in the
565
	 * TaxonomicParentCache attribute. Each taxon can have only one parent taxon.
566
	 * The child taxon and the parent taxon play the source respectively the
567
	 * target role in one {@link TaxonRelationship taxon relationship} with
568
	 * {@link TaxonRelationshipType taxon relationship type} "taxonomically included in".
569
	 * The {@link name.Rank rank} of the taxon name used as a parent taxon must be higher
570
	 * than the rank of the taxon name used as a child taxon.
571
	 * 
572
	 * @see  #setTaxonomicParent(Taxon, ReferenceBase, String)
573
	 * @see  #getTaxonomicChildren()
574
	 * @see  #getTaxonomicChildrenCount()
575
	 * @see  #getRelationsFromThisTaxon()
576
	 */
577
	@Transient
578
	public Taxon getTaxonomicParent() {
579
		return getTaxonomicParentCache();
580
	}
581
	/**
582
	 * Replaces both the taxonomic parent cache with the given new parent taxon
583
	 * and the corresponding taxon relationship with a new {@link TaxonRelationship taxon relationship}
584
	 * (with {@link TaxonRelationshipType taxon relationship type} "taxonomically included in") instance.
585
	 * In the new taxon relationship <i>this</i> taxon plays the source role (child).
586
	 * This method creates and adds the new taxon relationship to the set of
587
	 * {@link #getRelationsFromThisTaxon() "taxon relationships from"} belonging to <i>this</i> taxon.
588
	 * The taxon relationship will also be added to the set of
589
	 * {@link #getRelationsToThisTaxon() "taxon relationships to"} belonging to the second taxon
590
	 * (parent) involved in the new relationship.<P>
591
	 * Since the taxon relationship concerns the taxonomic tree modifications
592
	 * of the {@link #getTaxonomicParent() parent taxon} for <i>this</i> taxon and of the number of
593
	 * {@link #getTaxonomicChildrenCount() childrens} for the child taxon will be stored.
594
	 * 
595
	 * @param newParent		the taxon which plays the target role (parent) in the new taxon relationship
596
	 * @param citation		the reference source for the new taxon relationship
597
	 * @param microcitation	the string with the details describing the exact localisation within the reference
598
	 * @see    	   			#removeTaxonRelation(TaxonRelationship)
599
	 * @see    	   			#getTaxonomicParent()
600
	 * @see    	   			#addTaxonRelation(Taxon, TaxonRelationshipType, ReferenceBase, String)
601
	 * @see    	   			#addTaxonRelation(TaxonRelationship)
602
	 * @see    	   			#getTaxonRelations()
603
	 * @see    	   			#getRelationsFromThisTaxon()
604
	 * @see    	   			#getRelationsToThisTaxon()
605
	 * @see    	   			#getTaxonomicChildrenCount()
606
	 */
607
	public void setTaxonomicParent(Taxon newParent, ReferenceBase citation, String microcitation){
608
		//remove previously existing parent relationship!!!
609
		Taxon oldParent = this.getTaxonomicParent();
610
		Set<TaxonRelationship> taxRels = this.getTaxonRelations();
611
		for (TaxonRelationship taxRel : taxRels ){
612
			if (taxRel.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN()) && taxRel.getToTaxon().equals(oldParent)){
613
				this.removeTaxonRelation(taxRel);
614
			}
615
		}
616
		//add new parent
617
		if (newParent != null){
618
			addTaxonRelation(newParent, TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN(),citation,microcitation);
619
		}
620
	}
621

    
622
	/** 
623
	 * Returns the set of taxa which have <i>this</i> taxon as next higher taxon
624
	 * (parent) within the taxonomic tree. Each taxon can have several child
625
	 * taxa. The child taxon and the parent taxon play the source respectively
626
	 * the target role in one {@link TaxonRelationship taxon relationship} with
627
	 * {@link TaxonRelationshipType taxon relationship type} "taxonomically included in".
628
	 * The {@link name.Rank rank} of the taxon name used as a parent taxon must be higher
629
	 * than the rank of the taxon name used as a child taxon.
630
	 * 
631
	 * @see  #getTaxonomicParent()
632
	 * @see  #addTaxonomicChild(Taxon, ReferenceBase, String)
633
	 * @see  #getTaxonomicChildrenCount()
634
	 * @see  #getRelationsToThisTaxon()
635
	 */
636
	@Transient
637
	public Set<Taxon> getTaxonomicChildren() {
638
		Set<Taxon> taxa = new HashSet<Taxon>();
639
		Set<TaxonRelationship> rels = this.getRelationsToThisTaxon();
640
		for (TaxonRelationship rel: rels){
641
			TaxonRelationshipType tt = rel.getType();
642
			TaxonRelationshipType incl = TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN(); 
643
			if (tt.equals(incl)){
644
				taxa.add(rel.getFromTaxon());
645
			}
646
		}
647
		return taxa;
648
	}
649
	
650
	/** 
651
	 * Returns the number of taxa which have <i>this</i> taxon as next higher taxon
652
	 * (parent) within the taxonomic tree and the number of which is stored in
653
	 * the TaxonomicChildrenCount attribute. Each taxon can have several child
654
	 * taxa. The child taxon and the parent taxon play the source respectively
655
	 * the target role in one {@link TaxonRelationship taxon relationship} with
656
	 * {@link TaxonRelationshipType taxon relationship type} "taxonomically included in".
657
	 * The {@link name.Rank rank} of the taxon name used as a parent taxon must be higher
658
	 * than the rank of the taxon name used as a child taxon.
659
	 * 
660
	 * @see  #getTaxonomicChildren()
661
	 * @see  #getRelationsToThisTaxon()
662
	 */
663
	public int getTaxonomicChildrenCount(){
664
		return taxonomicChildrenCount;
665
	}	
666
	
667
	
668
	/**
669
	 * @see  #getTaxonomicChildrenCount()
670
	 */
671
	private void setTaxonomicChildrenCount(int taxonomicChildrenCount) {
672
		this.taxonomicChildrenCount = taxonomicChildrenCount;
673
	}
674

    
675
	/**
676
	 * Returns the boolean value indicating whether <i>this</i> taxon has at least one
677
	 * taxonomic child taxon within the taxonomic tree (true) or not (false).
678
	 * 
679
	 * @see  #getTaxonomicChildrenCount()
680
	 * @see  #getTaxonomicChildren()
681
	 */
682
	@Transient
683
	public boolean hasTaxonomicChildren(){
684
		return this.taxonomicChildrenCount > 0;
685
	}
686

    
687
	@Transient
688
	private int computeTaxonomicChildrenCount(){
689
		int count = 0;
690
		for (TaxonRelationship rel: this.getRelationsToThisTaxon()){
691
			if (rel.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN())){
692
				count++;
693
			}
694
		}
695
		return count;
696
	}
697
	
698
	/**
699
	 * Returns the boolean value indicating whether <i>this</i> taxon has at least one
700
	 * {@link Synoynm synonym} (true) or not (false). If true the {@link #getSynonymRelations() set of synonym relationships}
701
	 * belonging to <i>this</i> ("accepted/correct") taxon is not empty .
702
	 * 
703
	 * @see  #getSynonymRelations()
704
	 * @see  #getSynonyms()
705
	 * @see  #getSynonymNames()
706
	 * @see  #removeSynonym(Synonym)
707
	 * @see  SynonymRelationship
708
	 */
709
	@Transient
710
	public boolean hasSynonyms(){
711
		return this.getSynonymRelations().size() > 0;
712
	}
713

    
714
	
715
	/**
716
	 * Returns the boolean value indicating whether <i>this</i> taxon is at least
717
	 * involved in one {@link #getTaxonRelations() taxon relationship} between
718
	 * two taxa (true), either as a source or as a target, or not (false).
719
	 * 
720
	 * @see  #getTaxonRelations()
721
	 * @see  #getRelationsToThisTaxon()
722
	 * @see  #getRelationsFromThisTaxon()
723
	 * @see  #removeTaxonRelation(TaxonRelationship)
724
	 * @see  TaxonRelationship
725
	 */
726
	@Transient
727
	public boolean hasTaxonRelationships(){
728
		return this.getTaxonRelations().size() > 0;
729
	}
730

    
731
	/*
732
	 * MISAPPLIED NAMES
733
	 */
734
	/** 
735
	 * Returns the set of taxa playing the source role in {@link TaxonRelationship taxon relationships}
736
	 * (with {@link TaxonRelationshipType taxon relationship type} "misapplied name for") where
737
	 * <i>this</i> taxon plays the target role. A misapplied name is a taxon the
738
	 * {@link name.TaxonNameBase taxon name} of which has been erroneously used
739
	 * by the {@link TaxonBase#getSec() taxon reference} to denominate the same real taxon
740
	 * as the one meant by <i>this</i> ("accepted/correct") taxon. 
741
	 * 
742
	 * @see  #getTaxonRelations()
743
	 * @see  #getRelationsToThisTaxon()
744
	 * @see  #addMisappliedName(Taxon, ReferenceBase, String)
745
	 */
746
	@Transient
747
	public Set<Taxon> getMisappliedNames(){
748
		Set<Taxon> taxa = new HashSet<Taxon>();
749
		Set<TaxonRelationship> rels = this.getRelationsToThisTaxon();
750
		for (TaxonRelationship rel: rels){
751
			TaxonRelationshipType tt = rel.getType();
752
			TaxonRelationshipType incl = TaxonRelationshipType.MISAPPLIEDNAMEFOR(); 
753
			if (tt.equals(incl)){
754
				taxa.add(rel.getFromTaxon());
755
			}
756
		}
757
		return taxa;
758
	}
759
		
760
	
761
	/*
762
	 * DEALING WITH SYNONYMS
763
	 */
764
	/** 
765
	 * Returns the set of all {@link Synonym synonyms} of <i>this</i> ("accepted/correct") taxon.
766
	 * Each synonym is the source and <i>this</i> taxon is the target of a {@link SynonymRelationship synonym relationship}
767
	 * belonging to the {@link #getSynonymRelations() set of synonym relationships} assigned to <i>this</i> taxon.
768
	 * For a particular synonym and for a particular ("accepted/correct") taxon
769
	 * there can be several synonym relationships (if two or more
770
	 * {@link SynonymRelationshipType synonym relationship types} - for instance
771
	 * "pro parte synonym of" and "is homotypic synonym of" - must be combined). 
772
	 *  
773
	 * @see    #getSynonymsSortedByType()
774
	 * @see    #getSynonymNames()
775
	 * @see    #getSynonymRelations()
776
	 * @see    #addSynonym(Synonym, SynonymRelationshipType)
777
	 * @see    #addSynonym(Synonym, SynonymRelationshipType, ReferenceBase, String)
778
	 * @see    #removeSynonymRelation(SynonymRelationship)
779
	 * @see    #removeSynonym(Synonym)
780
	 */
781
	@Transient
782
	public Set<Synonym> getSynonyms(){
783
		Set<Synonym> syns = new HashSet<Synonym>();
784
		for (SynonymRelationship rel: this.getSynonymRelations()){
785
			syns.add(rel.getSynonym());
786
		}
787
		return syns;
788
	}
789
	/** 
790
	 * Returns the set of all {@link Synonym synonyms} of <i>this</i> ("accepted/correct") taxon
791
	 * sorted by the different {@link SynonymRelationshipType categories of synonym relationships}.
792
	 * Each synonym is the source and <i>this</i> taxon is the target of a {@link SynonymRelationship synonym relationship}
793
	 * belonging to the {@link #getSynonymRelations() set of synonym relationships} assigned to <i>this</i> taxon.
794
	 *  
795
	 * @see    #getSynonyms()
796
	 * @see    #getSynonymNames()
797
	 * @see    #getSynonymRelations()
798
	 * @see    #addSynonym(Synonym, SynonymRelationshipType)
799
	 * @see    #addSynonym(Synonym, SynonymRelationshipType, ReferenceBase, String)
800
	 * @see    #removeSynonymRelation(SynonymRelationship)
801
	 * @see    #removeSynonym(Synonym)
802
	 */
803
	@Transient
804
	public Set<Synonym> getSynonymsSortedByType(){
805
		// FIXME: need to sort synonyms according to type!!!
806
		logger.warn("getSynonymsSortedByType() not yet implemented");
807
		return getSynonyms();
808
	}
809
	/** 
810
	 * Returns the set of all {@link name.TaxonNameBase taxon names} used as {@link Synonym synonyms}
811
	 * of <i>this</i> ("accepted/correct") taxon. Each synonym is the source and
812
	 * <i>this</i> taxon is the target of a {@link SynonymRelationship synonym relationship} belonging
813
	 * to the {@link #getSynonymRelations() set of synonym relationships} assigned to <i>this</i> taxon.
814
	 *  
815
	 * @see    #getSynonyms()
816
	 * @see    #getSynonymsSortedByType()
817
	 * @see    #getSynonymRelations()
818
	 * @see    #addSynonymName(TaxonNameBase, SynonymRelationshipType)
819
	 * @see    #addSynonym(Synonym, SynonymRelationshipType, ReferenceBase, String)
820
	 * @see    #removeSynonymRelation(SynonymRelationship)
821
	 * @see    #removeSynonym(Synonym)
822
	 */
823
	@Transient
824
	public Set<TaxonNameBase> getSynonymNames(){
825
		Set<TaxonNameBase> names = new HashSet<TaxonNameBase>();
826
		for (SynonymRelationship rel: this.getSynonymRelations()){
827
			names.add(rel.getSynonym().getName());
828
		}
829
		return names;
830
	}
831
	/**
832
	 * Creates a new {@link SynonymRelationship synonym relationship} (with the given {@link Synonym synonym}
833
	 * and with the given {@link SynonymRelationshipType synonym relationship type}), returns it and adds it
834
	 * to the set of {@link #getSynonymRelations() synonym relationships} assigned to <i>this</i> taxon.
835
	 * The new synonym relationship will also be added to the set of
836
	 * {@link Synonym#getSynonymRelations() synonym relationships} belonging to the synonym
837
	 * involved in this synonym relationship.<BR>
838
	 * The returned synonym relationship allows to add further information to it.
839
	 * 
840
	 * @param synonym		the synonym involved in the relationship to be created
841
	 * 						and added to <i>this</i> taxon's synonym relationships set
842
	 * @param synonymType	the synonym relationship category of the synonym
843
	 * 						relationship to be added
844
	 * @return 				the created synonym relationship
845
	 * @see    	   			#addSynonymRelation(SynonymRelationship)
846
	 * @see    	   			#addSynonym(Synonym, SynonymRelationshipType, ReferenceBase, String)
847
	 * @see    	   			#addSynonymName(TaxonNameBase, SynonymRelationshipType)
848
	 * @see    	   			#addSynonymName(TaxonNameBase, SynonymRelationshipType, ReferenceBase, String)
849
	 * @see    	   			#addHomotypicSynonym(Synonym, ReferenceBase, String)
850
	 * @see    	   			#addHomotypicSynonymName(TaxonNameBase, ReferenceBase, String)
851
	 * @see    	   			#addHeterotypicSynonymName(TaxonNameBase)
852
	 * @see    	   			#addHeterotypicSynonymName(TaxonNameBase, HomotypicalGroup, ReferenceBase, String)
853
	 * @see    	   			#getSynonymRelations()
854
	 * @see    				#removeSynonym(Synonym)
855
	 * @see    	   			Synonym#getSynonymRelations()
856
	 */
857
	public SynonymRelationship addSynonym(Synonym synonym, SynonymRelationshipType synonymType){
858
		return addSynonym(synonym, synonymType, null, null);
859
	}
860
	/**
861
	 * Creates a new {@link SynonymRelationship synonym relationship} (with the given {@link Synonym synonym},
862
	 * with the given {@link SynonymRelationshipType synonym relationship type} and with the
863
	 * {@link reference.ReferenceBase reference source} on which the relationship assertion is based),
864
	 * returns it and adds it to the set of {@link #getSynonymRelations() synonym relationships}
865
	 * assigned to <i>this</i> taxon. The new synonym relationship will also be
866
	 * added to the set of {@link Synonym#getSynonymRelations() synonym relationships} belonging to the synonym
867
	 * involved in this synonym relationship.<BR>
868
	 * The returned synonym relationship allows to add further information to it.
869
	 * 
870
	 * @param synonym		the synonym involved in the relationship to be created
871
	 * 						and added to <i>this</i> taxon's synonym relationships set
872
	 * @param synonymType	the synonym relationship category of the synonym
873
	 * 						relationship to be added
874
	 * @param citation		the reference source for the new synonym relationship
875
	 * @param microcitation	the string with the details describing the exact localisation within the reference
876
	 * @return 				the created synonym relationship
877
	 * @see    	   			#addSynonymRelation(SynonymRelationship)
878
	 * @see    	   			#addSynonym(Synonym, SynonymRelationshipType, ReferenceBase, String)
879
	 * @see    	   			#addSynonymName(TaxonNameBase, SynonymRelationshipType)
880
	 * @see    	   			#addSynonymName(TaxonNameBase, SynonymRelationshipType, ReferenceBase, String)
881
	 * @see    	   			#addHomotypicSynonym(Synonym, ReferenceBase, String)
882
	 * @see    	   			#addHomotypicSynonymName(TaxonNameBase, ReferenceBase, String)
883
	 * @see    	   			#addHeterotypicSynonymName(TaxonNameBase)
884
	 * @see    	   			#addHeterotypicSynonymName(TaxonNameBase, HomotypicalGroup, ReferenceBase, String)
885
	 * @see    	   			#getSynonymRelations()
886
	 * @see    				#removeSynonym(Synonym)
887
	 * @see    	   			Synonym#getSynonymRelations()
888
	 */
889
	public SynonymRelationship addSynonym(Synonym synonym, SynonymRelationshipType synonymType, ReferenceBase citation, String citationMicroReference){
890
		SynonymRelationship synonymRelationship = new SynonymRelationship(synonym, this, synonymType, citation, citationMicroReference);
891
		return synonymRelationship;
892
	}
893
	
894
	/**
895
	 * Creates a new {@link Synonym synonym} (with the given {@link name.TaxonNameBase taxon name}),
896
	 * a new {@link SynonymRelationship synonym relationship} (with the new synonym and with the given 
897
	 * {@link SynonymRelationshipType synonym relationship type}), returns the relationship and adds it
898
	 * to the set of {@link #getSynonymRelations() synonym relationships} assigned to <i>this</i> taxon.
899
	 * The new synonym will have the same {@link TaxonBase#getSec() concept reference}
900
	 * as <i>this</i> taxon. The new synonym relationship will also be added to 
901
	 * the set of {@link Synonym#getSynonymRelations() synonym relationships} belonging
902
	 * to the created synonym.<BR>
903
	 * The returned synonym relationship allows to add further information to it.
904
	 * 
905
	 * @param synonymName	the taxon name to be used as a synonym to be added
906
	 * 						to <i>this</i> taxon's set of synonyms
907
	 * @param synonymType	the synonym relationship category of the synonym
908
	 * 						relationship to be added
909
	 * @return 				the created synonym relationship
910
	 * @see    	   			#addSynonymName(TaxonNameBase, SynonymRelationshipType, ReferenceBase, String)
911
	 * @see    	   			#addSynonym(Synonym, SynonymRelationshipType)
912
	 * @see    	   			#addSynonym(Synonym, SynonymRelationshipType, ReferenceBase, String)
913
	 * @see    	   			#addSynonymRelation(SynonymRelationship)
914
	 * @see    	   			#addHomotypicSynonym(Synonym, ReferenceBase, String)
915
	 * @see    	   			#addHomotypicSynonymName(TaxonNameBase, ReferenceBase, String)
916
	 * @see    	   			#addHeterotypicSynonymName(TaxonNameBase)
917
	 * @see    	   			#addHeterotypicSynonymName(TaxonNameBase, HomotypicalGroup, ReferenceBase, String)
918
	 * @see    	   			#getSynonymRelations()
919
	 * @see    				#removeSynonym(Synonym)
920
	 * @see    	   			Synonym#getSynonymRelations()
921
	 */
922
	public SynonymRelationship addSynonymName(TaxonNameBase synonymName, SynonymRelationshipType synonymType){
923
		return addSynonymName(synonymName, synonymType, null, null);
924
	}
925
	/**
926
	 * Creates a new {@link Synonym synonym} (with the given {@link name.TaxonNameBase taxon name}),
927
	 * a new {@link SynonymRelationship synonym relationship} (with the new synonym, with the given 
928
	 * {@link SynonymRelationshipType synonym relationship type} and with the {@link reference.ReferenceBase reference source}
929
	 * on which the relationship assertion is based), returns the relationship
930
	 * and adds it to the set of {@link #getSynonymRelations() synonym relationships} assigned
931
	 * to <i>this</i> taxon. The new synonym will have the same {@link TaxonBase#getSec() concept reference}
932
	 * as <i>this</i> taxon. The new synonym relationship will also be added to 
933
	 * the set of {@link Synonym#getSynonymRelations() synonym relationships} belonging
934
	 * to the created synonym.<BR>
935
	 * The returned synonym relationship allows to add further information to it.
936
	 * 
937
	 * @param synonymName	the taxon name to be used as a synonym to be added
938
	 * 						to <i>this</i> taxon's set of synonyms
939
	 * @param synonymType	the synonym relationship category of the synonym
940
	 * 						relationship to be added
941
	 * @param citation		the reference source for the new synonym relationship
942
	 * @param microcitation	the string with the details describing the exact localisation within the reference
943
	 * @return 				the created synonym relationship
944
	 * @see    	   			#addSynonymName(TaxonNameBase, SynonymRelationshipType, ReferenceBase, String)
945
	 * @see    	   			#addSynonym(Synonym, SynonymRelationshipType)
946
	 * @see    	   			#addSynonym(Synonym, SynonymRelationshipType, ReferenceBase, String)
947
	 * @see    	   			#addSynonymRelation(SynonymRelationship)
948
	 * @see    	   			#addHomotypicSynonym(Synonym, ReferenceBase, String)
949
	 * @see    	   			#addHomotypicSynonymName(TaxonNameBase, ReferenceBase, String)
950
	 * @see    	   			#addHeterotypicSynonymName(TaxonNameBase)
951
	 * @see    	   			#addHeterotypicSynonymName(TaxonNameBase, HomotypicalGroup, ReferenceBase, String)
952
	 * @see    	   			#getSynonymRelations()
953
	 * @see    				#removeSynonym(Synonym)
954
	 * @see    	   			Synonym#getSynonymRelations()
955
	 */
956
	public SynonymRelationship addSynonymName(TaxonNameBase synonymName, SynonymRelationshipType synonymType, ReferenceBase citation, String citationMicroReference){
957
		Synonym synonym = Synonym.NewInstance(synonymName, this.getSec());
958
		return addSynonym(synonym, synonymType, citation, citationMicroReference);
959
	}
960
	
961

    
962
	/**
963
	 * Creates a new {@link Synonym synonym} (with the given {@link name.TaxonNameBase taxon name}),
964
	 * a new {@link SynonymRelationship synonym relationship} (with the new synonym and with the 
965
	 * {@link SynonymRelationshipType#HETEROTYPIC_SYNONYM_OF() "is heterotypic synonym of" relationship type}),
966
	 * returns the relationship and adds it to the set of
967
	 * {@link #getSynonymRelations() synonym relationships} assigned to <i>this</i> taxon.
968
	 * The new synonym will have the same {@link TaxonBase#getSec() concept reference}
969
	 * as <i>this</i> taxon. The new synonym relationship will also be added to 
970
	 * the set of {@link Synonym#getSynonymRelations() synonym relationships} belonging
971
	 * to the created synonym.<BR>
972
	 * The returned synonym relationship allows to add further information to it.
973
	 * 
974
	 * @param synonymName	the taxon name to be used as an heterotypic synonym
975
	 * 						to be added to <i>this</i> taxon's set of synonyms
976
	 * @return 				the created synonym relationship
977
	 * @see    	   			#addHeterotypicSynonymName(TaxonNameBase, HomotypicalGroup, ReferenceBase, String)
978
	 * @see    	   			#addSynonymName(TaxonNameBase, SynonymRelationshipType)
979
	 * @see    	   			#addSynonymName(TaxonNameBase, SynonymRelationshipType, ReferenceBase, String)
980
	 * @see    	   			#addSynonym(Synonym, SynonymRelationshipType)
981
	 * @see    	   			#addSynonym(Synonym, SynonymRelationshipType, ReferenceBase, String)
982
	 * @see    	   			#addSynonymRelation(SynonymRelationship)
983
	 * @see    	   			#addHomotypicSynonym(Synonym, ReferenceBase, String)
984
	 * @see    	   			#addHomotypicSynonymName(TaxonNameBase, ReferenceBase, String)
985
	 * @see    	   			#getSynonymRelations()
986
	 * @see    				#removeSynonym(Synonym)
987
	 * @see    	   			Synonym#getSynonymRelations()
988
	 */
989
	public SynonymRelationship addHeterotypicSynonymName(TaxonNameBase synonymName){
990
		return addHeterotypicSynonymName(synonymName, null, null, null);
991
	}
992

    
993
	
994
	/**
995
	 * Creates a new {@link Synonym synonym} (with the given {@link name.TaxonNameBase taxon name}),
996
	 * a new {@link SynonymRelationship synonym relationship} (with the new synonym, with the 
997
	 * {@link SynonymRelationshipType#HETEROTYPIC_SYNONYM_OF() "is heterotypic synonym of" relationship type}
998
	 * and with the {@link reference.ReferenceBase reference source}
999
	 * on which the relationship assertion is based), returns the relationship
1000
	 * and adds it to the set of {@link #getSynonymRelations() synonym relationships} assigned
1001
	 * to <i>this</i> taxon. The new synonym will have the same {@link TaxonBase#getSec() concept reference}
1002
	 * as <i>this</i> taxon. Furthermore the new synonym relationship will be 
1003
	 * added to the set of {@link Synonym#getSynonymRelations() synonym relationships} belonging
1004
	 * to the created synonym and the taxon name used as synonym will be added
1005
	 * to the given {@link name.HomotypicalGroup homotypical group}.<BR>
1006
	 * The returned synonym relationship allows to add further information to it.
1007
	 * 
1008
	 * @param synonymName		the taxon name to be used as an heterotypic synonym
1009
	 * 							to be added to <i>this</i> taxon's set of synonyms
1010
	 * @param homotypicalGroup	the homotypical group to which the taxon name
1011
	 * 							of the synonym will be added
1012
	 * @param citation			the reference source for the new synonym relationship
1013
	 * @param microcitation		the string with the details describing the exact localisation
1014
	 * 							within the reference
1015
	 * @return 					the created synonym relationship
1016
	 * @see    	   				#addHeterotypicSynonymName(TaxonNameBase)
1017
	 * @see    	   				#addSynonymName(TaxonNameBase, SynonymRelationshipType, ReferenceBase, String)
1018
	 * @see    	   				#addSynonymName(TaxonNameBase, SynonymRelationshipType)
1019
	 * @see    	   				#addSynonym(Synonym, SynonymRelationshipType)
1020
	 * @see    	   				#addSynonym(Synonym, SynonymRelationshipType, ReferenceBase, String)
1021
	 * @see    	   				#addSynonymRelation(SynonymRelationship)
1022
	 * @see    	   				#addHomotypicSynonym(Synonym, ReferenceBase, String)
1023
	 * @see    	   				#addHomotypicSynonymName(TaxonNameBase, ReferenceBase, String)
1024
	 * @see    	   				#getSynonymRelations()
1025
	 * @see    					#removeSynonym(Synonym)
1026
	 * @see    	   				Synonym#getSynonymRelations()
1027
	 */
1028
	public SynonymRelationship addHeterotypicSynonymName(TaxonNameBase synonymName, HomotypicalGroup homotypicalGroup, ReferenceBase citation, String microCitation){
1029
		Synonym synonym = Synonym.NewInstance(synonymName, this.getSec());
1030
		if (homotypicalGroup != null){
1031
			homotypicalGroup.addTypifiedName(synonymName);
1032
		}
1033
		return addSynonym(synonym, SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF(), citation, microCitation);
1034
	}
1035
	
1036
	/**
1037
	 * Creates a new {@link Synonym synonym} (with the given {@link name.TaxonNameBase taxon name}),
1038
	 * a new {@link SynonymRelationship synonym relationship} (with the new synonym, with the 
1039
	 * {@link SynonymRelationshipType#HOMOTYPIC_SYNONYM_OF() "is homotypic synonym of" relationship type})
1040
	 * and with the {@link reference.ReferenceBase reference source}
1041
	 * on which the relationship assertion is based), returns the relationship
1042
	 * and adds it to the set of {@link #getSynonymRelations() synonym relationships} assigned
1043
	 * to <i>this</i> taxon. The new synonym will have the same {@link TaxonBase#getSec() concept reference}
1044
	 * as <i>this</i> taxon. Furthermore the new synonym relationship will be 
1045
	 * added to the set of {@link Synonym#getSynonymRelations() synonym relationships} belonging
1046
	 * to the created synonym and the taxon name used as synonym will be added
1047
	 * to the same {@link name.HomotypicalGroup homotypical group} to which the taxon name
1048
	 * of <i>this</i> taxon belongs.<BR>
1049
	 * The returned synonym relationship allows to add further information to it.
1050
	 * 
1051
	 * @param synonymName	the taxon name to be used as an homotypic synonym
1052
	 * 						to be added to <i>this</i> taxon's set of synonyms
1053
	 * @param citation		the reference source for the new synonym relationship
1054
	 * @param microcitation	the string with the details describing the exact localisation
1055
	 * 						within the reference
1056
	 * @return 				the created synonym relationship
1057
	 * @see    	   			#addHomotypicSynonym(Synonym, ReferenceBase, String)
1058
	 * @see    	   			#addSynonymName(TaxonNameBase, SynonymRelationshipType, ReferenceBase, String)
1059
	 * @see    	   			#addSynonymName(TaxonNameBase, SynonymRelationshipType)
1060
	 * @see    	   			#addSynonym(Synonym, SynonymRelationshipType)
1061
	 * @see    	   			#addSynonym(Synonym, SynonymRelationshipType, ReferenceBase, String)
1062
	 * @see    	   			#addSynonymRelation(SynonymRelationship)
1063
	 * @see    	   			#addHeterotypicSynonymName(TaxonNameBase)
1064
	 * @see    	   			#addHeterotypicSynonymName(TaxonNameBase, HomotypicalGroup, ReferenceBase, String)
1065
	 * @see    	   			#getSynonymRelations()
1066
	 * @see    				#removeSynonym(Synonym)
1067
	 * @see    	   			Synonym#getSynonymRelations()
1068
	 */
1069
	public SynonymRelationship addHomotypicSynonymName(TaxonNameBase synonymName, ReferenceBase citation, String microCitation){
1070
		Synonym synonym = Synonym.NewInstance(synonymName, this.getSec());
1071
		return addHomotypicSynonym(synonym, citation, microCitation);
1072
	}
1073
	
1074
	/**
1075
	 * Creates a new {@link SynonymRelationship synonym relationship} (with the given {@link Synonym synonym},
1076
	 * with the {@link SynonymRelationshipType#HOMOTYPIC_SYNONYM_OF() "is homotypic synonym of" relationship type}
1077
	 * and with the {@link reference.ReferenceBase reference source} on which the relationship
1078
	 * assertion is based), returns it and adds it to the set of
1079
	 * {@link #getSynonymRelations() synonym relationships} assigned to <i>this</i> taxon.
1080
	 * Furthermore the new synonym relationship will be added to the set of
1081
	 * {@link Synonym#getSynonymRelations() synonym relationships} belonging to the synonym
1082
	 * involved in this synonym relationship and the {@link name.TaxonNameBase taxon name}
1083
	 * used as synonym will be added to the same {@link name.HomotypicalGroup homotypical group}
1084
	 * to which the taxon name of <i>this</i> taxon belongs.<BR>
1085
	 * The returned synonym relationship allows to add further information to it.
1086
	 * 
1087
	 * @param synonym		the synonym involved in the "is homotypic synonym of" relationship to be created
1088
	 * 						and added to <i>this</i> taxon's synonym relationships set
1089
	 * @param citation		the reference source for the new synonym relationship
1090
	 * @param microcitation	the string with the details describing the exact localisation within the reference
1091
	 * @return 				the created synonym relationship
1092
	 * @see    	   			#addHomotypicSynonymName(TaxonNameBase, ReferenceBase, String)
1093
	 * @see    	   			#addSynonym(Synonym, SynonymRelationshipType)
1094
	 * @see    	   			#addSynonym(Synonym, SynonymRelationshipType, ReferenceBase, String)
1095
	 * @see    	   			#addSynonymName(TaxonNameBase, SynonymRelationshipType, ReferenceBase, String)
1096
	 * @see    	   			#addSynonymName(TaxonNameBase, SynonymRelationshipType)
1097
	 * @see    	   			#addSynonymRelation(SynonymRelationship)
1098
	 * @see    	   			#addHeterotypicSynonymName(TaxonNameBase)
1099
	 * @see    	   			#addHeterotypicSynonymName(TaxonNameBase, HomotypicalGroup, ReferenceBase, String)
1100
	 * @see    	   			#getSynonymRelations()
1101
	 * @see    				#removeSynonym(Synonym)
1102
	 * @see    	   			Synonym#getSynonymRelations()
1103
	 */
1104
	public SynonymRelationship addHomotypicSynonym(Synonym synonym, ReferenceBase citation, String microCitation){
1105
		if (this.getName() != null){
1106
			this.getName().getHomotypicalGroup().addTypifiedName(synonym.getName());
1107
		}
1108
		SynonymRelationship synRel = addSynonym(synonym, SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF(), citation, microCitation);
1109
		return synRel;
1110
	}
1111
	
1112
	/** 
1113
	 * Removes the element(s) from the set of {@link SynonymRelationship synonym relationships}
1114
	 * assigned to <i>this</i> ("accepted/correct") taxon in which the given synonym is involved.
1115
	 * Due to bidirectionality the same synonym relationships will also be
1116
	 * removed from the set of synonym relationships assigned to the
1117
	 * {@link Synonym#getSynonymRelations() synonym} involved in the relationship. Furthermore the content of
1118
	 * the {@link SynonymRelationship#getAcceptedTaxon() accepted taxon attribute} and of the
1119
	 * {@link SynonymRelationship#getSynonym() synonym attribute} within the synonym relationships
1120
	 * themselves will be set to "null".
1121
	 *
1122
	 * @param  synonym  the synonym involved in the synonym relationship which should be deleted
1123
	 * @see     		#getSynonymRelations()
1124
	 * @see     		#addSynonym(Synonym, SynonymRelationshipType)
1125
	 * @see     		#addSynonym(Synonym, SynonymRelationshipType, ReferenceBase, String)
1126
	 * @see 			#removeSynonymRelation(SynonymRelationship)
1127
	 */
1128
	public void removeSynonym(Synonym synonym){
1129
		Set<SynonymRelationship> synonymRelationships = new HashSet<SynonymRelationship>();
1130
		synonymRelationships.addAll(this.getSynonymRelations());
1131
		for(SynonymRelationship synonymRelationship : synonymRelationships){
1132
			if (synonymRelationship.getAcceptedTaxon().equals(this) && synonymRelationship.getSynonym().equals(synonym)){
1133
				this.removeSynonymRelation(synonymRelationship);
1134
			}
1135
		}
1136
	}
1137
	
1138
	
1139
	
1140
	/** 
1141
	 * Returns an {@link java.lang.Iterable#iterator() iterator} over the set of taxa which
1142
	 * are {@link #getTaxonomicChildren() taxonomic children} of <i>this</i> taxon.
1143
	 * 
1144
	 * @see #getTaxonomicChildren()
1145
	 * @see java.lang.Iterable#iterator()
1146
	 */
1147
	public Iterator<Taxon> iterator() {
1148
		return new TaxonIterator(this.getTaxonomicChildren());
1149
	}
1150
	/**
1151
	 * inner iterator class for the iterable interface
1152
	 * @author m.doering
1153
	 *
1154
	 */
1155
	private class TaxonIterator implements Iterator<Taxon> {
1156
		   private Taxon[] items;
1157
		   private int i= 0;
1158
		   public TaxonIterator(Set<Taxon> items) {
1159
		      // check for null being passed in etc.
1160
		      this.items= items.toArray(new Taxon[0]);
1161
		   }
1162
		   // interface implementation
1163
		   public boolean hasNext() { return i < items.length; }
1164
		   public Taxon next() { return items[i++]; }
1165
		   public void remove() { throw new UnsupportedOperationException(); }
1166
	}
1167
	
1168
	/**
1169
	 * Retrieves the ordered list (depending on the date of publication) of
1170
	 * homotypic {@link Synonym synonyms} (according to the same {@link reference.ReferenceBase reference}
1171
	 * as for <i>this</i> taxon) under the condition that the {@link name.TaxonNameBase taxon names}
1172
	 * of these synonyms and the taxon name of <i>this</i> taxon belong to the
1173
	 * same {@link name.HomotypicalGroup homotypical group}.
1174
	 * 
1175
	 * @return		the ordered list of homotypic synonyms
1176
	 * @see			#getHomotypicSynonymsByHomotypicRelationship()
1177
	 * @see			#getSynonyms()
1178
	 * @see			#getHomotypicSynonymyGroups()
1179
	 * @see			name.HomotypicalGroup
1180
	 * @see			name.HomotypicalGroup#getSynonymsInGroup(ReferenceBase)
1181
	 */
1182
	@Transient
1183
	public List<Synonym> getHomotypicSynonymsByHomotypicGroup(){
1184
		if (this.getHomotypicGroup() == null){
1185
			return null;
1186
		}else{
1187
			return this.getHomotypicGroup().getSynonymsInGroup(this.getSec());
1188
		}
1189
	}
1190
	
1191
	/**
1192
	 * Retrieves the ordered list (depending on the date of publication) of
1193
	 * homotypic {@link Synonym synonyms} (according to the same {@link reference.ReferenceBase reference}
1194
	 * as for <i>this</i> taxon) under the condition that these synonyms and
1195
	 * <i>this</i> taxon are involved in {@link SynonymRelationship synonym relationships} with an
1196
	 * "is homotypic synonym of" {@link SynonymRelationshipType#HOMOTYPIC_SYNONYM_OF() synonym relationship type}.
1197
	 * 
1198
	 * @return		the ordered list of homotypic synonyms
1199
	 * @see			#getHomotypicSynonymsByHomotypicGroup()
1200
	 * @see			#getSynonyms()
1201
	 * @see			#getHomotypicSynonymyGroups()
1202
	 * @see			SynonymRelationshipType
1203
	 */
1204
	@Transient
1205
	public List<Synonym> getHomotypicSynonymsByHomotypicRelationship(){
1206
		Set<SynonymRelationship> synonymRelations = this.getSynonymRelations(); 
1207
		List<Synonym> result = new ArrayList<Synonym>();
1208
		for(SynonymRelationship synonymRelation : synonymRelations) {
1209
    		if(synonymRelation.getType().equals(SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF())){
1210
				result.add(synonymRelation.getSynonym());
1211
    		}
1212
		}
1213
		return result;
1214
	}
1215
	
1216
	/**
1217
	 * Returns the ordered list of all {@link name.HomotypicalGroup homotypical groups} {@link Synonym synonyms} of
1218
	 * <i>this</i> taxon belongs to. {@link name.TaxonNameBase Taxon names} of homotypic synonyms
1219
	 * belong to the same homotypical group as the taxon name of <i>this</i>
1220
	 * taxon. Taxon names of heterotypic synonyms belong to at least one other
1221
	 * homotypical group. <BR>
1222
	 * The list returned is ordered according to the date of publication of the
1223
	 * first published name within each homotypical group.
1224
	 * 
1225
	 * @see			#getHeterotypicSynonymyGroups()
1226
	 * @see			#getSynonyms()
1227
	 * @see			name.HomotypicalGroup
1228
	 */
1229
	@Transient
1230
	public List<HomotypicalGroup> getHomotypicSynonymyGroups(){
1231
		List<HomotypicalGroup> result = new ArrayList<HomotypicalGroup>();
1232
		result.add(this.getHomotypicGroup());
1233
		for (TaxonNameBase taxonNameBase :this.getSynonymNames()){
1234
			if (!result.contains(taxonNameBase.getHomotypicalGroup())){
1235
				result.add(taxonNameBase.getHomotypicalGroup());
1236
			}
1237
		}
1238
		// TODO: sort list according to date of first published name within each group
1239
		return result;
1240
	}
1241
	
1242
	/**
1243
	 * Returns the List of all homotypic groups heterotypic synonyms of this taxon belongs too.
1244
	 * This does not include the homotypic group of <i>this</i> taxon.
1245
	 * @return
1246
	 */
1247
	/**
1248
	 * Returns the ordered list of all {@link name.HomotypicalGroup homotypical groups} heterotypic
1249
	 * {@link Synonym synonyms} of <i>this</i> taxon belongs to.
1250
	 * {@link name.TaxonNameBase Taxon names} of heterotypic synonyms belong to at least
1251
	 * one homotypical group which cannot be the homotypical group to which the
1252
	 * taxon name of <i>this</i> taxon belongs. This method returns the same
1253
	 * list as the {@link #getHomotypicSynonymyGroups() getHomotypicSynonymyGroups} method
1254
	 * but the homotypical group to which the taxon name of <i>this</i> taxon
1255
	 * belongs.<BR>
1256
	 * The list returned is ordered according to the date of publication of the
1257
	 * first published name within each homotypical group.
1258
	 * 
1259
	 * @see			#getHeterotypicSynonymyGroups()
1260
	 * @see			#getSynonyms()
1261
	 * @see			SynonymRelationshipType#HETEROTYPIC_SYNONYM_OF()
1262
	 * @see			name.HomotypicalGroup
1263
	 */
1264
	@Transient
1265
	public List<HomotypicalGroup> getHeterotypicSynonymyGroups(){
1266
		List<HomotypicalGroup> list = getHomotypicSynonymyGroups();
1267
		list.remove(this.getHomotypicGroup());
1268
		//sort
1269
		Map<Synonym, HomotypicalGroup> map = new HashMap<Synonym, HomotypicalGroup>();
1270
		for (HomotypicalGroup homoGroup: list){
1271
			List<Synonym> synonymList = homoGroup.getSynonymsInGroup(getSec());
1272
			if (synonymList.size() > 0){
1273
				map.put(synonymList.get(0), homoGroup);
1274
			}
1275
		}
1276
		List<Synonym> keyList = new ArrayList<Synonym>();
1277
		keyList.addAll(map.keySet());
1278
		Collections.sort(keyList, new TaxonComparator());
1279
		
1280
		List<HomotypicalGroup> result = new ArrayList<HomotypicalGroup>();
1281
		for(Synonym synonym: keyList){
1282
			result.add(map.get(synonym));
1283
		}
1284
		//sort end
1285
		return result;
1286
	}	
1287

    
1288
}
(4-4/9)