Project

General

Profile

Download (27.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
package eu.etaxonomy.cdm.strategy.cache.name;
10

    
11
import java.util.ArrayList;
12
import java.util.Iterator;
13
import java.util.List;
14
import java.util.Set;
15
import java.util.UUID;
16

    
17
import org.apache.commons.lang.StringUtils;
18
import org.apache.log4j.Logger;
19

    
20
import eu.etaxonomy.cdm.common.CdmUtils;
21
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
22
import eu.etaxonomy.cdm.model.agent.INomenclaturalAuthor;
23
import eu.etaxonomy.cdm.model.agent.Team;
24
import eu.etaxonomy.cdm.model.common.Language;
25
import eu.etaxonomy.cdm.model.common.Representation;
26
import eu.etaxonomy.cdm.model.name.BotanicalName;
27
import eu.etaxonomy.cdm.model.name.HybridRelationship;
28
import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
29
import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
30
import eu.etaxonomy.cdm.model.name.NonViralName;
31
import eu.etaxonomy.cdm.model.name.Rank;
32
import eu.etaxonomy.cdm.model.reference.INomenclaturalReference;
33
import eu.etaxonomy.cdm.strategy.TagEnum;
34
import eu.etaxonomy.cdm.strategy.TaggedText;
35
import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
36
import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImplRegExBase;
37

    
38

    
39
/**
40
 * This class is a default implementation for the INonViralNameCacheStrategy<T extends NonViralName> 
41
 * interface.<BR>
42
 * The method implements a cache strategy for botanical names so no method has to be overwritten by
43
 * a subclass for botanic names.
44
 * Where differing from this default botanic name strategy other subclasses should overwrite the
45
 * existing methods, e.g. a CacheStrategy for zoological names should overwrite getAuthorAndExAuthor
46
 * @author a.mueller
47
 */
48
/**
49
 * @author AM
50
 *
51
 * @param <T>
52
 */
53
public class NonViralNameDefaultCacheStrategy<T extends NonViralName> extends NameCacheStrategyBase<T> implements INonViralNameCacheStrategy<T> {
54
	private static final Logger logger = Logger.getLogger(NonViralNameDefaultCacheStrategy.class);
55
	
56
	final static UUID uuid = UUID.fromString("1cdda0d1-d5bc-480f-bf08-40a510a2f223");
57
	
58
	protected String NameAuthorSeperator = " ";
59
	protected String BasionymStart = "(";
60
	protected String BasionymEnd = ")";
61
	protected String ExAuthorSeperator = " ex ";
62
	protected CharSequence BasionymAuthorCombinationAuthorSeperator = " ";
63
	
64
	@Override
65
	public  UUID getUuid(){
66
		return uuid;
67
	}
68

    
69
	
70
	/**
71
	 * Factory method
72
	 * @return NonViralNameDefaultCacheStrategy A new instance of  NonViralNameDefaultCacheStrategy
73
	 */
74
	public static NonViralNameDefaultCacheStrategy NewInstance(){
75
		return new NonViralNameDefaultCacheStrategy();
76
	}
77
	
78
	/**
79
	 * Factory method
80
	 * @return NonViralNameDefaultCacheStrategy A new instance of  NonViralNameDefaultCacheStrategy
81
	 */
82
	public static <T extends NonViralName<?>> NonViralNameDefaultCacheStrategy<T> NewInstance(Class<T> clazz){
83
		return new NonViralNameDefaultCacheStrategy<T>();
84
	}
85
	
86
	/**
87
	 * Constructor
88
	 */
89
	protected NonViralNameDefaultCacheStrategy(){
90
		super();
91
	}
92

    
93
/* **************** GETTER / SETTER **************************************/
94
	
95
	/**
96
	 * String that separates the NameCache part from the AuthorCache part
97
	 * @return
98
	 */
99
	public String getNameAuthorSeperator() {
100
		return NameAuthorSeperator;
101
	}
102

    
103

    
104
	public void setNameAuthorSeperator(String nameAuthorSeperator) {
105
		NameAuthorSeperator = nameAuthorSeperator;
106
	}
107

    
108

    
109
	/**
110
	 * String the basionym author part starts with e.g. '('.
111
	 * This should correspond with the {@link NonViralNameDefaultCacheStrategy#getBasionymEnd() basionymEnd} attribute
112
	 * @return
113
	 */
114
	public String getBasionymStart() {
115
		return BasionymStart;
116
	}
117

    
118

    
119
	public void setBasionymStart(String basionymStart) {
120
		BasionymStart = basionymStart;
121
	}
122

    
123

    
124
	/**
125
	 * String the basionym author part ends with e.g. ')'.
126
	 * This should correspond with the {@link NonViralNameDefaultCacheStrategy#getBasionymStart() basionymStart} attribute
127
	 * @return
128
	 */
129
	public String getBasionymEnd() {
130
		return BasionymEnd;
131
	}
132

    
133

    
134
	public void setBasionymEnd(String basionymEnd) {
135
		BasionymEnd = basionymEnd;
136
	}
137

    
138

    
139
	/**
140
	 * String to seperate ex author from author.
141
	 * @return
142
	 */
143
	public String getExAuthorSeperator() {
144
		return ExAuthorSeperator;
145
	}
146

    
147

    
148
	public void setExAuthorSeperator(String exAuthorSeperator) {
149
		ExAuthorSeperator = exAuthorSeperator;
150
	}
151

    
152

    
153
	/**
154
	 * String that seperates the basionym/original_combination author part from the combination author part
155
	 * @return
156
	 */
157
	public CharSequence getBasionymAuthorCombinationAuthorSeperator() {
158
		return BasionymAuthorCombinationAuthorSeperator;
159
	}
160

    
161

    
162
	public void setBasionymAuthorCombinationAuthorSeperator( CharSequence basionymAuthorCombinationAuthorSeperator) {
163
		BasionymAuthorCombinationAuthorSeperator = basionymAuthorCombinationAuthorSeperator;
164
	}
165

    
166
	
167
//** *****************************************************************************************/
168

    
169
	/* (non-Javadoc)
170
	 * @see eu.etaxonomy.cdm.strategy.cache.name.NameCacheStrategyBase#getTitleCache(eu.etaxonomy.cdm.model.name.TaxonNameBase)
171
	 */
172
	@Override
173
	public String getTitleCache(T nonViralName) {
174
		List<TaggedText> tags = getTaggedTitle(nonViralName);
175
		if (tags == null){
176
			return null;
177
		}else{
178
			String result = createString(tags);
179
			return result;
180
		}
181
	}
182

    
183
	/* (non-Javadoc)
184
	 * @see eu.etaxonomy.cdm.strategy.cache.name.NameCacheStrategyBase#getFullTitleCache(eu.etaxonomy.cdm.model.name.TaxonNameBase)
185
	 */
186
	@Override
187
	public String getFullTitleCache(T nonViralName) {
188
		List<TaggedText> tags = getTaggedFullTitle(nonViralName);
189
		if (tags == null){
190
			return null;
191
		}else{
192
			String result = createString(tags);
193
			return result;
194
		}
195
	}
196

    
197
	
198
	/**
199
	 * Generates and returns the "name cache" (only scientific name without author teams and year).
200
	 * @see eu.etaxonomy.cdm.strategy.cache.name.INameCacheStrategy#getNameCache(eu.etaxonomy.cdm.model.name.TaxonNameBase)
201
	 */
202
	public String getNameCache(T nonViralName) {
203
		List<TaggedText> tags = getTaggedName(nonViralName);
204
		if (tags == null){
205
			return null;
206
		}else{
207
			String result = createString(tags);
208
			return result;
209
		}
210
	}
211
	
212

    
213
	/**
214
	 * Creates a string from tagged text.
215
	 * @param tags
216
	 * @return
217
	 */
218
	protected String createString(List<TaggedText> tags) {
219
		StringBuffer result = new StringBuffer();
220
		
221
		boolean isSeparator;
222
		boolean wasSeparator = true;  //true for start tag
223
		for (TaggedText tag: tags){
224
			isSeparator = tag.getType().equals(TagEnum.separator);
225
			if (! wasSeparator && ! isSeparator ){
226
				result.append(" ");
227
			}
228
			result.append(tag.getText());
229
			wasSeparator = isSeparator;
230
		}
231
		return result.toString();
232
	}
233
	
234
// ******************* Authorship ******************************/	
235
	
236

    
237
	/* (non-Javadoc)
238
	 * @see eu.etaxonomy.cdm.strategy.cache.INonViralNameCacheStrategy#getAuthorCache(eu.etaxonomy.cdm.model.name.NonViralName)
239
	 */
240
	public String getAuthorshipCache(T nonViralName) {
241
		if (nonViralName == null){
242
			return null;
243
		}
244
		//cache protected
245
		if (nonViralName.isProtectedAuthorshipCache() == true) {
246
			return nonViralName.getAuthorshipCache();
247
		}
248
		return getNonCacheAuthorshipCache(nonViralName);
249

    
250
	}
251
	
252
	/**
253
	 * Returns the authorshipcache string for the atomized authorship fields. Does not use the authorshipfield.
254
	 * @throws NullPointerException if nonViralName is null.
255
	 * @param nonViralName
256
	 * @return
257
	 */
258
	protected String getNonCacheAuthorshipCache(T nonViralName){
259
		String result = "";
260
		INomenclaturalAuthor combinationAuthor = nonViralName.getCombinationAuthorTeam();
261
		INomenclaturalAuthor exCombinationAuthor = nonViralName.getExCombinationAuthorTeam();
262
		INomenclaturalAuthor basionymAuthor = nonViralName.getBasionymAuthorTeam();
263
		INomenclaturalAuthor exBasionymAuthor = nonViralName.getExBasionymAuthorTeam();
264
		String basionymPart = "";
265
		String authorPart = "";
266
		//basionym
267
		if (basionymAuthor != null || exBasionymAuthor != null){
268
			basionymPart = BasionymStart + getAuthorAndExAuthor(basionymAuthor, exBasionymAuthor) + BasionymEnd;
269
		}
270
		if (combinationAuthor != null || exCombinationAuthor != null){
271
			authorPart = getAuthorAndExAuthor(combinationAuthor, exCombinationAuthor);
272
		}
273
		result = CdmUtils.concat(BasionymAuthorCombinationAuthorSeperator, basionymPart, authorPart);
274
		return result;
275
	}
276
	
277
	/**
278
	 * Returns the AuthorCache part for a combination of an author and an ex author. This applies on combination authors
279
	 * as well as on basionym/orginal combination authors.
280
	 * @param author the author
281
	 * @param exAuthor the ex-author
282
	 * @return
283
	 */
284
	protected String getAuthorAndExAuthor(INomenclaturalAuthor author, INomenclaturalAuthor exAuthor){
285
		String result = "";
286
		String authorString = "";
287
		String exAuthorString = "";
288
		if (author != null){
289
			authorString = CdmUtils.Nz(author.getNomenclaturalTitle());
290
		}
291
		if (exAuthor != null){
292
			exAuthorString = CdmUtils.Nz(exAuthor.getNomenclaturalTitle());
293
		}
294
		if (exAuthorString.length() > 0 ){
295
			exAuthorString = exAuthorString + ExAuthorSeperator;
296
		}
297
		result = exAuthorString + authorString;
298
		return result;
299
	}
300
	
301
	
302
	/**
303
	 * Checks if the given name should include the author in it's cached version.<BR>
304
	 * This is usually the case but not for <i>species aggregates</i>.
305
	 * @param nonViralName
306
	 * @return
307
	 */
308
	protected boolean nameIncludesAuthorship(NonViralName<?> nonViralName){
309
		Rank rank = nonViralName.getRank();
310
		if (rank != null && rank.isSpeciesAggregate()){
311
			return false;
312
		}else{
313
			return true;
314
		}
315
	}
316
	
317
// ************* TAGGED NAME ***************************************/	
318

    
319
	/* (non-Javadoc)
320
	 * @see eu.etaxonomy.cdm.strategy.cache.name.NameCacheStrategyBase#getTaggedFullTitle(eu.etaxonomy.cdm.model.name.TaxonNameBase)
321
	 */
322
	@Override
323
	public List<TaggedText> getTaggedFullTitle(T nonViralName) {
324
		List<TaggedText> tags = new ArrayList<TaggedText>();
325
		
326
		//null
327
		if (nonViralName == null){
328
			return null;
329
		}
330
		
331
		//protected full title cache
332
		if (nonViralName.isProtectedFullTitleCache()){
333
			tags.add(new TaggedText(TagEnum.fullName, nonViralName.getFullTitleCache()));
334
			return tags;
335
		}
336
		
337
		//title cache
338
//		String titleCache = nonViralName.getTitleCache();
339
		List<TaggedText> titleTags = getTaggedTitle(nonViralName);
340
		tags.addAll(titleTags);
341
		
342
		
343
		//reference
344
		String microReference = nonViralName.getNomenclaturalMicroReference();
345
		INomenclaturalReference ref = nonViralName.getNomenclaturalReference();
346
		String referenceBaseCache = null;
347
		if (ref != null){
348
			INomenclaturalReference nomenclaturalReference = HibernateProxyHelper.deproxy(ref, INomenclaturalReference.class);
349
			nomenclaturalReference.setCacheStrategy(nomenclaturalReference.getType().getCacheStrategy());
350
			referenceBaseCache = nomenclaturalReference.getNomenclaturalCitation(microReference);
351
		}
352
			//add to tags
353
		if (StringUtils.isNotBlank(referenceBaseCache)){
354
			if (! referenceBaseCache.trim().startsWith("in ")){
355
				String refConcat = ", ";
356
				tags.add(new TaggedText(TagEnum.separator, refConcat));
357
			}
358
			tags.add(new TaggedText(TagEnum.reference, referenceBaseCache));
359
		}
360
		
361
		//nomenclatural status
362
		Set<NomenclaturalStatus> ncStati = nonViralName.getStatus();
363
		Iterator<NomenclaturalStatus> iterator = ncStati.iterator();
364
		List<TaggedText> nomStatusTags = new ArrayList<TaggedText>();
365
		while (iterator.hasNext()) {
366
			NomenclaturalStatus ncStatus = (NomenclaturalStatus)iterator.next();
367
			// since the NewInstance method of nomencatural status allows null as parameter
368
			// we have to check for null values here
369
			String suffix = "not defined";
370
			if(ncStatus.getType() != null){
371
				NomenclaturalStatusType statusType =  ncStatus.getType();
372
				Language lang = Language.LATIN();
373
				Representation repr = statusType.getRepresentation(lang);
374
				if (repr != null){
375
					suffix = repr.getAbbreviatedLabel();
376
				}else{
377
					String message = "No latin representation available for nom. status. " + statusType.getTitleCache();
378
					logger.warn(message);
379
					throw new IllegalStateException(message);
380
				}
381
			}else if(ncStatus.getRuleConsidered() != null && ! ncStatus.getRuleConsidered().equals("")){
382
				suffix = ncStatus.getRuleConsidered();
383
			}
384
			String statusSeparator = ", ";
385
			nomStatusTags.add(new TaggedText(TagEnum.separator, statusSeparator));
386
			nomStatusTags.add(new TaggedText(TagEnum.nomStatus, suffix));
387
		}
388
		tags.addAll(nomStatusTags);
389
		return tags;
390
		
391
	}
392
		
393
	/* (non-Javadoc)
394
	 * @see eu.etaxonomy.cdm.strategy.cache.name.NameCacheStrategyBase#getTaggedTitle(eu.etaxonomy.cdm.model.name.TaxonNameBase)
395
	 */
396
	public List<TaggedText> getTaggedTitle(T nonViralName) {
397
		if (nonViralName == null){
398
			return null;
399
		}
400

    
401
		List<TaggedText> tags = new ArrayList<TaggedText>();
402
		
403
		//TODO how to handle protected fullTitleCache here?
404
		
405
		if (nonViralName.isProtectedTitleCache()){
406
			//protected title cache
407
			tags.add(new TaggedText(TagEnum.name, nonViralName.getTitleCache()));
408
			return tags;
409
		}else if (nonViralName.isHybridFormula()){
410
			//hybrid formula
411
			String hybridSeparator = NonViralNameParserImplRegExBase.hybridSign;
412
			boolean isFirst = true;
413
			List<HybridRelationship> rels = nonViralName.getOrderedChildRelationships();
414
			for (HybridRelationship rel: rels){
415
				if (! isFirst){
416
					tags.add(new TaggedText(TagEnum.hybridSign, hybridSeparator));
417
				}
418
				isFirst = false;
419
				tags.addAll(getTaggedTitle((T)rel.getParentName()));
420
			}
421
			return tags;
422
		}else if (nonViralName.isAutonym()){
423
			//Autonym
424
			tags.addAll(handleTaggedAutonym(nonViralName));
425
		}else{ //not Autonym
426
//			String nameCache = nonViralName.getNameCache();  //OLD: CdmUtils.Nz(getNameCache(nonViralName));
427
			List<TaggedText> nameTags = getTaggedName(nonViralName);
428
			tags.addAll(nameTags);
429
			if (nameIncludesAuthorship(nonViralName)){
430
				String authorCache = getAuthorshipCache(nonViralName);
431
				if (StringUtils.isNotBlank(authorCache)){
432
					tags.add(new TaggedText(TagEnum.authors, authorCache));
433
				}
434
			}
435
		}
436
		return tags;
437

    
438
	}
439
	
440
	
441
	/**
442
	 * Returns the tag list of the name part (without author and reference).
443
	 * @param nonViralName
444
	 * @return
445
	 */
446
	public List<TaggedText> getTaggedName(T nonViralName) {
447
		if (nonViralName == null){
448
			return null;
449
		}
450
		List<TaggedText> tags = new ArrayList<TaggedText>();
451
		Rank rank = nonViralName.getRank();
452
		
453
		if (nonViralName.isProtectedNameCache()){
454
			tags.add(new TaggedText(TagEnum.name, nonViralName.getNameCache()));
455
		}else if (rank == null){
456
			tags = getRanklessTaggedNameCache(nonViralName);
457
//		}else if (nonViralName.isInfragenericUnranked()){
458
//			result = getUnrankedInfragenericNameCache(nonViralName);
459
		}else if (rank.isInfraSpecific()){
460
			tags = getInfraSpeciesTaggedNameCache(nonViralName);
461
		}else if (rank.isSpecies()){
462
			tags = getSpeciesTaggedNameCache(nonViralName);
463
		}else if (rank.isInfraGeneric()){
464
			tags = getInfraGenusTaggedNameCache(nonViralName);
465
		}else if (rank.isGenus()){
466
			tags = getGenusOrUninomialTaggedNameCache(nonViralName);
467
		}else if (rank.isSupraGeneric()){
468
			tags = getGenusOrUninomialTaggedNameCache(nonViralName);
469
		}else{ 
470
			logger.warn("Name Strategy for Name (UUID: " + nonViralName.getUuid() +  ") not yet implemented");
471
		}
472
		//TODO handle appended phrase here instead of different places, check first if this is true for all
473
		//cases
474
		
475
		return tags;
476

    
477
	}
478

    
479

    
480
	
481

    
482
//***************************** PRIVATES ***************************************/
483
	
484

    
485
	/**
486
	 * Returns the tag list for an autonym taxon.
487
	 * 
488
	 * @see NonViralName#isAutonym()
489
	 * @see BotanicalName#isAutonym()
490
	 * @param nonViralName
491
	 * @return
492
	 */
493
	private List<TaggedText> handleTaggedAutonym(T nonViralName) {
494
		
495
		//species part
496
		List<TaggedText> tags = getSpeciesTaggedNameCache(nonViralName);
497
		
498
		//author
499
		//TODO should this include basionym authors and ex authors
500
		INomenclaturalAuthor author = nonViralName.getCombinationAuthorTeam();
501
		String authorPart = "";
502
		if (author != null){
503
			authorPart = CdmUtils.Nz(author.getNomenclaturalTitle());
504
		}
505
		INomenclaturalAuthor basAuthor = nonViralName.getBasionymAuthorTeam();
506
		String basAuthorPart = "";
507
		if (basAuthor != null){
508
			basAuthorPart = CdmUtils.Nz(basAuthor.getNomenclaturalTitle());
509
		}
510
		if (! "".equals(basAuthorPart)){
511
			authorPart = "("+ basAuthorPart +") " + authorPart;
512
		}
513
		if (StringUtils.isNotBlank(authorPart)){
514
			tags.add(new TaggedText(TagEnum.authors, authorPart));
515
		}
516
		
517
		
518
		//infra species marker
519
		if (nonViralName.getRank() == null || !nonViralName.getRank().isInfraSpecific()){
520
			//TODO handle exception
521
			logger.warn("Rank for autonym does not exist or is not lower than species !!");
522
		}else{
523
			String infraSpeciesMarker = nonViralName.getRank().getAbbreviation();
524
			if (StringUtils.isNotBlank(infraSpeciesMarker)){
525
				tags.add(new TaggedText(TagEnum.rank, infraSpeciesMarker));
526
			}
527
		}
528
		
529
		//infra species
530
		String infraSpeciesPart = CdmUtils.Nz(nonViralName.getInfraSpecificEpithet()).trim().replace("null", "");
531
		if (StringUtils.isNotBlank(infraSpeciesPart)){
532
			tags.add(new TaggedText(TagEnum.name, infraSpeciesPart));
533
		}
534
		
535
		return tags;
536
	}
537
	
538
	
539
	
540
	/**
541
	 * Returns the tag list for rankless taxa.
542
	 * @param nonViralName
543
	 * @return
544
	 */
545
	protected List<TaggedText> getRanklessTaggedNameCache(NonViralName<?> nonViralName){
546
		List<TaggedText> tags = getUninomialTaggedPart(nonViralName);
547
		String speciesEpi = CdmUtils.Nz(nonViralName.getSpecificEpithet()).trim().replace("null", "");
548
		if (StringUtils.isNotBlank(speciesEpi)){
549
			tags.add(new TaggedText(TagEnum.name, speciesEpi));
550
		}
551
		
552
		String infraSpeciesEpi = CdmUtils.Nz(nonViralName.getInfraSpecificEpithet()).trim().replace("null", "");
553
		if (StringUtils.isNotBlank(infraSpeciesEpi)){
554
			tags.add(new TaggedText(TagEnum.name, infraSpeciesEpi));
555
		}
556
		
557
		//result += " (rankless)";
558
		addAppendedTaggedPhrase(tags, nonViralName);
559
		return tags;			
560
	}
561

    
562
	/**
563
	 * Returns the tag list for the first epithet (including a hybrid sign if required).
564
	 * @param nonViralName
565
	 * @return
566
	 */
567
	private List<TaggedText> getUninomialTaggedPart(NonViralName<?> nonViralName) {
568
		List<TaggedText> tags = new ArrayList<TaggedText>();
569
		
570
		if (nonViralName.isMonomHybrid()){
571
			addHybridPrefix(tags);
572
		}
573
		
574
		String uninomial = CdmUtils.Nz(nonViralName.getGenusOrUninomial()).trim().replace("null", "");
575
		if (StringUtils.isNotBlank(uninomial)){
576
			tags.add(new TaggedText(TagEnum.name, uninomial));
577
		}
578
			
579
		return tags;
580
	}
581
	
582
	/**
583
	 * Returns the tag list for an genus or higher taxon.
584
	 * 
585
	 * @param nonViralName
586
	 * @return
587
	 */
588
	protected List<TaggedText> getGenusOrUninomialTaggedNameCache(NonViralName<?> nonViralName){
589
		List<TaggedText> tags = getUninomialTaggedPart(nonViralName);
590
		addAppendedTaggedPhrase(tags, nonViralName);
591
		return tags;
592
	}
593
	
594
	/**
595
	 * Returns the tag list for an infrageneric taxon (including species aggregates).
596
	 * 
597
	 * @see #getSpeciesAggregateTaggedCache(NonViralName)
598
	 * @param nonViralName
599
	 * @return
600
	 */
601
	protected List<TaggedText> getInfraGenusTaggedNameCache(NonViralName<?> nonViralName){
602
		Rank rank = nonViralName.getRank();
603
		if (rank.isSpeciesAggregate()){
604
			return getSpeciesAggregateTaggedCache(nonViralName);
605
		}
606
		
607
		//genus
608
		List<TaggedText> tags = getUninomialTaggedPart(nonViralName);
609
		
610
		//marker
611
		String infraGenericMarker = "'unhandled infrageneric rank'";
612
		if (rank != null){
613
			try {
614
				infraGenericMarker = rank.getInfraGenericMarker();
615
			} catch (UnknownCdmTypeException e) {
616
				infraGenericMarker = "'unhandled infrageneric rank'";
617
			}
618
		}
619
		tags.add(new TaggedText(TagEnum.rank, infraGenericMarker));
620
		
621
		
622
		String infraGenEpi = CdmUtils.Nz(nonViralName.getInfraGenericEpithet()).trim().replace("null", "");
623
		if (StringUtils.isNotBlank(infraGenEpi)){
624
			tags.add(new TaggedText(TagEnum.name, infraGenEpi));
625
		}
626
		
627
		addAppendedTaggedPhrase(tags, nonViralName);
628
		return tags;
629
	}
630
	
631
	/**
632
	 * Returns the tag list for a species aggregate (or similar) taxon.<BR>
633
	 * Possible ranks for a <i>species aggregate</i> are "aggr.", "species group", ...	
634
	 * @param nonViralName
635
	 * @return
636
	 */
637
	protected List<TaggedText> getSpeciesAggregateTaggedCache(NonViralName<?> nonViralName){
638
		List<TaggedText> tags = getGenusAndSpeciesTaggedPart(nonViralName);
639
		
640
		addSpeciesAggregateTaggedEpithet(tags, nonViralName);
641
		addAppendedTaggedPhrase(tags, nonViralName);
642
		return tags;
643
	}
644
	
645
	/**
646
	 * Adds the aggregate tag to the tag list.
647
	 * @param tags
648
	 * @param nonViralName
649
	 */
650
	private void addSpeciesAggregateTaggedEpithet(List<TaggedText> tags, NonViralName<?> nonViralName) {
651
		String marker;
652
		try {
653
			marker = nonViralName.getRank().getInfraGenericMarker();
654
		} catch (UnknownCdmTypeException e) {
655
			marker = "'unknown aggregat type'";
656
		}
657
		if (StringUtils.isNotBlank(marker)){
658
			tags.add(new TaggedText(TagEnum.rank, marker));
659
		}
660
	}
661

    
662
	
663
	/**
664
	 * Returns the tag list for a species taxon.
665
	 * @param nonViralName
666
	 * @return
667
	 */
668
	protected List<TaggedText> getSpeciesTaggedNameCache(NonViralName<?> nonViralName){
669
		List<TaggedText> tags = getGenusAndSpeciesTaggedPart(nonViralName);
670
		addAppendedTaggedPhrase(tags, nonViralName);
671
		return tags;
672
	}
673

    
674
	/**
675
	 * Creates the tag list for an infraspecific taxon. In include is true the result will contain
676
	 * @param nonViralName
677
	 * @return
678
	 */
679
	protected List<TaggedText> getInfraSpeciesTaggedNameCache(NonViralName<?> nonViralName){
680
		return getInfraSpeciesTaggedNameCache(nonViralName, true);
681
	}
682
	
683
	/**
684
	 * Creates the tag list for an infraspecific taxon. In include is true the result will contain
685
	 * the infraspecific marker (e.g. "var.")
686
	 * @param nonViralName
687
	 * @param includeMarker
688
	 * @return
689
	 */
690
	protected List<TaggedText> getInfraSpeciesTaggedNameCache(NonViralName<?> nonViralName, boolean includeMarker){
691
		List<TaggedText> tags = getGenusAndSpeciesTaggedPart(nonViralName);
692
		if (includeMarker){ 
693
			String marker = (nonViralName.getRank().getAbbreviation()).trim().replace("null", "");
694
			if (StringUtils.isNotBlank(marker)){
695
				tags.add(new TaggedText(TagEnum.rank, marker));
696
			}
697
		}
698
		String infrSpecEpi = CdmUtils.Nz(nonViralName.getInfraSpecificEpithet());
699
		if (nonViralName.isTrinomHybrid()){
700
			addHybridPrefix(tags);
701
		}
702
		
703
		infrSpecEpi = infrSpecEpi.trim().replace("null", "");
704
		if (StringUtils.isNotBlank(infrSpecEpi)){
705
			tags.add(new TaggedText(TagEnum.name, infrSpecEpi));
706
		}
707
		
708
		addAppendedTaggedPhrase(tags, nonViralName);
709
		return tags;
710
	}
711

    
712

    
713
	/**
714
	 * Adds a tag for the hybrid sign and an empty separator to avoid trailing whitespaces.
715
	 * @param tags
716
	 */
717
	private void addHybridPrefix(List<TaggedText> tags) {
718
		tags.add(new TaggedText(TagEnum.hybridSign, NonViralNameParserImplRegExBase.hybridSign));
719
		tags.add(new TaggedText(TagEnum.separator, "")); //no whitespace separator
720
	}
721

    
722
	/**
723
	 * Creates the tag list for the genus and species part.
724
	 * @param nonViralName
725
	 * @return
726
	 */
727
	private List<TaggedText> getGenusAndSpeciesTaggedPart(NonViralName<?> nonViralName) {
728
		//Uninomial
729
		List<TaggedText> tags = getUninomialTaggedPart(nonViralName);
730
		
731
		//InfraGenericEpi
732
		boolean hasInfraGenericEpi = StringUtils.isNotBlank(nonViralName.getInfraGenericEpithet());
733
		if (hasInfraGenericEpi){
734
			String infrGenEpi = nonViralName.getInfraGenericEpithet().trim();
735
			if (nonViralName.isBinomHybrid()){
736
//					addHybridPrefix(tags);  FIXME hybridSign should be tag, but then we need to handle "(" ")" differently.
737
				infrGenEpi = NonViralNameParserImplRegExBase.hybridSign + infrGenEpi;
738
			}
739
			infrGenEpi = "(" + infrGenEpi + ")";
740
			tags.add(new TaggedText(TagEnum.name, infrGenEpi));
741
		}
742

    
743
		//Species Epi
744
		String specEpi = CdmUtils.Nz(nonViralName.getSpecificEpithet()).trim().replace("null", "");
745
		if (! hasInfraGenericEpi && nonViralName.isBinomHybrid() || 
746
				hasInfraGenericEpi && nonViralName.isTrinomHybrid()){
747
			addHybridPrefix(tags); 
748
		}
749
		if (StringUtils.isNotBlank(specEpi)){
750
			tags.add(new TaggedText(TagEnum.name, specEpi));
751
		}
752
		return tags;
753
	}
754
	
755
	/**
756
	 * Adds the tag for the appended phrase if an appended phrase exists
757
	 * @param tags
758
	 * @param nonViralName
759
	 */
760
	protected void addAppendedTaggedPhrase(List<TaggedText> tags, NonViralName<?> nonViralName){
761
		String appendedPhrase = nonViralName ==null ? null : nonViralName.getAppendedPhrase();
762
		if (StringUtils.isNotEmpty(appendedPhrase)){
763
			tags.add(new TaggedText(TagEnum.name, appendedPhrase));
764
		}
765
	}
766

    
767
	public String getLastEpithet(T taxonNameBase) {
768
		Rank rank = taxonNameBase.getRank();
769
		if(rank.isGenus() || rank.isSupraGeneric()) {
770
			return taxonNameBase.getGenusOrUninomial();
771
		} else if(rank.isInfraGeneric()) {
772
			return taxonNameBase.getInfraGenericEpithet();
773
		} else if(rank.isSpecies()) {
774
			return taxonNameBase.getSpecificEpithet();
775
		} else {
776
			return taxonNameBase.getInfraSpecificEpithet();
777
		}
778
	}
779
	
780
// *************************** DEPRECATED ***************************************************/
781
	
782

    
783
	//Old: may be replaced once getTagged(Full)Title is fully tested
784
	/* (non-Javadoc)
785
	 * @see eu.etaxonomy.cdm.strategy.INameCacheStrategy#getTaggedName(eu.etaxonomy.cdm.model.common.CdmBase)
786
	 */
787
	@Override
788
	@Deprecated
789
	public List<Object> getTaggedNameDeprecated(T nonViralName) {
790
		List<Object> tags = new ArrayList<Object>();
791
		
792
		if (nonViralName.isProtectedNameCache() ||
793
				nonViralName.isProtectedAuthorshipCache() ||
794
				nonViralName.isProtectedFullTitleCache() ||
795
				nonViralName.isProtectedTitleCache()){
796
			tags.add(nonViralName.getTitleCache());
797
			return tags;
798
		}
799
		
800
		// Why does it make sense to add the nameCache in case of non existing genusOrUninomial?
801
//		if (nonViralName.getGenusOrUninomial() == null){
802
//			tags.add(nonViralName.getNameCache());
803
//		}else{
804
		
805
		if (nonViralName.getGenusOrUninomial() != null) {
806
			tags.add(nonViralName.getGenusOrUninomial());
807
		}
808
		if (nonViralName.isSpecies() || nonViralName.isInfraSpecific()){
809
			tags.add(nonViralName.getSpecificEpithet());			
810
		}
811
		
812
		// No autonym 
813
		if (nonViralName.isInfraSpecific() && ! nonViralName.getSpecificEpithet().equals(nonViralName.getInfraSpecificEpithet())){
814
			tags.add(nonViralName.getRank());			
815
			tags.add(nonViralName.getInfraSpecificEpithet());			
816
		}
817
		
818
		if (nonViralName.isInfraGeneric()){
819
			//TODO choose right strategy or generic approach?
820
			// --- strategy 1 --- 
821
					
822
			if (nonViralName.getRank().isSpeciesAggregate()){
823
				tags.add(nonViralName.getSpecificEpithet());
824
				tags.add(getSpeciesAggregateEpithet(nonViralName));
825
			}else{
826
				tags.add(nonViralName.getRank());	
827
				tags.add(nonViralName.getInfraGenericEpithet());	
828
			}
829
			// --- strategy 2 --- 
830
//			tags.add('('+nvn.getInfraGenericEpithet()+')');	
831
		}
832
		Team authorTeam = Team.NewInstance();
833
		authorTeam.setProtectedTitleCache(true);
834
		authorTeam.setTitleCache(nonViralName.getAuthorshipCache(), true);
835
		tags.add(authorTeam);
836
		
837
		// Name is an autonym. Rank and infraspecific epitheton follow the author
838
		if (nonViralName.isInfraSpecific() && nonViralName.getSpecificEpithet().equals(nonViralName.getInfraSpecificEpithet())){
839
			tags.add(nonViralName.getRank());			
840
			tags.add(nonViralName.getInfraSpecificEpithet());			
841
		}
842
		
843
		if(! "".equals(nonViralName.getAppendedPhrase())&& (nonViralName.getAppendedPhrase() != null)){
844
			tags.add(nonViralName.getAppendedPhrase());
845
		}
846
		
847
		return tags;
848
	}
849
	
850
	
851
	/**
852
	 * @deprecated use only for {@link #getTaggedNameDeprecated(NonViralName)}. Delete when the later 
853
	 * is deleted.
854
	 */
855
	@Deprecated 
856
	private String getSpeciesAggregateEpithet(NonViralName<?> nonViralName) {
857
		String marker;
858
		try {
859
			marker = nonViralName.getRank().getInfraGenericMarker();
860
		} catch (UnknownCdmTypeException e) {
861
			marker = "'unknown aggregat type'";
862
		}
863
		return marker;
864
	}
865

    
866
	
867
}
(7-7/8)