Project

General

Profile

Download (47.9 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.name;
11

    
12
import java.lang.reflect.Method;
13
import java.util.HashSet;
14
import java.util.List;
15
import java.util.Set;
16

    
17
import javax.persistence.Column;
18
import javax.persistence.Entity;
19
import javax.persistence.FetchType;
20
import javax.persistence.Inheritance;
21
import javax.persistence.InheritanceType;
22
import javax.persistence.ManyToMany;
23
import javax.persistence.ManyToOne;
24
import javax.persistence.OneToMany;
25
import javax.persistence.Transient;
26
import javax.xml.bind.annotation.XmlAccessType;
27
import javax.xml.bind.annotation.XmlAccessorType;
28
import javax.xml.bind.annotation.XmlAttribute;
29
import javax.xml.bind.annotation.XmlElement;
30
import javax.xml.bind.annotation.XmlElementWrapper;
31
import javax.xml.bind.annotation.XmlIDREF;
32
import javax.xml.bind.annotation.XmlRootElement;
33
import javax.xml.bind.annotation.XmlSchemaType;
34
import javax.xml.bind.annotation.XmlType;
35

    
36
import org.apache.log4j.Logger;
37
import org.hibernate.annotations.Cascade;
38
import org.hibernate.annotations.CascadeType;
39
import org.hibernate.annotations.Index;
40
import org.hibernate.annotations.Table;
41
import org.hibernate.envers.Audited;
42
import org.hibernate.search.annotations.Field;
43
import org.springframework.util.ReflectionUtils;
44

    
45
import eu.etaxonomy.cdm.model.common.IParsable;
46
import eu.etaxonomy.cdm.model.common.IReferencedEntity;
47
import eu.etaxonomy.cdm.model.common.IRelated;
48
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
49
import eu.etaxonomy.cdm.model.common.RelationshipBase;
50
import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
51
import eu.etaxonomy.cdm.model.occurrence.Specimen;
52
import eu.etaxonomy.cdm.model.reference.INomenclaturalReference;
53
import eu.etaxonomy.cdm.model.reference.ReferenceBase;
54
import eu.etaxonomy.cdm.model.reference.StrictReferenceBase;
55
import eu.etaxonomy.cdm.model.taxon.Synonym;
56
import eu.etaxonomy.cdm.model.taxon.Taxon;
57
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
58
import eu.etaxonomy.cdm.strategy.cache.name.INameCacheStrategy;
59

    
60
/**
61
 * The upmost (abstract) class for scientific taxon names regardless of any
62
 * particular {@link NomenclaturalCode nomenclature code}. The scientific taxon name does not depend
63
 * on the use made of it in a publication or a treatment
64
 * ({@link eu.etaxonomy.cdm.model.taxon.TaxonBase taxon concept respectively potential taxon})
65
 * as an {@link eu.etaxonomy.cdm.model.taxon.Taxon "accepted" respectively "correct" (taxon) name}
66
 * or as a {@link eu.etaxonomy.cdm.model.taxon.Synonym synonym}.
67
 * <P>
68
 * This class corresponds partially to: <ul>
69
 * <li> TaxonName according to the TDWG ontology
70
 * <li> ScientificName and CanonicalName according to the TCS
71
 * <li> ScientificName according to the ABCD schema
72
 * </ul>
73
 * 
74
 * @author m.doering
75
 * @version 1.0
76
 * @created 08-Nov-2007 13:06:57
77
 */
78
@XmlAccessorType(XmlAccessType.FIELD)
79
@XmlType(name = "TaxonNameBase", propOrder = {
80
    "appendedPhrase",
81
    "nomenclaturalMicroReference",
82
    "nomenclaturalReference",
83
    "rank",
84
    "fullTitleCache",
85
    "protectedFullTitleCache",
86
    "homotypicalGroup",
87
    "typeDesignations",
88
    "relationsFromThisName",
89
    "relationsToThisName",
90
    "status",
91
    "descriptions",
92
    "taxonBases"
93
})
94
@XmlRootElement(name = "TaxonNameBase")
95
@Entity
96
@Audited
97
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
98
@Table(appliesTo="TaxonNameBase", indexes = { @Index(name = "taxonNameBaseTitleCacheIndex", columnNames = { "titleCache" }) })
99
public abstract class TaxonNameBase<T extends TaxonNameBase<?,?>, S extends INameCacheStrategy> extends IdentifiableEntity<S> implements IReferencedEntity, IParsable, IRelated {
100

    
101
	private static final long serialVersionUID = -4530368639601532116L;
102
	private static final Logger logger = Logger.getLogger(TaxonNameBase.class);
103

    
104
	@XmlElement(name = "FullTitleCache")
105
	@Column(length=330, name="fullTitleCache")
106
	private String fullTitleCache;
107
	
108
	//if true titleCache will not be automatically generated/updated
109
	@XmlElement(name = "ProtectedFullTitleCache")
110
	private boolean protectedFullTitleCache;
111
	
112
    @XmlElementWrapper(name = "Descriptions")
113
    @XmlElement(name = "Description")
114
    @OneToMany(mappedBy="taxonName", fetch= FetchType.LAZY) 
115
	@Cascade({CascadeType.SAVE_UPDATE})
116
	private Set<TaxonNameDescription> descriptions = new HashSet<TaxonNameDescription>();
117
	
118
    @XmlElement(name = "AppendedPhrase")
119
    @Field(index= org.hibernate.search.annotations.Index.TOKENIZED)
120
	private String appendedPhrase;
121
	
122
    @XmlElement(name = "NomenclaturalMicroReference")
123
    @Field(index= org.hibernate.search.annotations.Index.TOKENIZED)
124
	private String nomenclaturalMicroReference;
125
	
126
    @XmlAttribute
127
	private boolean hasProblem = false;
128
	
129
    @XmlAttribute
130
    private int problemStarts = -1;
131
    
132
    @XmlAttribute
133
    private int problemEnds = -1;
134
    
135
    @XmlElementWrapper(name = "TypeDesignations")
136
    @XmlElement(name = "TypeDesignation")
137
    @XmlIDREF
138
    @XmlSchemaType(name = "IDREF")
139
    @ManyToMany(fetch = FetchType.LAZY)
140
	//TODO @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE_ORPHAN})
141
	@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
142
	private Set<TypeDesignationBase> typeDesignations = new HashSet<TypeDesignationBase>();
143

    
144
    @XmlElement(name = "HomotypicalGroup")
145
    @XmlIDREF
146
    @XmlSchemaType(name = "IDREF")
147
    @ManyToOne(fetch = FetchType.LAZY)
148
	@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
149
	private HomotypicalGroup homotypicalGroup;
150

    
151
    @XmlElementWrapper(name = "RelationsFromThisName")
152
    @XmlElement(name = "RelationFromThisName")
153
    @OneToMany(mappedBy="relatedFrom", fetch= FetchType.LAZY)
154
	//TODO @Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE_ORPHAN}) => DELETE_ORPHAN does not work ( org.hibernate.HibernateException: Don't change the reference to a collection with cascade="all-delete-orphan": eu.etaxonomy.cdm.model.name.TaxonNameBase.relationsFromThisName)
155
	@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
156
	private Set<NameRelationship> relationsFromThisName = new HashSet<NameRelationship>();
157

    
158
    @XmlElementWrapper(name = "RelationsToThisName")
159
    @XmlElement(name = "RelationToThisName")
160
    @XmlIDREF
161
    @XmlSchemaType(name = "IDREF")
162
    @OneToMany(mappedBy="relatedTo", fetch= FetchType.LAZY)
163
	@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
164
	private Set<NameRelationship> relationsToThisName = new HashSet<NameRelationship>();
165

    
166
    @XmlElementWrapper(name = "NomenclaturalStatuses")
167
    @XmlElement(name = "NomenclaturalStatus")
168
    @OneToMany(fetch= FetchType.LAZY)
169
	@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
170
	private Set<NomenclaturalStatus> status = new HashSet<NomenclaturalStatus>();
171

    
172
    @XmlElementWrapper(name = "TaxonBases")
173
    @XmlElement(name = "TaxonBase")
174
    @XmlIDREF
175
    @XmlSchemaType(name = "IDREF")
176
    @OneToMany(mappedBy="name", fetch= FetchType.LAZY)
177
	private Set<TaxonBase> taxonBases = new HashSet<TaxonBase>();
178
    
179
    @XmlElement(name = "Rank")
180
	@XmlIDREF
181
	@XmlSchemaType(name = "IDREF")
182
	@ManyToOne(fetch = FetchType.EAGER)
183
	private Rank rank;
184

    
185
	@XmlElement(name = "NomenclaturalReference")
186
    @XmlIDREF
187
    @XmlSchemaType(name = "IDREF")
188
    @ManyToOne(fetch = FetchType.LAZY)
189
	@Cascade({CascadeType.SAVE_UPDATE})
190
	private ReferenceBase nomenclaturalReference;
191
	
192
// ************* CONSTRUCTORS *************/	
193
	/** 
194
	 * Class constructor: creates a new empty taxon name.
195
	 * 
196
	 * @see #TaxonNameBase(Rank)
197
	 * @see #TaxonNameBase(HomotypicalGroup)
198
	 * @see #TaxonNameBase(Rank, HomotypicalGroup)
199
	 */
200
	public TaxonNameBase() {
201
		super();
202
	}
203
	/** 
204
	 * Class constructor: creates a new taxon name
205
	 * only containing its {@link Rank rank}.
206
	 * 
207
	 * @param  rank  the rank to be assigned to <i>this</i> taxon name
208
	 * @see    		 #TaxonNameBase()
209
	 * @see    		 #TaxonNameBase(HomotypicalGroup)
210
	 * @see    		 #TaxonNameBase(Rank, HomotypicalGroup)
211
	 */
212
	public TaxonNameBase(Rank rank) {
213
		this(rank, null);
214
	}
215
	/** 
216
	 * Class constructor: creates a new taxon name
217
	 * only containing its {@link HomotypicalGroup homotypical group}.
218
	 * The new taxon name will be also added to the set of taxon names
219
	 * belonging to this homotypical group.
220
	 * 
221
	 * @param  homotypicalGroup  the homotypical group to which <i>this</i> taxon name belongs
222
	 * @see    					 #TaxonNameBase()
223
	 * @see    					 #TaxonNameBase(Rank)
224
	 * @see    					 #TaxonNameBase(Rank, HomotypicalGroup)
225
	 */
226
	public TaxonNameBase(HomotypicalGroup homotypicalGroup) {
227
		this(null, homotypicalGroup);
228
	}
229
	/** 
230
	 * Class constructor: creates a new taxon name
231
	 * only containing its {@link Rank rank} and
232
	 * its {@link HomotypicalGroup homotypical group}.
233
	 * The new taxon name will be also added to the set of taxon names
234
	 * belonging to this homotypical group.
235
	 * 
236
	 * @param  rank  			 the rank to be assigned to <i>this</i> taxon name
237
	 * @param  homotypicalGroup  the homotypical group to which <i>this</i> taxon name belongs
238
	 * @see    					 #TaxonNameBase()
239
	 * @see    					 #TaxonNameBase(Rank)
240
	 * @see    					 #TaxonNameBase(HomotypicalGroup)
241
	 */
242
	public TaxonNameBase(Rank rank, HomotypicalGroup homotypicalGroup) {
243
		super();
244
		this.setRank(rank);
245
		if (homotypicalGroup == null){
246
			homotypicalGroup = new HomotypicalGroup();
247
		}
248
		homotypicalGroup.addTypifiedName(this);
249
	}
250
	
251
//********* METHODS **************************************/
252
	
253
	/**
254
	 * Returns the boolean value "false" since the components of <i>this</i> taxon name
255
	 * cannot follow the rules of a corresponding {@link NomenclaturalCode nomenclatural code}
256
	 * which is not defined for this class. The nomenclature code depends on
257
	 * the concrete name subclass ({@link BacterialName BacterialName},
258
	 * {@link BotanicalName BotanicalName}, {@link CultivarPlantName CultivarPlantName},
259
	 * {@link ZoologicalName ZoologicalName} or {@link ViralName ViralName}) 
260
	 * to which a taxon name belongs.
261
	 *  
262
	 * @return  false
263
	 */
264
	@Transient
265
	public abstract boolean isCodeCompliant();
266
	
267
	public abstract String generateFullTitle();
268

    
269
	@Transient
270
	public String getFullTitleCache(){
271
		if (protectedFullTitleCache){
272
			return this.fullTitleCache;			
273
		}
274
		if (fullTitleCache == null){
275
			this.setFullTitleCache(generateFullTitle(), protectedFullTitleCache);
276
		}
277
		return fullTitleCache;
278
	}
279
	
280
	@Transient
281
	public List<Object> getTaggedName(){
282
		return getCacheStrategy().getTaggedName(this);
283
	}
284

    
285
    public void setFullTitleCache(String fullTitleCache){
286
		setFullTitleCache(fullTitleCache, PROTECTED);
287
	}
288
	
289
	public void setFullTitleCache(String fullTitleCache, boolean protectCache){
290
		//TODO truncation of full title cache
291
		if (fullTitleCache != null && fullTitleCache.length() > 329){
292
			logger.warn("Truncation of full title cache: " + this.toString() + "/" + fullTitleCache);
293
			fullTitleCache = fullTitleCache.substring(0, 329) + "...";
294
		}
295
		this.fullTitleCache = fullTitleCache;
296
		this.setProtectedFullTitleCache(protectCache);
297
	}
298
	
299
	public boolean isProtectedFullTitleCache() {
300
		return protectedFullTitleCache;
301
	}
302

    
303
	public void setProtectedFullTitleCache(boolean protectedFullTitleCache) {
304
		this.protectedFullTitleCache = protectedFullTitleCache;
305
	}
306
	
307
	/** 
308
	 * Returns the set of all {@link NameRelationship name relationships}
309
	 * in which <i>this</i> taxon name is involved. A taxon name can be both source
310
	 * in some name relationships or target in some others.
311
	 *  
312
	 * @see    #getRelationsToThisName()
313
	 * @see    #getRelationsFromThisName()
314
	 * @see    #addNameRelationship(NameRelationship)
315
	 * @see    #addRelationshipToName(TaxonNameBase, NameRelationshipType, String)
316
	 * @see    #addRelationshipFromName(TaxonNameBase, NameRelationshipType, String)
317
	 */
318
	@Transient
319
	public Set<NameRelationship> getNameRelations() {
320
		Set<NameRelationship> rels = new HashSet<NameRelationship>();
321
		rels.addAll(getRelationsFromThisName());
322
		rels.addAll(getRelationsToThisName());
323
		return rels;
324
	}
325
	
326
	/**
327
	 * Creates a new {@link NameRelationship#NameRelationship(TaxonNameBase, TaxonNameBase, NameRelationshipType, String) name relationship} from <i>this</i> taxon name to another taxon name
328
	 * and adds it both to the set of {@link #getRelationsFromThisName() relations from <i>this</i> taxon name} and
329
	 * to the set of {@link #getRelationsToThisName() relations to the other taxon name}.
330
	 * 
331
	 * @param toName		  the taxon name of the target for this new name relationship
332
	 * @param type			  the type of this new name relationship
333
	 * @param ruleConsidered  the string which specifies the rule on which this name relationship is based
334
	 * @see    				  #getRelationsToThisName()
335
	 * @see    				  #getNameRelations()
336
	 * @see    				  #addRelationshipFromName(TaxonNameBase, NameRelationshipType, String)
337
	 * @see    				  #addNameRelationship(NameRelationship)
338
	 */
339
	public void addRelationshipToName(TaxonNameBase toName, NameRelationshipType type, String ruleConsidered){
340
		NameRelationship rel = new NameRelationship(toName, this, type, ruleConsidered);
341
	}
342
	
343
	public void addRelationshipToName(TaxonNameBase toName, NameRelationshipType type, ReferenceBase citation, String microCitation, String ruleConsidered){
344
		NameRelationship rel = new NameRelationship(toName, this, type, citation, microCitation, ruleConsidered);
345
	}
346
	
347
	/**
348
	 * Creates a new {@link NameRelationship#NameRelationship(TaxonNameBase, TaxonNameBase, NameRelationshipType, String) name relationship} from another taxon name to <i>this</i> taxon name
349
	 * and adds it both to the set of {@link #getRelationsToThisName() relations to <i>this</i> taxon name} and
350
	 * to the set of {@link #getRelationsFromThisName() relations from the other taxon name}.
351
	 * 
352
	 * @param fromName		  the taxon name of the source for this new name relationship
353
	 * @param type			  the type of this new name relationship
354
	 * @param ruleConsidered  the string which specifies the rule on which this name relationship is based
355
	 * @see    				  #getRelationsFromThisName()
356
	 * @see    				  #getNameRelations()
357
	 * @see    				  #addRelationshipToName(TaxonNameBase, NameRelationshipType, String)
358
	 * @see    				  #addNameRelationship(NameRelationship)
359
	 */
360
	public void addRelationshipFromName(TaxonNameBase fromName, NameRelationshipType type, String ruleConsidered){
361
		NameRelationship rel = new NameRelationship(this, fromName, type, ruleConsidered);
362
	}
363
	public void addRelationshipFromName(TaxonNameBase fromName, NameRelationshipType type, ReferenceBase citation, String microCitation, String ruleConsidered){
364
		NameRelationship rel = new NameRelationship(this, fromName, type, citation, microCitation, ruleConsidered);
365
	}
366

    
367
	/**
368
	 * Adds an existing {@link NameRelationship name relationship} either to the set of
369
	 * {@link #getRelationsToThisName() relations to <i>this</i> taxon name} or to the set of
370
	 * {@link #getRelationsFromThisName() relations from <i>this</i> taxon name}. If neither the
371
	 * source nor the target of the name relationship match with <i>this</i> taxon name
372
	 * no addition will be carried out.
373
	 * 
374
	 * @param rel  the name relationship to be added to one of <i>this</i> taxon name's name relationships sets
375
	 * @see    	   #getNameRelations()
376
	 * @see    	   #addRelationshipToName(TaxonNameBase, NameRelationshipType, String)
377
	 * @see    	   #addRelationshipFromName(TaxonNameBase, NameRelationshipType, String)
378
	 */
379
	protected void addNameRelationship(NameRelationship rel) {
380
		if (rel!=null && rel.getToName().equals(this)){
381
			this.relationsToThisName.add(rel);
382
		}else if(rel!=null && rel.getFromName().equals(this)){
383
			this.relationsFromThisName.add(rel);			
384
		}else{
385
			//TODO: raise error???
386
		}
387
	}
388
	/** 
389
	 * Removes one {@link NameRelationship name relationship} from one of both sets of
390
	 * {@link #getNameRelations() name relationships} in which <i>this</i> taxon name is involved.
391
	 * The name relationship will also be removed from one of both sets belonging
392
	 * to the second taxon name involved. Furthermore the fromName and toName
393
	 * attributes of the name relationship object will be nullified. 
394
	 *
395
	 * @param  nameRelation  the name relationship which should be deleted from one of both sets
396
	 * @see    				 #getNameRelations()
397
	 */
398
	public void removeNameRelationship(NameRelationship nameRelation) {
399
		
400
		TaxonNameBase fromName = nameRelation.getFromName();
401
		TaxonNameBase toName = nameRelation.getToName();
402

    
403
		if (nameRelation != null) {
404
			nameRelation.setToName(null);
405
			nameRelation.setFromName(null);
406
		}
407
		
408
		if (fromName != null) {
409
			fromName.removeNameRelationship(nameRelation);
410
		}
411
		
412
		if (toName != null) {
413
			toName.removeNameRelationship(nameRelation);
414
		}
415
		
416
		this.relationsToThisName.remove(nameRelation);
417
		this.relationsFromThisName.remove(nameRelation);
418
	}
419
		
420
	public void removeTaxonName(TaxonNameBase taxonName) {
421
		Set<NameRelationship> nameRelationships = new HashSet<NameRelationship>();
422
//		nameRelationships.addAll(this.getNameRelations());
423
		nameRelationships.addAll(this.getRelationsFromThisName());
424
		nameRelationships.addAll(this.getRelationsToThisName());
425
		for(NameRelationship nameRelationship : nameRelationships) {
426
			// remove name relationship from this side 
427
			if (nameRelationship.getFromName().equals(this) && nameRelationship.getToName().equals(taxonName)) {
428
				this.removeNameRelation(nameRelationship);
429
			}
430
		}
431
	}
432
	
433
	public void removeNameRelation(NameRelationship nameRelation) {
434
		nameRelation.setToName(null);
435
	
436
		TaxonNameBase name = nameRelation.getFromName();
437
		if (name != null){
438
			nameRelation.setFromName(null);
439
			name.removeNameRelation(nameRelation);
440
		}
441
		this.relationsToThisName.remove(nameRelation);
442
		this.relationsFromThisName.remove(nameRelation);
443
	}
444
	
445
	
446
	/**
447
	 * Does exactly the same as the addNameRelationship method provided that
448
	 * the given relationship is a name relationship.
449
	 * 
450
	 * @param relation  the relationship to be added to one of <i>this</i> taxon name's name relationships sets
451
	 * @see    	   		#addNameRelationship(NameRelationship)
452
	 * @see    	   		#getNameRelations()
453
	 * @see    	   		NameRelationship
454
	 * @see    	   		eu.etaxonomy.cdm.model.common.RelationshipBase
455
	 */
456
	public void addRelationship(RelationshipBase relation) {
457
		if (relation instanceof NameRelationship){
458
			addNameRelationship((NameRelationship)relation);
459
			if (relation.getType() != null && 
460
						( relation.getType().equals(NameRelationshipType.BASIONYM()) ||
461
						  relation.getType().equals(NameRelationshipType.REPLACED_SYNONYM()) 
462
						 )){
463
				TaxonNameBase fromName = ((NameRelationship)relation).getFromName();
464
				TaxonNameBase toName = ((NameRelationship)relation).getToName();
465
				fromName.getHomotypicalGroup().merge(toName.getHomotypicalGroup());
466
			}		
467
		}else{
468
			logger.warn("Relationship not of type NameRelationship!");
469
			//TODO exception handling
470
		}
471
	}
472

    
473
	
474
	/** 
475
	 * Returns the set of all {@link NameRelationship name relationships}
476
	 * in which <i>this</i> taxon name is involved as a source.
477
	 *  
478
	 * @see    #getNameRelations()
479
	 * @see    #getRelationsToThisName()
480
	 * @see    #addRelationshipFromName(TaxonNameBase, NameRelationshipType, String)
481
	 */
482
	public Set<NameRelationship> getRelationsFromThisName() {
483
		return relationsFromThisName;
484
	}
485

    
486
	/** 
487
	 * Returns the set of all {@link NameRelationship name relationships}
488
	 * in which <i>this</i> taxon name is involved as a target.
489
	 *  
490
	 * @see    #getNameRelations()
491
	 * @see    #getRelationsFromThisName()
492
	 * @see    #addRelationshipToName(TaxonNameBase, NameRelationshipType, String)
493
	 */
494
	public Set<NameRelationship> getRelationsToThisName() {
495
		return relationsToThisName;
496
	}
497
	
498
	/** 
499
	 * Returns the set of {@link NomenclaturalStatus nomenclatural status} assigned
500
	 * to <i>this</i> taxon name according to its corresponding nomenclature code.
501
	 * This includes the {@link NomenclaturalStatusType type} of the nomenclatural status
502
	 * and the nomenclatural code rule considered.
503
	 *
504
	 * @see     NomenclaturalStatus
505
	 * @see     NomenclaturalStatusType
506
	 */
507
	public Set<NomenclaturalStatus> getStatus() {
508
		return status;
509
	}
510

    
511
	/** 
512
	 * Adds a new {@link NomenclaturalStatus nomenclatural status}
513
	 * to <i>this</i> taxon name's set of nomenclatural status.
514
	 *
515
	 * @param  nomStatus  the nomenclatural status to be added
516
	 * @see 			  #getStatus()
517
	 */
518
	public void addStatus(NomenclaturalStatus nomStatus) {
519
		this.status.add(nomStatus);
520
	}
521
	
522
	/** 
523
	 * Removes one element from the set of nomenclatural status of <i>this</i> taxon name.
524
	 * Type and ruleConsidered attributes of the nomenclatural status object
525
	 * will be nullified.
526
	 *
527
	 * @param  nomStatus  the nomenclatural status of <i>this</i> taxon name which should be deleted
528
	 * @see     		  #getStatus()
529
	 */
530
	public void removeStatus(NomenclaturalStatus nomStatus) {
531
		//TODO to be implemented?
532
		logger.warn("not yet fully implemented?");
533
		this.status.remove(nomStatus);
534
	}
535

    
536
	
537
	/**
538
	 * Indicates whether <i>this</i> taxon name is a {@link NameRelationshipType#BASIONYM() basionym}
539
	 * or a {@link NameRelationshipType#REPLACED_SYNONYM() replaced synonym}
540
	 * of any other taxon name. Returns "true", if a basionym or a replaced 
541
	 * synonym {@link NameRelationship relationship} from <i>this</i> taxon name to another taxon name exists,
542
	 * false otherwise (also in case <i>this</i> taxon name is the only one in the
543
	 * homotypical group).
544
	 */
545
	@Transient
546
	public boolean isOriginalCombination(){
547
		Set<NameRelationship> relationsFromThisName = this.getRelationsFromThisName();
548
		for (NameRelationship relation : relationsFromThisName) {
549
			if (relation.getType().equals(NameRelationshipType.BASIONYM()) ||
550
					relation.getType().equals(NameRelationshipType.REPLACED_SYNONYM())) {
551
				return true;
552
			}
553
		}
554
		return false;
555
	}
556
	
557
	/**
558
	 * Returns the taxon name which is the {@link NameRelationshipType#BASIONYM() basionym} of <i>this</i> taxon name.
559
	 * The basionym of a taxon name is its epithet-bringing synonym.
560
	 * For instance <i>Pinus abies</i> L. was published by Linnaeus and the botanist
561
	 * Karsten transferred later <i>this</i> taxon to the genus Picea. Therefore,
562
	 * <i>Pinus abies</i> L. is the basionym of the new combination <i>Picea abies</i> (L.) H. Karst.
563
	 */
564
	@Transient
565
	public T getBasionym(){
566
		//TODO: pick the right name relationships...
567
		logger.warn("get Basionym not yet implemented");
568
		return null;
569
	}
570
	/**
571
	 * Assigns a taxon name as {@link NameRelationshipType#BASIONYM() basionym} of <i>this</i> taxon name.
572
	 * The basionym {@link NameRelationship relationship} will be added to <i>this</i> taxon name
573
	 * and to the basionym. The basionym cannot have itself a basionym.
574
	 * The {@link HomotypicalGroup homotypical groups} of <i>this</i> taxon name and of the basionym
575
	 * will be {@link HomotypicalGroup#merge(HomotypicalGroup) merged}.
576
	 * 
577
	 * @param  basionym		the taxon name to be set as the basionym of <i>this</i> taxon name
578
	 * @see  				#getBasionym()
579
	 * @see  				#addBasionym(TaxonNameBase, String)
580
	 */
581
	public void addBasionym(T basionym){
582
		addBasionym(basionym, null, null, null);
583
	}
584
	/**
585
	 * Assigns a taxon name as {@link NameRelationshipType#BASIONYM() basionym} of <i>this</i> taxon name
586
	 * and keeps the nomenclatural rule considered for it. The basionym
587
	 * {@link NameRelationship relationship} will be added to <i>this</i> taxon name and to the basionym.
588
	 * The basionym cannot have itself a basionym.
589
	 * The {@link HomotypicalGroup homotypical groups} of <i>this</i> taxon name and of the basionym
590
	 * will be {@link HomotypicalGroup#merge(HomotypicalGroup) merged}.
591
	 * 
592
	 * @param  basionym			the taxon name to be set as the basionym of <i>this</i> taxon name
593
	 * @param  ruleConsidered	the string identifying the nomenclatural rule
594
	 * @see  					#getBasionym()
595
	 * @see  					#addBasionym(TaxonNameBase)
596
	 */
597
	public void addBasionym(T basionym, ReferenceBase citation, String microcitation, String ruleConsidered){
598
		if (basionym != null){
599
			basionym.addRelationshipToName(this, NameRelationshipType.BASIONYM(), citation, microcitation, ruleConsidered);
600
		}
601
	}
602
	
603
	/** 
604
	 * Removes the {@link NameRelationshipType#BASIONYM() basionym} {@link NameRelationship relationship} from the set of
605
	 * {@link #getRelationsToThisName() name relationships to} <i>this</i> taxon name. The same relationhip will be
606
	 * removed from the set of {@link #getRelationsFromThisName() name relationships from} the taxon name
607
	 * previously used as basionym.
608
	 *
609
	 * @see   #getBasionym()
610
	 * @see   #addBasionym(TaxonNameBase)
611
	 */
612
	public void removeBasionym(){
613
		//TODO implement
614
		logger.warn("not yet implemented");
615
	}
616
	
617
	/** 
618
	 * Returns the taxonomic {@link Rank rank} of <i>this</i> taxon name.
619
	 *
620
	 * @see 	Rank
621
	 */
622
	public Rank getRank(){
623
		return this.rank;
624
	}
625
	
626
	/**
627
	 * @see  #getRank()
628
	 */
629
	public void setRank(Rank rank){
630
		this.rank = rank;
631
	}
632

    
633
	/** 
634
	 * Returns the {@link eu.etaxonomy.cdm.model.reference.INomenclaturalReference nomenclatural reference} of <i>this</i> taxon name.
635
	 * The nomenclatural reference is here meant to be the one publication
636
	 * <i>this</i> taxon name was originally published in while fulfilling the formal
637
	 * requirements as specified by the corresponding {@link NomenclaturalCode nomenclatural code}.
638
	 *
639
	 * @see 	eu.etaxonomy.cdm.model.reference.INomenclaturalReference
640
	 * @see 	eu.etaxonomy.cdm.model.reference.ReferenceBase
641
	 */
642
	public ReferenceBase getNomenclaturalReference(){
643
		return this.nomenclaturalReference;
644
	}
645
	/**
646
	 * Assigns a {@link eu.etaxonomy.cdm.model.reference.INomenclaturalReference nomenclatural reference} to <i>this</i> taxon name.
647
	 * The corresponding {@link eu.etaxonomy.cdm.model.reference.ReferenceBase.isNomenclaturallyRelevant nomenclaturally relevant flag} will be set to true
648
	 * as it is obviously used for nomenclatural purposes.
649
	 *
650
	 * @throws IllegalArgumentException if parameter <code>nomenclaturalReference</code> is not assignable from {@link INomenclaturalReference}
651
	 * @see  #getNomenclaturalReference()
652
	 */
653
	public void setNomenclaturalReference(ReferenceBase nomenclaturalReference){
654
		if(nomenclaturalReference != null){
655
			if(!INomenclaturalReference.class.isAssignableFrom(nomenclaturalReference.getClass())){
656
				throw new IllegalArgumentException("Parameter nomenclaturalReference is not assignable from INomenclaturalReference");
657
			}
658
			this.nomenclaturalReference = (ReferenceBase)nomenclaturalReference;
659
		} else {
660
			this.nomenclaturalReference = null;
661
		}
662
	}
663

    
664
	/** 
665
	 * Returns the appended phrase string assigned to <i>this</i> taxon name.
666
	 * The appended phrase is a non-atomised addition to a name. It is
667
	 * not ruled by a nomenclatural code.
668
	 */
669
	public String getAppendedPhrase(){
670
		return this.appendedPhrase;
671
	}
672
	
673
	/**
674
	 * @see  #getAppendedPhrase()
675
	 */
676
	public void setAppendedPhrase(String appendedPhrase){
677
		this.appendedPhrase = appendedPhrase;
678
	}
679

    
680
	/** 
681
	 * Returns the details string of the {@link #getNomenclaturalReference() nomenclatural reference} assigned
682
	 * to <i>this</i> taxon name. The details describe the exact localisation within
683
	 * the publication used as nomenclature reference. These are mostly
684
	 * (implicitly) pages but can also be figures or tables or any other
685
	 * element of a publication. A nomenclatural micro reference (details)
686
	 * requires the existence of a nomenclatural reference.
687
	 */
688
	//Details of the nomenclatural reference (protologue). 
689
	public String getNomenclaturalMicroReference(){
690
		return this.nomenclaturalMicroReference;
691
	}
692
	/**
693
	 * @see  #getNomenclaturalMicroReference()
694
	 */
695
	public void setNomenclaturalMicroReference(String nomenclaturalMicroReference){
696
		this.nomenclaturalMicroReference = nomenclaturalMicroReference;
697
	}
698

    
699
	/* (non-Javadoc)
700
	 * @see eu.etaxonomy.cdm.model.common.IParsable#getHasProblem()
701
	 */
702
	public boolean getHasProblem(){
703
		return this.hasProblem;
704
	}
705
	
706
	/* (non-Javadoc)
707
	 * @see eu.etaxonomy.cdm.model.common.IParsable#setHasProblem(boolean)
708
	 */
709
	public void setHasProblem(boolean hasProblem){
710
		this.hasProblem = hasProblem;
711
	}
712
	
713
	/* (non-Javadoc)
714
	 * @see eu.etaxonomy.cdm.model.common.IParsable#hasProblem()
715
	 */
716
	public boolean hasProblem(){
717
		return getHasProblem();
718
	}
719
	
720
	/* (non-Javadoc)
721
	 * @see eu.etaxonomy.cdm.model.common.IParsable#problemStarts()
722
	 */
723
	public int getProblemStarts(){
724
		return this.problemStarts;
725
	}
726
	
727
	/* (non-Javadoc)
728
	 * @see eu.etaxonomy.cdm.model.common.IParsable#setProblemStarts(int)
729
	 */
730
	public void setProblemStarts(int start) {
731
		this.problemStarts = start;
732
	}
733
	
734
	/* (non-Javadoc)
735
	 * @see eu.etaxonomy.cdm.model.common.IParsable#problemEnds()
736
	 */
737
	public int getProblemEnds(){
738
		return this.problemEnds;
739
	}
740

    
741
	/* (non-Javadoc)
742
	 * @see eu.etaxonomy.cdm.model.common.IParsable#setProblemEnds(int)
743
	 */
744
	public void setProblemEnds(int end) {
745
		this.problemEnds = end;
746
	}
747

    
748
//*********************** TYPE DESIGNATION *********************************************//	
749
	
750
	/** 
751
	 * Returns the set of {@link TypeDesignationBase type designations} assigned
752
	 * to <i>this</i> taxon name.
753
	 * @see     NameTypeDesignation
754
	 * @see     SpecimenTypeDesignation
755
	 */
756
	public Set<TypeDesignationBase> getTypeDesignations() {
757
		return typeDesignations;
758
	}
759
	
760
	/** 
761
	 * Removes one element from the set of {@link TypeDesignationBase type designations} assigned to
762
	 * <i>this</i> taxon name. The type designation itself will be nullified.
763
	 *
764
	 * @param  typeDesignation  the type designation which should be deleted
765
	 */
766
	public void removeTypeDesignation(TypeDesignationBase typeDesignation) {
767
		logger.warn("not yet fully implemented: nullify the specimen type designation itself?");
768
		this.typeDesignations.remove(typeDesignation);
769
	}
770
	
771
	/** 
772
	 * Returns the set of {@link SpecimenTypeDesignation specimen type designations} assigned
773
	 * to <i>this</i> taxon name. The {@link Rank rank} of <i>this</i> taxon name is generally
774
	 * "species" or below. The specimen type designations include all the
775
	 * specimens on which the typification of this name is based (which are
776
	 * exclusively used to typify taxon names belonging to the same
777
	 * {@link HomotypicalGroup homotypical group} to which <i>this</i> taxon name
778
	 * belongs) and eventually the status of these designations.
779
	 *
780
	 * @see     SpecimenTypeDesignation
781
	 * @see     NameTypeDesignation
782
	 * @see     HomotypicalGroup
783
	 */
784
	@Transient
785
	public Set<SpecimenTypeDesignation> getSpecimenTypeDesignationsOfHomotypicalGroup() {
786
		return this.getHomotypicalGroup().getSpecimenTypeDesignations();
787
	}
788
	
789
//*********************** NAME TYPE DESIGNATION *********************************************//	
790
	
791
	/** 
792
	 * Returns the set of {@link NameTypeDesignation name type designations} assigned
793
	 * to <i>this</i> taxon name the rank of which must be above "species".
794
	 * The name type designations include all the taxon names used to typify
795
	 * <i>this</i> taxon name and eventually the rejected or conserved status
796
	 * of these designations.
797
	 *
798
	 * @see     NameTypeDesignation
799
	 * @see     SpecimenTypeDesignation
800
	 */
801
	@Transient
802
	public Set<NameTypeDesignation> getNameTypeDesignations() {
803
		Set<NameTypeDesignation> result = new HashSet<NameTypeDesignation>();
804
		for (TypeDesignationBase typeDesignation : this.typeDesignations){
805
			if (typeDesignation instanceof NameTypeDesignation){
806
				result.add((NameTypeDesignation)typeDesignation);
807
			}
808
		}
809
		return result;
810
	}
811
	
812
	/** 
813
	 * Creates and adds a new {@link NameTypeDesignation name type designation}
814
	 * to <i>this</i> taxon name's set of type designations.
815
	 *
816
	 * @param  typeSpecies				the taxon name to be used as type of <i>this</i> taxon name
817
	 * @param  citation					the reference for this new designation
818
	 * @param  citationMicroReference	the string with the details (generally pages) within the reference
819
	 * @param  originalNameString		the taxon name string used in the reference to assert this designation
820
	 * @param  isRejectedType			the boolean status for a rejected name type designation
821
	 * @param  isConservedType			the boolean status for a conserved name type designation
822
	 * @param  isLectoType				the boolean status for a lectotype name type designation
823
	 * @param  isNotDesignated			the boolean status for a name type designation without name type
824
	 * @param  addToAllHomotypicNames	the boolean indicating whether the name type designation should be
825
	 * 									added to all taxon names of the homotypical group this taxon name belongs to
826
	 * @see 			  				#getNameTypeDesignations()
827
	 * @see 			  				NameTypeDesignation
828
	 * @see 			  				TypeDesignationBase#isNotDesignated()
829
	 */
830
	public void addNameTypeDesignation(TaxonNameBase typeSpecies, 
831
				ReferenceBase citation, 
832
				String citationMicroReference, 
833
				String originalNameString, 
834
				boolean isRejectedType, 
835
				boolean isConservedType, 
836
				boolean isLectoType, 
837
				boolean isNotDesignated, 
838
				boolean addToAllHomotypicNames) {
839
		NameTypeDesignation nameTypeDesignation = new NameTypeDesignation(typeSpecies, citation, citationMicroReference, originalNameString, isRejectedType, isConservedType, isLectoType, isNotDesignated);
840
		nameTypeDesignation.setLectoType(isLectoType);
841
		addTypeDesignation(nameTypeDesignation, addToAllHomotypicNames);
842
	}
843
	
844
//*********************** SPECIMEN TYPE DESIGNATION *********************************************//	
845
	
846
	/** 
847
	 * Returns the set of {@link SpecimenTypeDesignation specimen type designations}
848
	 * that typify <i>this</i> taxon name.
849
	 */
850
	@Transient
851
	public Set<SpecimenTypeDesignation> getSpecimenTypeDesignations() {
852
		Set<SpecimenTypeDesignation> result = new HashSet<SpecimenTypeDesignation>();
853
		for (TypeDesignationBase typeDesignation : this.typeDesignations){
854
			if (typeDesignation instanceof SpecimenTypeDesignation){
855
				result.add((SpecimenTypeDesignation)typeDesignation);
856
			}
857
		}
858
		return result;
859
	}
860

    
861
	
862
	/** 
863
	 * Creates and adds a new {@link SpecimenTypeDesignation specimen type designation}
864
	 * to <i>this</i> taxon name's set of type designations.
865
	 *
866
	 * @param  typeSpecimen				the specimen to be used as a type for <i>this</i> taxon name
867
	 * @param  status					the specimen type designation status
868
	 * @param  citation					the reference for this new specimen type designation
869
	 * @param  citationMicroReference	the string with the details (generally pages) within the reference
870
	 * @param  originalNameString		the taxon name used in the reference to assert this designation
871
	 * @param  isNotDesignated			the boolean status for a specimen type designation without specimen type
872
	 * @param  addToAllHomotypicNames	the boolean indicating whether the specimen type designation should be
873
	 * 									added to all taxon names of the homotypical group the typified
874
	 * 									taxon name belongs to
875
	 * @see 			  				#getSpecimenTypeDesignations()
876
	 * @see 			  				SpecimenTypeDesignationStatus
877
	 * @see 			  				SpecimenTypeDesignation
878
	 * @see 			  				TypeDesignationBase#isNotDesignated()
879
	 */
880
	public void addSpecimenTypeDesignation(Specimen typeSpecimen, 
881
				SpecimenTypeDesignationStatus status, 
882
				ReferenceBase citation, 
883
				String citationMicroReference, 
884
				String originalNameString, 
885
				boolean isNotDesignated, 
886
				boolean addToAllHomotypicNames) {
887
		SpecimenTypeDesignation specimenTypeDesignation = new SpecimenTypeDesignation(typeSpecimen, status, citation, citationMicroReference, originalNameString, isNotDesignated);
888
		addTypeDesignation(specimenTypeDesignation, addToAllHomotypicNames);
889
	}
890
	
891
	private boolean addTypeDesignation(TypeDesignationBase typeDesignation, boolean addToAllNames){
892
		//at them moment typeDesignations are not persisted with the homotypical group
893
		//so explicit adding to the homotypical group is not necessary.
894
		if (typeDesignation != null){
895
			this.typeDesignations.add(typeDesignation);
896
			typeDesignation.addTypifiedName(this);
897
			
898
			if (addToAllNames){
899
				for (TaxonNameBase taxonName : this.getHomotypicalGroup().getTypifiedNames()){
900
					if (taxonName != this){
901
						taxonName.addTypeDesignation(typeDesignation, false);
902
					}
903
				}
904
			}
905
		}
906
		return true;
907
	}
908
	
909

    
910
	
911
//*********************** HOMOTYPICAL GROUP *********************************************//	
912

    
913
	
914
	/** 
915
	 * Returns the {@link HomotypicalGroup homotypical group} to which
916
	 * <i>this</i> taxon name belongs. A homotypical group represents all taxon names
917
	 * that share the same types.
918
	 *
919
	 * @see 	HomotypicalGroup
920
	 */
921
	
922
	public HomotypicalGroup getHomotypicalGroup() {
923
		return homotypicalGroup;
924
	}
925
	
926
	/* 
927
	 * @see #getHomotypicalGroup()
928
	 */
929
	protected void setHomotypicalGroup(HomotypicalGroup homotypicalGroup) {
930
		this.homotypicalGroup = homotypicalGroup;
931
	}
932

    
933
// *************************************************************************//
934
	
935
	/** 
936
	 * @see #getNomenclaturalReference()
937
	 */
938
	@Transient
939
	public StrictReferenceBase getCitation(){
940
		//TODO What is the purpose of this method differing from the getNomenclaturalReference method? 
941
		logger.warn("getCitation not yet implemented");
942
		return null;
943
	}
944

    
945
	/** 
946
	 * Returns the complete string containing the
947
	 * {@link eu.etaxonomy.cdm.model.reference.INomenclaturalReference#getNomenclaturalCitation() nomenclatural reference citation}
948
	 * and the {@link #getNomenclaturalMicroReference() details} assigned to <i>this</i> taxon name.
949
	 * 
950
	 * @return  the string containing the nomenclatural reference of <i>this</i> taxon name
951
	 * @see		eu.etaxonomy.cdm.model.reference.INomenclaturalReference#getNomenclaturalCitation()
952
	 * @see		#getNomenclaturalReference()
953
	 * @see		#getNomenclaturalMicroReference()
954
	 */
955
	@Transient
956
	@Deprecated
957
	public String getCitationString(){
958
		logger.warn("getCitationString not yet implemented");
959
		return null;
960
	}
961

    
962
	/** 
963
	 * Not yet implemented
964
	 */
965
	@Deprecated
966
	public String[] getProblems(){
967
		logger.warn("getProblems not yet implemented");
968
		return null;
969
	}
970

    
971
	/**
972
	 * Returns the string containing the publication date (generally only year)
973
	 * of the {@link #getNomenclaturalReference() nomenclatural reference} for <i>this</i> taxon name, null if there is
974
	 * no nomenclatural reference.
975
	 * 
976
	 * @return  the string containing the publication date of <i>this</i> taxon name
977
	 * @see		eu.etaxonomy.cdm.model.reference.INomenclaturalReference#getYear()
978
	 */
979
	@Transient
980
	public String getReferenceYear(){
981
		if (this.getNomenclaturalReference() != null ){
982
			return this.getNomenclaturalReference().getYear();
983
		}else{
984
			return null;
985
		}
986
	}
987

    
988
	/** 
989
	 * Returns the set of {@link eu.etaxonomy.cdm.model.taxon.TaxonBase taxon bases} that refer to <i>this</i> taxon name.
990
	 * In this context a taxon base means the use of a taxon name by a reference
991
	 * either as a {@link eu.etaxonomy.cdm.model.taxon.Taxon taxon} ("accepted/correct" name) or
992
	 * as a (junior) {@link eu.etaxonomy.cdm.model.taxon.Synonym synonym}.
993
	 * A taxon name can be used by several distinct {@link eu.etaxonomy.cdm.model.reference.ReferenceBase references} but only once
994
	 * within a taxonomic treatment (identified by one reference).
995
	 *
996
	 * @see	#getTaxa()
997
	 * @see	#getSynonyms()
998
	 */
999
	public Set<TaxonBase> getTaxonBases() {
1000
		return this.taxonBases;
1001
	}
1002
	
1003
	/** 
1004
	 * Adds a new {@link eu.etaxonomy.cdm.model.taxon.TaxonBase taxon base}
1005
	 * to the set of taxon bases using <i>this</i> taxon name.
1006
	 *
1007
	 * @param  taxonBase  the taxon base to be added
1008
	 * @see 			  #getTaxonBases()
1009
	 * @see 			  #removeTaxonBase(TaxonBase)
1010
	 */
1011
	//TODO protected
1012
	public void addTaxonBase(TaxonBase taxonBase){
1013
		Method method = ReflectionUtils.findMethod(TaxonBase.class, "setName", new Class[] {TaxonNameBase.class});
1014
		ReflectionUtils.makeAccessible(method);
1015
		ReflectionUtils.invokeMethod(method, taxonBase, new Object[] {this});
1016
		taxonBases.add(taxonBase);
1017
	}
1018
	/** 
1019
	 * Removes one element from the set of {@link eu.etaxonomy.cdm.model.taxon.TaxonBase taxon bases} that refer to <i>this</i> taxon name.
1020
	 *
1021
	 * @param  taxonBase	the taxon base which should be removed from the corresponding set
1022
	 * @see    				#getTaxonBases()
1023
	 * @see    				#addTaxonBase(TaxonBase)
1024
	 */
1025
	public void removeTaxonBase(TaxonBase taxonBase){
1026
		Method method = ReflectionUtils.findMethod(TaxonBase.class, "setName", new Class[] {TaxonNameBase.class});
1027
		ReflectionUtils.makeAccessible(method);
1028
		ReflectionUtils.invokeMethod(method, taxonBase, new Object[] {null});
1029
		taxonBases.remove(taxonBase);
1030
	}
1031
	
1032
	/**
1033
	 * Returns the set of {@link eu.etaxonomy.cdm.model.taxon.Taxon taxa} ("accepted/correct" names according to any
1034
	 * reference) that are based on <i>this</i> taxon name. This set is a subset of
1035
	 * the set returned by getTaxonBases(). 
1036
	 * 
1037
	 * @see	eu.etaxonomy.cdm.model.taxon.Taxon
1038
	 * @see	#getTaxonBases()
1039
	 * @see	#getSynonyms()
1040
	 */
1041
	@Transient
1042
	public Set<Taxon> getTaxa(){
1043
		Set<Taxon> result = new HashSet<Taxon>();
1044
		for (TaxonBase taxonBase : this.taxonBases){
1045
			if (taxonBase instanceof Taxon){
1046
				result.add((Taxon)taxonBase);
1047
			}
1048
		}
1049
		return result;
1050
	}
1051
	
1052
	/**
1053
	 * Returns the set of {@link eu.etaxonomy.cdm.model.taxon.Synonym (junior) synonyms} (according to any
1054
	 * reference) that are based on <i>this</i> taxon name. This set is a subset of
1055
	 * the set returned by getTaxonBases(). 
1056
	 * 
1057
	 * @see	eu.etaxonomy.cdm.model.taxon.Synonym
1058
	 * @see	#getTaxonBases()
1059
	 * @see	#getTaxa()
1060
	 */
1061
	@Transient
1062
	public Set<Synonym> getSynonyms() {
1063
		Set<Synonym> result = new HashSet<Synonym>();
1064
		for (TaxonBase taxonBase : this.taxonBases){
1065
			if (taxonBase instanceof Synonym){
1066
				result.add((Synonym)taxonBase);
1067
			}
1068
		}
1069
		return result;
1070
	}
1071
	
1072
	
1073
// *********** DESCRIPTIONS *************************************	
1074

    
1075
	/**
1076
	 * Returns the set of {@link eu.etaxonomy.cdm.model.description.TaxonNameDescription taxon name descriptions} assigned
1077
	 * to <i>this</i> taxon name. A taxon name description is a piece of information
1078
	 * concerning the taxon name like for instance the content of its first
1079
	 * publication (protolog) or a picture of this publication.
1080
	 * 
1081
	 * @see	#addDescription(TaxonNameDescription)
1082
	 * @see	#removeDescription(TaxonNameDescription)
1083
	 * @see	eu.etaxonomy.cdm.model.description.TaxonNameDescription
1084
	 */
1085
	public Set<TaxonNameDescription> getDescriptions() {
1086
		return descriptions;
1087
	}
1088

    
1089
	/** 
1090
	 * Adds a new {@link eu.etaxonomy.cdm.model.description.TaxonNameDescription taxon name description}
1091
	 * to the set of taxon name descriptions assigned to <i>this</i> taxon name. The
1092
	 * content of the {@link eu.etaxonomy.cdm.model.description.TaxonNameDescription#getTaxonName() taxonName attribute} of the
1093
	 * taxon name description itself will be replaced with <i>this</i> taxon name.
1094
	 *
1095
	 * @param  description  the taxon name description to be added
1096
	 * @see					#getDescriptions()
1097
	 * @see 			  	#removeDescription(TaxonNameDescription)
1098
	 */
1099
	public void addDescription(TaxonNameDescription description) {
1100
		java.lang.reflect.Field field = ReflectionUtils.findField(TaxonNameDescription.class, "taxonName", TaxonNameBase.class);
1101
		ReflectionUtils.makeAccessible(field);
1102
		ReflectionUtils.setField(field, description, this);
1103
		descriptions.add(description);
1104
	}
1105
	/** 
1106
	 * Removes one element from the set of {@link eu.etaxonomy.cdm.model.description.TaxonNameDescription taxon name descriptions} assigned
1107
	 * to <i>this</i> taxon name. The content of the {@link eu.etaxonomy.cdm.model.description.TaxonNameDescription#getTaxonName() taxonName attribute}
1108
	 * of the description itself will be set to "null".
1109
	 *
1110
	 * @param  description  the taxon name description which should be removed
1111
	 * @see     		  	#getDescriptions()
1112
	 * @see     		  	#addDescription(TaxonNameDescription)
1113
	 * @see 			  	eu.etaxonomy.cdm.model.description.TaxonNameDescription#getTaxonName()
1114
	 */
1115
	public void removeDescription(TaxonNameDescription description) {
1116
		java.lang.reflect.Field field = ReflectionUtils.findField(TaxonNameDescription.class, "taxonName", TaxonNameBase.class);
1117
		ReflectionUtils.makeAccessible(field);
1118
		ReflectionUtils.setField(field, description, null);
1119
		descriptions.remove(description);
1120
	}
1121
	
1122
// ***********
1123
	/**
1124
	 * Returns the boolean value indicating whether a given taxon name belongs
1125
	 * to the same {@link HomotypicalGroup homotypical group} as <i>this</i> taxon name (true)
1126
	 * or not (false). Returns "true" only if the homotypical groups of both
1127
	 * taxon names exist and if they are identical. 
1128
	 *
1129
	 * @param	homoTypicName  the taxon name the homotypical group of which is to be checked
1130
	 * @return  			   the boolean value of the check
1131
	 * @see     			   HomotypicalGroup
1132
	 */
1133
	@Transient
1134
	public boolean isHomotypic(TaxonNameBase homoTypicName) {
1135
		if (homoTypicName == null) {
1136
			return false;
1137
		}
1138
		HomotypicalGroup homotypicGroup = homoTypicName.getHomotypicalGroup();
1139
		if (homotypicGroup == null || this.getHomotypicalGroup() == null) {
1140
			return false;
1141
		}
1142
		if (homotypicGroup.equals(this.getHomotypicalGroup())) {
1143
			return true;
1144
		}
1145
		return false;
1146
	}
1147
	
1148
//*********  Rank comparison shortcuts   ********************//
1149
	/**
1150
	 * Returns the boolean value indicating whether the taxonomic {@link Rank rank} of <i>this</i>
1151
	 * taxon name is higher than the genus rank (true) or not (false).
1152
	 * Suprageneric non viral names are monomials.
1153
	 * Returns false if rank is null.
1154
	 * 
1155
	 * @see  #isGenus()
1156
	 * @see  #isInfraGeneric()
1157
	 * @see  #isSpecies()
1158
	 * @see  #isInfraSpecific()
1159
	 */
1160
	@Transient
1161
	public boolean isSupraGeneric() {
1162
		if (rank == null){
1163
			return false;
1164
		}
1165
		return getRank().isSupraGeneric();
1166
	}
1167
	/**
1168
	 * Returns the boolean value indicating whether the taxonomic {@link Rank rank} of <i>this</i>
1169
	 * taxon name is the genus rank (true) or not (false). Non viral names with
1170
	 * genus rank are monomials. Returns false if rank is null.
1171
	 *
1172
	 * @see  #isSupraGeneric()
1173
	 * @see  #isInfraGeneric()
1174
	 * @see  #isSpecies()
1175
	 * @see  #isInfraSpecific()
1176
	 */
1177
	@Transient
1178
	public boolean isGenus() {
1179
		if (rank == null){
1180
			return false;
1181
		}
1182
		return getRank().isGenus();
1183
	}
1184
	/**
1185
	 * Returns the boolean value indicating whether the taxonomic {@link Rank rank} of <i>this</i>
1186
	 * taxon name is higher than the species rank and lower than the
1187
	 * genus rank (true) or not (false). Infrageneric non viral names are
1188
	 * binomials. Returns false if rank is null.
1189
	 *
1190
	 * @see  #isSupraGeneric()
1191
	 * @see  #isGenus()
1192
	 * @see  #isSpecies()
1193
	 * @see  #isInfraSpecific()
1194
	 */
1195
	@Transient
1196
	public boolean isInfraGeneric() {
1197
		if (rank == null){
1198
			return false;
1199
		}
1200
		return getRank().isInfraGeneric();
1201
	}
1202
	/**
1203
	 * Returns the boolean value indicating whether the taxonomic {@link Rank rank} of <i>this</i>
1204
	 * taxon name is the species rank (true) or not (false). Non viral names
1205
	 * with species rank are binomials.
1206
	 * Returns false if rank is null.
1207
	 *
1208
	 * @see  #isSupraGeneric()
1209
	 * @see  #isGenus()
1210
	 * @see  #isInfraGeneric()
1211
	 * @see  #isInfraSpecific()
1212
	 */
1213
	@Transient
1214
	public boolean isSpecies() {
1215
		if (rank == null){
1216
			return false;
1217
		}
1218
		return getRank().isSpecies();
1219
	}
1220
	/**
1221
	 * Returns the boolean value indicating whether the taxonomic {@link Rank rank} of <i>this</i>
1222
	 * taxon name is lower than the species rank (true) or not (false).
1223
	 * Infraspecific non viral names are trinomials.
1224
	 * Returns false if rank is null.
1225
	 *
1226
	 * @see  #isSupraGeneric()
1227
	 * @see  #isGenus()
1228
	 * @see  #isInfraGeneric()
1229
	 * @see  #isSpecies()
1230
	 */
1231
	@Transient
1232
	public boolean isInfraSpecific() {
1233
		if (rank == null){
1234
			return false;
1235
		}
1236
		return getRank().isInfraSpecific();
1237
	}
1238
	
1239
	
1240
	/**
1241
	 * Returns null as the {@link NomenclaturalCode nomenclatural code} that governs
1242
	 * the construction of <i>this</i> taxon name since there is no specific
1243
	 * nomenclatural code defined. The real implementention takes place in the
1244
	 * subclasses {@link ViralName ViralName}, {@link BacterialName BacterialName},
1245
	 * {@link BotanicalName BotanicalName}, {@link CultivarPlantName CultivarPlantName} and
1246
	 * {@link ZoologicalName ZoologicalName}. Each taxon name is governed by one
1247
	 * and only one nomenclatural code. 
1248
	 *
1249
	 * @return  null
1250
	 * @see  	#isCodeCompliant()
1251
	 * @see  	#getHasProblem()
1252
	 */
1253
	abstract public NomenclaturalCode getNomenclaturalCode();
1254
	/* (non-Javadoc)
1255
	 * @see eu.etaxonomy.cdm.model.common.IdentifiableEntity#generateTitle()
1256
	 */
1257
	/**
1258
	 * Generates and returns the string with the scientific name of <i>this</i>
1259
	 * taxon name (only non viral taxon names can be generated from their
1260
	 * components). This string may be stored in the inherited
1261
	 * {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#getTitleCache() titleCache} attribute.
1262
	 * This method overrides the generic and inherited
1263
	 * {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity#generateTitle() method} from
1264
	 * {@link eu.etaxonomy.cdm.model.common.IdentifiableEntity IdentifiableEntity}.
1265
	 *
1266
	 * @return  the string with the composed name of this non viral taxon name with authorship (and maybe year)
1267
	 * @see  	eu.etaxonomy.cdm.model.common.IdentifiableEntity#generateTitle()
1268
	 * @see  	eu.etaxonomy.cdm.model.common.IdentifiableEntity#getTitleCache()
1269
	 */
1270
//	@Override
1271
//	public abstract String generateTitle();
1272
}
(19-19/25)