Project

General

Profile

Download (36.3 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.HybridRelationship;
27
import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
28
import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
29
import eu.etaxonomy.cdm.model.name.NonViralName;
30
import eu.etaxonomy.cdm.model.name.Rank;
31
import eu.etaxonomy.cdm.model.reference.INomenclaturalReference;
32
import eu.etaxonomy.cdm.strategy.TagEnum;
33
import eu.etaxonomy.cdm.strategy.TaggedText;
34
import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
35
import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImplRegExBase;
36

    
37

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

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

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

    
101

    
102
	public void setNameAuthorSeperator(String nameAuthorSeperator) {
103
		NameAuthorSeperator = nameAuthorSeperator;
104
	}
105

    
106

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

    
116

    
117
	public void setBasionymStart(String basionymStart) {
118
		BasionymStart = basionymStart;
119
	}
120

    
121

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

    
131

    
132
	public void setBasionymEnd(String basionymEnd) {
133
		BasionymEnd = basionymEnd;
134
	}
135

    
136

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

    
145

    
146
	public void setExAuthorSeperator(String exAuthorSeperator) {
147
		ExAuthorSeperator = exAuthorSeperator;
148
	}
149

    
150

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

    
159

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

    
165
	
166
//** *****************************************************************************************/
167

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

    
182
	
183
	
184
	public String getTitleCache_OLD(T nonViralName) {
185
		if (nonViralName == null){
186
			return null;
187
		}
188
		
189
		if (nonViralName.isProtectedTitleCache()){
190
			return nonViralName.getTitleCache();
191
		}
192
		String result = "";
193
		if (nonViralName.isHybridFormula()){
194
			//hybrid formula
195
			result = null;
196
			String hybridSeparator = " " + NonViralNameParserImplRegExBase.hybridSign + " ";
197
			List<HybridRelationship> rels = nonViralName.getOrderedChildRelationships();
198
			for (HybridRelationship rel: rels){
199
				result = CdmUtils.concat(hybridSeparator, result, rel.getParentName().getTitleCache()).trim();
200
			}
201
			return result;
202
		}else if (nonViralName.isAutonym()){
203
			//Autonym
204
			result = handleAutonym(nonViralName);
205
		}else{ //not Autonym
206
			String nameCache = nonViralName.getNameCache();  //OLD: CdmUtils.Nz(getNameCache(nonViralName));
207
			if (nameIncludesAuthorship(nonViralName)){
208
				String authorCache = CdmUtils.Nz(getAuthorshipCache(nonViralName));
209
				result = CdmUtils.concat(NameAuthorSeperator, nameCache, authorCache);
210
			}else{
211
				result = nameCache;
212
			}
213
		}
214
		return result;
215
	}
216

    
217

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

    
239

    
240
	/**
241
	 * @param nonViralName
242
	 * @param speciesPart
243
	 * @return
244
	 */
245
	private List<TaggedText> handleTaggedAutonym(T nonViralName) {
246
		
247
		//species part
248
		List<TaggedText> tags = getSpeciesTaggedNameCache(nonViralName);
249
		
250
		//author
251
		//TODO should this include basionym authors and ex authors
252
		INomenclaturalAuthor author = nonViralName.getCombinationAuthorTeam();
253
		String authorPart = "";
254
		if (author != null){
255
			authorPart = CdmUtils.Nz(author.getNomenclaturalTitle());
256
		}
257
		INomenclaturalAuthor basAuthor = nonViralName.getBasionymAuthorTeam();
258
		String basAuthorPart = "";
259
		if (basAuthor != null){
260
			basAuthorPart = CdmUtils.Nz(basAuthor.getNomenclaturalTitle());
261
		}
262
		if (! "".equals(basAuthorPart)){
263
			authorPart = "("+ basAuthorPart +") " + authorPart;
264
		}
265
		if (StringUtils.isNotBlank(authorPart)){
266
			tags.add(new TaggedText(TagEnum.authors, authorPart));
267
		}
268
		
269
		
270
		//infra species marker
271
		if (nonViralName.getRank() == null || !nonViralName.getRank().isInfraSpecific()){
272
			//TODO handle exception
273
			logger.warn("Rank for autonym does not exist or is not lower than species !!");
274
		}else{
275
			String infraSpeciesMarker = nonViralName.getRank().getAbbreviation();
276
			if (StringUtils.isNotBlank(infraSpeciesMarker)){
277
				tags.add(new TaggedText(TagEnum.rank, infraSpeciesMarker));
278
			}
279
		}
280
		
281
		//infra species
282
		String infraSpeciesPart = CdmUtils.Nz(nonViralName.getInfraSpecificEpithet()).trim().replace("null", "");
283
		if (StringUtils.isNotBlank(infraSpeciesPart)){
284
			tags.add(new TaggedText(TagEnum.name, infraSpeciesPart));
285
		}
286
		
287
		return tags;
288
	}
289
	
290
	/**
291
	 * @param nonViralName
292
	 * @param speciesPart
293
	 * @return
294
	 */
295
	private String handleAutonym(T nonViralName) {
296
		String result;
297
		String speciesPart = getSpeciesNameCache(nonViralName);
298
		//TODO should this include basionym authors and ex authors
299
		INomenclaturalAuthor author = nonViralName.getCombinationAuthorTeam();
300
		String authorPart = "";
301
		if (author != null){
302
			authorPart = CdmUtils.Nz(author.getNomenclaturalTitle());
303
		}
304
		INomenclaturalAuthor basAuthor = nonViralName.getBasionymAuthorTeam();
305
		String basAuthorPart = "";
306
		if (basAuthor != null){
307
			basAuthorPart = CdmUtils.Nz(basAuthor.getNomenclaturalTitle());
308
		}
309
		if (! "".equals(basAuthorPart)){
310
			authorPart = "("+ basAuthorPart +") " + authorPart;
311
		}
312
		String infraSpeciesPart = (CdmUtils.Nz(nonViralName.getInfraSpecificEpithet()));
313

    
314
		String infraSpeciesSeparator = "";
315
		if (nonViralName.getRank() == null || !nonViralName.getRank().isInfraSpecific()){
316
			//TODO handle exception
317
			logger.warn("Rank for autonym does not exist or is not lower than species !!");
318
		}else{
319
			infraSpeciesSeparator = nonViralName.getRank().getAbbreviation();
320
		}
321
		
322
		result = CdmUtils.concat(" ", new String[]{speciesPart, authorPart, infraSpeciesSeparator, infraSpeciesPart});
323
		result = result.trim().replace("null", "");
324
		return result;
325
	}
326
	
327
	protected boolean nameIncludesAuthorship(NonViralName<?> nonViralName){
328
		Rank rank = nonViralName.getRank();
329
		if (rank != null && rank.isSpeciesAggregate()){
330
			return false;
331
		}else{
332
			return true;
333
		}
334
	}
335
	
336
	/* (non-Javadoc)
337
	 * @see eu.etaxonomy.cdm.strategy.cache.name.NameCacheStrategyBase#getFullTitleCache(eu.etaxonomy.cdm.model.name.TaxonNameBase)
338
	 */
339
	@Override
340
	public String getFullTitleCache(T nonViralName) {
341
		List<TaggedText> tags = getTaggedFullTitle(nonViralName);
342
		if (tags == null){
343
			return null;
344
		}else{
345
			String result = createString(tags);
346
			return result;
347
		}
348
	}
349
	
350
	
351
	public String getFullTitleCache_OLD(T nonViralName) {
352
		//null
353
		if (nonViralName == null){
354
			return null;
355
		}
356
		//full title cache
357
		if (nonViralName.isProtectedFullTitleCache() == true) {
358
			return nonViralName.getFullTitleCache();
359
		}
360
		
361
		String result = "";
362
		//title cache
363
		String titleCache = nonViralName.getTitleCache();   // OLD: getTitleCache(nonViralName);
364
		
365
		String microReference = nonViralName.getNomenclaturalMicroReference();
366
		INomenclaturalReference ref = nonViralName.getNomenclaturalReference();
367
		String referenceBaseCache = null;
368
		if (ref != null){
369
			INomenclaturalReference nomenclaturalReference = HibernateProxyHelper.deproxy(ref, INomenclaturalReference.class);
370
			nomenclaturalReference.setCacheStrategy(nomenclaturalReference.getType().getCacheStrategy());
371
			referenceBaseCache = nomenclaturalReference.getNomenclaturalCitation(microReference);
372
		}
373
		
374
		//make nomenclatural status
375
		String ncStatusCache = "";
376
		Set<NomenclaturalStatus> ncStati = nonViralName.getStatus();
377
		Iterator<NomenclaturalStatus> iterator = ncStati.iterator();
378
		while (iterator.hasNext()) {
379
			NomenclaturalStatus ncStatus = (NomenclaturalStatus)iterator.next();
380
			// since the NewInstance method of nomencatural status allows null as parameter
381
			// we have to check for null values here
382
			String suffix = "not defined";
383
			if(ncStatus.getType() != null){
384
				NomenclaturalStatusType statusType =  ncStatus.getType();
385
				Language lang = Language.LATIN();
386
				Representation repr = statusType.getRepresentation(lang);
387
				if (repr != null){
388
					suffix = repr.getAbbreviatedLabel();
389
				}else{
390
					String message = "No latin representation available for nom. status. " + statusType.getTitleCache();
391
					logger.warn(message);
392
					throw new IllegalStateException(message);
393
				}
394
			}else if(ncStatus.getRuleConsidered() != null && ! ncStatus.getRuleConsidered().equals("")){
395
				suffix = ncStatus.getRuleConsidered();
396
			}
397
			ncStatusCache = ", " + suffix;
398
		}
399
		String refConcat = " ";
400
		if (referenceBaseCache != null && ! referenceBaseCache.trim().startsWith("in ")){
401
			refConcat = ", ";
402
		}
403
		result = CdmUtils.concat(refConcat, titleCache, referenceBaseCache);
404
		result = CdmUtils.concat("", result, ncStatusCache);
405
		return result;
406
	}
407
	
408

    
409
	
410
	/**
411
	 * Generates and returns the "name cache" (only scientific name without author teams and year).
412
	 * @see eu.etaxonomy.cdm.strategy.cache.name.INameCacheStrategy#getNameCache(eu.etaxonomy.cdm.model.name.TaxonNameBase)
413
	 */
414
	public String getNameCache(T nonViralName) {
415
		List<TaggedText> tags = getNameTags(nonViralName);
416
		if (tags == null){
417
			return null;
418
		}else{
419
			String result = createString(tags);
420
			return result;
421
		}
422
	}
423
	
424
	public String getNameCache_OLD(T nonViralName) {
425
		if (nonViralName == null){
426
			return null;
427
		}
428
		String result;
429
		Rank rank = nonViralName.getRank();
430
		
431
		if (nonViralName.isProtectedNameCache()){
432
			result = nonViralName.getNameCache();
433
		}else if (rank == null){
434
			result = getRanklessNameCache(nonViralName);
435
//		}else if (nonViralName.isInfragenericUnranked()){
436
//			result = getUnrankedInfragenericNameCache(nonViralName);
437
		}else if (rank.isInfraSpecific()){
438
			result = getInfraSpeciesNameCache(nonViralName);
439
		}else if (rank.isSpecies()){
440
			result = getSpeciesNameCache(nonViralName);
441
		}else if (rank.isInfraGeneric()){
442
			result = getInfraGenusNameCache(nonViralName);
443
		}else if (rank.isGenus()){
444
			result = getGenusOrUninomialNameCache(nonViralName);
445
		}else if (rank.isSupraGeneric()){
446
			result = getGenusOrUninomialNameCache(nonViralName);
447
		}else{ 
448
			logger.warn("Name Strategy for Name (UUID: " + nonViralName.getUuid() +  ") not yet implemented");
449
			result = "";
450
		}
451
		return result;
452
	}
453

    
454

    
455
	private String getUnrankedInfragenericNameCache(T nonViralName) {
456
		String result;
457
		Rank rank = nonViralName.getRank();
458
		if (rank.isSpeciesAggregate()){
459
			return getSpeciesAggregateCache(nonViralName);
460
		}
461
		String infraGenericMarker = rank.getAbbreviation();
462
		result = CdmUtils.Nz(nonViralName.getGenusOrUninomial()).trim();
463
		result += " " + infraGenericMarker + " " + (CdmUtils.Nz(nonViralName.getInfraGenericEpithet())).trim().replace("null", "");
464
		result = addAppendedPhrase(result, nonViralName).trim();
465
		return result; 
466
	}
467

    
468

    
469
	/* (non-Javadoc)
470
	 * @see eu.etaxonomy.cdm.strategy.cache.INonViralNameCacheStrategy#getAuthorCache(eu.etaxonomy.cdm.model.name.NonViralName)
471
	 */
472
	public String getAuthorshipCache(T nonViralName) {
473
		if (nonViralName == null){
474
			return null;
475
		}
476
		//cache protected
477
		if (nonViralName.isProtectedAuthorshipCache() == true) {
478
			return nonViralName.getAuthorshipCache();
479
		}
480
		return getNonCacheAuthorshipCache(nonViralName);
481

    
482
	}
483
	
484
	/**
485
	 * Returns the authorshipcache string for the atomized authorship fields. Does not use the authorshipfield.
486
	 * @throws NullPointerException if nonViralName is null.
487
	 * @param nonViralName
488
	 * @return
489
	 */
490
	protected String getNonCacheAuthorshipCache(T nonViralName){
491
		String result = "";
492
		INomenclaturalAuthor combinationAuthor = nonViralName.getCombinationAuthorTeam();
493
		INomenclaturalAuthor exCombinationAuthor = nonViralName.getExCombinationAuthorTeam();
494
		INomenclaturalAuthor basionymAuthor = nonViralName.getBasionymAuthorTeam();
495
		INomenclaturalAuthor exBasionymAuthor = nonViralName.getExBasionymAuthorTeam();
496
		String basionymPart = "";
497
		String authorPart = "";
498
		//basionym
499
		if (basionymAuthor != null || exBasionymAuthor != null){
500
			basionymPart = BasionymStart + getAuthorAndExAuthor(basionymAuthor, exBasionymAuthor) + BasionymEnd;
501
		}
502
		if (combinationAuthor != null || exCombinationAuthor != null){
503
			authorPart = getAuthorAndExAuthor(combinationAuthor, exCombinationAuthor);
504
		}
505
		result = CdmUtils.concat(BasionymAuthorCombinationAuthorSeperator, basionymPart, authorPart);
506
		return result;
507
	}
508
	
509
	/**
510
	 * Returns the AuthorCache part for a combination of an author and an ex author. This applies on combination authors
511
	 * as well as on basionym/orginal combination authors.
512
	 * @param author the author
513
	 * @param exAuthor the ex-author
514
	 * @return
515
	 */
516
	protected String getAuthorAndExAuthor(INomenclaturalAuthor author, INomenclaturalAuthor exAuthor){
517
		String result = "";
518
		String authorString = "";
519
		String exAuthorString = "";
520
		if (author != null){
521
			authorString = CdmUtils.Nz(author.getNomenclaturalTitle());
522
		}
523
		if (exAuthor != null){
524
			exAuthorString = CdmUtils.Nz(exAuthor.getNomenclaturalTitle());
525
		}
526
		if (exAuthorString.length() > 0 ){
527
			exAuthorString = exAuthorString + ExAuthorSeperator;
528
		}
529
		result = exAuthorString + authorString;
530
		return result;
531
 
532
	}
533
	
534
// ************* TAGGED NAME ***************************************/	
535
	
536
	/* (non-Javadoc)
537
	 * @see eu.etaxonomy.cdm.strategy.cache.name.NameCacheStrategyBase#getTaggedTitle(eu.etaxonomy.cdm.model.name.TaxonNameBase)
538
	 */
539
	@Override
540
	public List<TaggedText> getTaggedFullTitle(T nonViralName) {
541
		List<TaggedText> tags = new ArrayList<TaggedText>();
542
		
543
		//null
544
		if (nonViralName == null){
545
			return null;
546
		}
547
		
548
		//protected full title cache
549
		if (nonViralName.isProtectedFullTitleCache()){
550
			tags.add(new TaggedText(TagEnum.fullName, nonViralName.getFullTitleCache()));
551
			return tags;
552
		}
553
		
554
		//title cache
555
//		String titleCache = nonViralName.getTitleCache();
556
		List<TaggedText> titleTags = getTaggedTitle(nonViralName);
557
		tags.addAll(titleTags);
558
		
559
		
560
		//reference
561
		String microReference = nonViralName.getNomenclaturalMicroReference();
562
		INomenclaturalReference ref = nonViralName.getNomenclaturalReference();
563
		String referenceBaseCache = null;
564
		if (ref != null){
565
			INomenclaturalReference nomenclaturalReference = HibernateProxyHelper.deproxy(ref, INomenclaturalReference.class);
566
			nomenclaturalReference.setCacheStrategy(nomenclaturalReference.getType().getCacheStrategy());
567
			referenceBaseCache = nomenclaturalReference.getNomenclaturalCitation(microReference);
568
		}
569
			//add to tags
570
		if (StringUtils.isNotBlank(referenceBaseCache)){
571
			if (! referenceBaseCache.trim().startsWith("in ")){
572
				String refConcat = ", ";
573
				tags.add(new TaggedText(TagEnum.separator, refConcat));
574
			}
575
			tags.add(new TaggedText(TagEnum.reference, referenceBaseCache));
576
		}
577
		
578
		//nomenclatural status
579
		Set<NomenclaturalStatus> ncStati = nonViralName.getStatus();
580
		Iterator<NomenclaturalStatus> iterator = ncStati.iterator();
581
		List<TaggedText> nomStatusTags = new ArrayList<TaggedText>();
582
		while (iterator.hasNext()) {
583
			NomenclaturalStatus ncStatus = (NomenclaturalStatus)iterator.next();
584
			// since the NewInstance method of nomencatural status allows null as parameter
585
			// we have to check for null values here
586
			String suffix = "not defined";
587
			if(ncStatus.getType() != null){
588
				NomenclaturalStatusType statusType =  ncStatus.getType();
589
				Language lang = Language.LATIN();
590
				Representation repr = statusType.getRepresentation(lang);
591
				if (repr != null){
592
					suffix = repr.getAbbreviatedLabel();
593
				}else{
594
					String message = "No latin representation available for nom. status. " + statusType.getTitleCache();
595
					logger.warn(message);
596
					throw new IllegalStateException(message);
597
				}
598
			}else if(ncStatus.getRuleConsidered() != null && ! ncStatus.getRuleConsidered().equals("")){
599
				suffix = ncStatus.getRuleConsidered();
600
			}
601
			String statusSeparator = ", ";
602
			nomStatusTags.add(new TaggedText(TagEnum.separator, statusSeparator));
603
			nomStatusTags.add(new TaggedText(TagEnum.nomStatus, suffix));
604
		}
605
		tags.addAll(nomStatusTags);
606
		return tags;
607
		
608
	}
609
		
610
	public List<TaggedText> getTaggedTitle(T nonViralName) {
611
		if (nonViralName == null){
612
			return null;
613
		}
614

    
615
		List<TaggedText> tags = new ArrayList<TaggedText>();
616
		
617
		//TODO how to handle protected fullTitleCache here?
618
		
619
		if (nonViralName.isProtectedTitleCache()){
620
			//protected title cache
621
			tags.add(new TaggedText(TagEnum.name, nonViralName.getTitleCache()));
622
			return tags;
623
		}else if (nonViralName.isHybridFormula()){
624
			//hybrid formula
625
			String hybridSeparator = NonViralNameParserImplRegExBase.hybridSign;
626
			boolean isFirst = true;
627
			List<HybridRelationship> rels = nonViralName.getOrderedChildRelationships();
628
			for (HybridRelationship rel: rels){
629
				if (! isFirst){
630
					tags.add(new TaggedText(TagEnum.hybridSign, hybridSeparator));
631
				}
632
				isFirst = false;
633
				tags.addAll(getTaggedTitle((T)rel.getParentName()));
634
			}
635
			return tags;
636
		}else if (nonViralName.isAutonym()){
637
			//Autonym
638
			tags.addAll(handleTaggedAutonym(nonViralName));
639
		}else{ //not Autonym
640
//			String nameCache = nonViralName.getNameCache();  //OLD: CdmUtils.Nz(getNameCache(nonViralName));
641
			List<TaggedText> nameTags = getNameTags(nonViralName);
642
			tags.addAll(nameTags);
643
			if (nameIncludesAuthorship(nonViralName)){
644
				String authorCache = getAuthorshipCache(nonViralName);
645
				if (StringUtils.isNotBlank(authorCache)){
646
					tags.add(new TaggedText(TagEnum.authors, authorCache));
647
				}
648
			}
649
		}
650
		return tags;
651

    
652
	}
653
	
654
	
655
	/**
656
	 * @param nonViralName
657
	 * @return
658
	 */
659
	private List<TaggedText> getNameTags(T nonViralName) {
660
		if (nonViralName == null){
661
			return null;
662
		}
663
		List<TaggedText> tags = new ArrayList<TaggedText>();
664
		Rank rank = nonViralName.getRank();
665
		
666
		if (nonViralName.isProtectedNameCache()){
667
			tags.add(new TaggedText(TagEnum.name, nonViralName.getNameCache()));
668
		}else if (rank == null){
669
			tags = getRanklessTaggedNameCache(nonViralName);
670
//		}else if (nonViralName.isInfragenericUnranked()){
671
//			result = getUnrankedInfragenericNameCache(nonViralName);
672
		}else if (rank.isInfraSpecific()){
673
			tags = getInfraSpeciesTaggedNameCache(nonViralName);
674
		}else if (rank.isSpecies()){
675
			tags = getSpeciesTaggedNameCache(nonViralName);
676
		}else if (rank.isInfraGeneric()){
677
			tags = getInfraGenusTaggedNameCache(nonViralName);
678
		}else if (rank.isGenus()){
679
			tags = getGenusOrUninomialTaggedNameCache(nonViralName);
680
		}else if (rank.isSupraGeneric()){
681
			tags = getGenusOrUninomialTaggedNameCache(nonViralName);
682
		}else{ 
683
			logger.warn("Name Strategy for Name (UUID: " + nonViralName.getUuid() +  ") not yet implemented");
684
		}
685
		//TODO handle appended phrase here instead of different places, check first if this is true for all
686
		//cases
687
		
688
		return tags;
689

    
690
	}
691

    
692

    
693
	//Old: may be replaced once getTagged(Full)Title is fully tested
694
	/* (non-Javadoc)
695
	 * @see eu.etaxonomy.cdm.strategy.INameCacheStrategy#getTaggedName(eu.etaxonomy.cdm.model.common.CdmBase)
696
	 */
697
	@Override
698
	public List<Object> getTaggedName(T nonViralName) {
699
		List<Object> tags = new ArrayList<Object>();
700
		
701
		if (nonViralName.isProtectedNameCache() ||
702
				nonViralName.isProtectedAuthorshipCache() ||
703
				nonViralName.isProtectedFullTitleCache() ||
704
				nonViralName.isProtectedTitleCache()){
705
			tags.add(nonViralName.getTitleCache());
706
			return tags;
707
		}
708
		
709
		// Why does it make sense to add the nameCache in case of non existing genusOrUninomial?
710
//		if (nonViralName.getGenusOrUninomial() == null){
711
//			tags.add(nonViralName.getNameCache());
712
//		}else{
713
		
714
		if (nonViralName.getGenusOrUninomial() != null) {
715
			tags.add(nonViralName.getGenusOrUninomial());
716
		}
717
		if (nonViralName.isSpecies() || nonViralName.isInfraSpecific()){
718
			tags.add(nonViralName.getSpecificEpithet());			
719
		}
720
		
721
		// No autonym 
722
		if (nonViralName.isInfraSpecific() && ! nonViralName.getSpecificEpithet().equals(nonViralName.getInfraSpecificEpithet())){
723
			tags.add(nonViralName.getRank());			
724
			tags.add(nonViralName.getInfraSpecificEpithet());			
725
		}
726
		
727
		if (nonViralName.isInfraGeneric()){
728
			//TODO choose right strategy or generic approach?
729
			// --- strategy 1 --- 
730
					
731
			if (nonViralName.getRank().isSpeciesAggregate()){
732
				tags.add(nonViralName.getSpecificEpithet());
733
				tags.add(getSpeciesAggregateEpithet(nonViralName));
734
			}else{
735
				tags.add(nonViralName.getRank());	
736
				tags.add(nonViralName.getInfraGenericEpithet());	
737
			}
738
			// --- strategy 2 --- 
739
//			tags.add('('+nvn.getInfraGenericEpithet()+')');	
740
		}
741
		Team authorTeam = Team.NewInstance();
742
		authorTeam.setProtectedTitleCache(true);
743
		authorTeam.setTitleCache(nonViralName.getAuthorshipCache(), true);
744
		tags.add(authorTeam);
745
		
746
		// Name is an autonym. Rank and infraspecific epitheton follow the author
747
		if (nonViralName.isInfraSpecific() && nonViralName.getSpecificEpithet().equals(nonViralName.getInfraSpecificEpithet())){
748
			tags.add(nonViralName.getRank());			
749
			tags.add(nonViralName.getInfraSpecificEpithet());			
750
		}
751
		
752
		if(! "".equals(nonViralName.getAppendedPhrase())&& (nonViralName.getAppendedPhrase() != null)){
753
			tags.add(nonViralName.getAppendedPhrase());
754
		}
755
		
756
		return tags;
757
	}
758
	
759

    
760
//***************************** PRIVATES ***************************************/
761
		
762
	protected List<TaggedText> getRanklessTaggedNameCache(NonViralName<?> nonViralName){
763
		List<TaggedText> tags = getUninomialTaggedPart(nonViralName);
764
		String speciesEpi = CdmUtils.Nz(nonViralName.getSpecificEpithet()).trim().replace("null", "");
765
		if (StringUtils.isNotBlank(speciesEpi)){
766
			tags.add(new TaggedText(TagEnum.name, speciesEpi));
767
		}
768
		
769
		String infraSpeciesEpi = CdmUtils.Nz(nonViralName.getInfraSpecificEpithet()).trim().replace("null", "");
770
		if (StringUtils.isNotBlank(infraSpeciesEpi)){
771
			tags.add(new TaggedText(TagEnum.name, infraSpeciesEpi));
772
		}
773
		
774
		//result += " (rankless)";
775
		addAppendedTaggedPhrase(tags, nonViralName);
776
		return tags;			
777
	}
778
	
779
	protected String getRanklessNameCache(NonViralName<?> nonViralName){
780
		String result = "";
781
		result = (result + (CdmUtils.Nz(nonViralName.getGenusOrUninomial()))).trim().replace("null", "");
782
		result += " " + (CdmUtils.Nz(nonViralName.getSpecificEpithet())).trim();
783
		result += " " + (CdmUtils.Nz(nonViralName.getInfraSpecificEpithet())).trim();
784
		result = result.trim().replace("null", "");
785
		//result += " (rankless)";
786
		result = addAppendedPhrase(result, nonViralName);
787
		return result;			
788
	}
789

    
790
		
791
	protected List<TaggedText> getGenusOrUninomialTaggedNameCache(NonViralName<?> nonViralName){
792
		List<TaggedText> tags = getUninomialTaggedPart(nonViralName);
793
		addAppendedTaggedPhrase(tags, nonViralName);
794
		return tags;
795
	}
796

    
797
	protected String getGenusOrUninomialNameCache(NonViralName<?> nonViralName){
798
		String result;
799
		result = getUninomialPart(nonViralName);
800
		result = addAppendedPhrase(result, nonViralName).trim();
801
		return result;
802
	}
803

    
804

    
805
	private List<TaggedText> getUninomialTaggedPart(NonViralName<?> nonViralName) {
806
		List<TaggedText> tags = new ArrayList<TaggedText>();
807
		
808
		if (nonViralName.isMonomHybrid()){
809
			addHybridPrefix(tags);
810
		}
811
		
812
		String uninomial = CdmUtils.Nz(nonViralName.getGenusOrUninomial()).trim().replace("null", "");
813
		if (StringUtils.isNotBlank(uninomial)){
814
			tags.add(new TaggedText(TagEnum.name, uninomial));
815
		}
816
			
817
		return tags;
818
	}
819
	
820
	private String getUninomialPart(NonViralName<?> nonViralName) {
821
		String result;
822
		result = CdmUtils.Nz(nonViralName.getGenusOrUninomial()).trim();
823
		if (nonViralName.isMonomHybrid()){
824
			result = NonViralNameParserImplRegExBase.hybridSign + result; 
825
		}
826
		return result;
827
	}
828
	
829
	
830
	protected List<TaggedText> getInfraGenusTaggedNameCache(NonViralName<?> nonViralName){
831
		Rank rank = nonViralName.getRank();
832
		if (rank.isSpeciesAggregate()){
833
			return getSpeciesAggregateTaggedCache(nonViralName);
834
		}
835
		
836
		//genus
837
		List<TaggedText> tags = getUninomialTaggedPart(nonViralName);
838
		
839
		//marker
840
		String infraGenericMarker = "'unhandled infrageneric rank'";
841
		if (rank != null){
842
			try {
843
				infraGenericMarker = rank.getInfraGenericMarker();
844
			} catch (UnknownCdmTypeException e) {
845
				infraGenericMarker = "'unhandled infrageneric rank'";
846
			}
847
		}
848
		tags.add(new TaggedText(TagEnum.rank, infraGenericMarker));
849
		
850
		
851
		String infraGenEpi = CdmUtils.Nz(nonViralName.getInfraGenericEpithet()).trim().replace("null", "");
852
		if (StringUtils.isNotBlank(infraGenEpi)){
853
			tags.add(new TaggedText(TagEnum.name, infraGenEpi));
854
		}
855
		
856
		addAppendedTaggedPhrase(tags, nonViralName);
857
		return tags;
858
	}
859
	
860
	protected String getInfraGenusNameCache(NonViralName<?> nonViralName){
861
		String result;
862
		Rank rank = nonViralName.getRank();
863
		if (rank.isSpeciesAggregate()){
864
			return getSpeciesAggregateCache(nonViralName);
865
		}
866
		String infraGenericMarker = "'unhandled infrageneric rank'";
867
		if (rank != null){
868
			try {
869
				infraGenericMarker = rank.getInfraGenericMarker();
870
			} catch (UnknownCdmTypeException e) {
871
				infraGenericMarker = "'unhandled infrageneric rank'";
872
			}
873
		}
874
		result = getUninomialPart(nonViralName);
875
		result += " " + infraGenericMarker + " " + (CdmUtils.Nz(nonViralName.getInfraGenericEpithet())).trim().replace("null", "");
876
		result = addAppendedPhrase(result, nonViralName).trim();
877
		return result;
878
	}
879

    
880
//		aggr.|agg.|group
881
	protected List<TaggedText> getSpeciesAggregateTaggedCache(NonViralName<?> nonViralName){
882
		List<TaggedText> tags = getGenusAndSpeciesTaggedPart(nonViralName);
883
		
884
		addSpeciesAggregateTaggedEpithet(tags, nonViralName);
885
		addAppendedTaggedPhrase(tags, nonViralName);
886
		return tags;
887
	}
888
	
889
	private void addSpeciesAggregateTaggedEpithet(List<TaggedText> tags, NonViralName<?> nonViralName) {
890
		String marker;
891
		try {
892
			marker = nonViralName.getRank().getInfraGenericMarker();
893
		} catch (UnknownCdmTypeException e) {
894
			marker = "'unknown aggregat type'";
895
		}
896
		if (StringUtils.isNotBlank(marker)){
897
			tags.add(new TaggedText(TagEnum.rank, marker));
898
		}
899
	}
900
	
901
//		aggr.|agg.|group
902
	protected String getSpeciesAggregateCache(NonViralName<?> nonViralName){
903
		String result = getGenusAndSpeciesPart(nonViralName);
904
		
905
		result += " " + getSpeciesAggregateEpithet(nonViralName);
906
		result = addAppendedPhrase(result, nonViralName).trim();
907
		return result;
908
	}
909
	
910
	private String getSpeciesAggregateEpithet(NonViralName<?> nonViralName) {
911
		String marker;
912
		try {
913
			marker = nonViralName.getRank().getInfraGenericMarker();
914
		} catch (UnknownCdmTypeException e) {
915
			marker = "'unknown aggregat type'";
916
		}
917
		return marker;
918
	}
919

    
920
	
921
	protected List<TaggedText> getSpeciesTaggedNameCache(NonViralName<?> nonViralName){
922
		List<TaggedText> tags = getGenusAndSpeciesTaggedPart(nonViralName);
923
		addAppendedTaggedPhrase(tags, nonViralName);
924
		return tags;
925
	}
926
	
927
	protected String getSpeciesNameCache(NonViralName<?> nonViralName){
928
		String result = getGenusAndSpeciesPart(nonViralName);
929
		result = addAppendedPhrase(result, nonViralName).trim();
930
		result = result.replace("\\s\\", " ");
931
		return result;
932
	}
933

    
934
	protected List<TaggedText> getInfraSpeciesTaggedNameCache(NonViralName<?> nonViralName){
935
		return getInfraSpeciesTaggedNameCache(nonViralName, true);
936
	}
937
	
938
	protected List<TaggedText> getInfraSpeciesTaggedNameCache(NonViralName<?> nonViralName, boolean includeMarker){
939
		List<TaggedText> tags = getGenusAndSpeciesTaggedPart(nonViralName);
940
		if (includeMarker){ 
941
			String marker = (nonViralName.getRank().getAbbreviation()).trim().replace("null", "");
942
			if (StringUtils.isNotBlank(marker)){
943
				tags.add(new TaggedText(TagEnum.rank, marker));
944
			}
945
		}
946
		String infrSpecEpi = CdmUtils.Nz(nonViralName.getInfraSpecificEpithet());
947
		if (nonViralName.isTrinomHybrid()){
948
			addHybridPrefix(tags);
949
		}
950
		
951
		infrSpecEpi = infrSpecEpi.trim().replace("null", "");
952
		if (StringUtils.isNotBlank(infrSpecEpi)){
953
			tags.add(new TaggedText(TagEnum.name, infrSpecEpi));
954
		}
955
		
956
		addAppendedTaggedPhrase(tags, nonViralName);
957
		return tags;
958
	}
959

    
960

    
961
	/**
962
	 * Adds a tag for the hybrid sign and an empty separator to avoid trailing whitespaces.
963
	 * @param tags
964
	 */
965
	private void addHybridPrefix(List<TaggedText> tags) {
966
		tags.add(new TaggedText(TagEnum.hybridSign, NonViralNameParserImplRegExBase.hybridSign));
967
		tags.add(new TaggedText(TagEnum.separator, "")); //no whitespace separator
968
	}
969
	
970
	protected String getInfraSpeciesNameCache(NonViralName<?> nonViralName){
971
		return getInfraSpeciesNameCache(nonViralName, true);
972
	}
973

    
974
	
975
	protected String getInfraSpeciesNameCache(NonViralName<?> nonViralName, boolean includeMarker){
976
		String result = getGenusAndSpeciesPart(nonViralName);
977
		if (includeMarker){ 
978
			result += " " + (nonViralName.getRank().getAbbreviation()).trim().replace("null", "");
979
		}
980
		String infrSpecEpi = CdmUtils.Nz(nonViralName.getInfraSpecificEpithet());
981
		if (nonViralName.isTrinomHybrid()){
982
			infrSpecEpi = NonViralNameParserImplRegExBase.hybridSign + infrSpecEpi; 
983
		}
984
		result += " " + (infrSpecEpi).trim().replace("null", "");
985
		result = addAppendedPhrase(result, nonViralName).trim();
986
		return result;
987
	}
988

    
989

    
990
	private List<TaggedText> getGenusAndSpeciesTaggedPart(NonViralName<?> nonViralName) {
991
		//Uninomial
992
		List<TaggedText> tags = getUninomialTaggedPart(nonViralName);
993
		
994
		//InfraGenericEpi
995
		boolean hasInfraGenericEpi = StringUtils.isNotBlank(nonViralName.getInfraGenericEpithet());
996
		if (hasInfraGenericEpi){
997
			String infrGenEpi = nonViralName.getInfraGenericEpithet().trim();
998
			if (nonViralName.isBinomHybrid()){
999
//					addHybridPrefix(tags);  FIXME hybridSign should be tag, but then we need to handle "(" ")" differently.
1000
				infrGenEpi = NonViralNameParserImplRegExBase.hybridSign + infrGenEpi;
1001
			}
1002
			infrGenEpi = "(" + infrGenEpi + ")";
1003
			tags.add(new TaggedText(TagEnum.name, infrGenEpi));
1004
		}
1005

    
1006
		//Species Epi
1007
		String specEpi = CdmUtils.Nz(nonViralName.getSpecificEpithet()).trim().replace("null", "");
1008
		if (! hasInfraGenericEpi && nonViralName.isBinomHybrid() || 
1009
				hasInfraGenericEpi && nonViralName.isTrinomHybrid()){
1010
			addHybridPrefix(tags); 
1011
		}
1012
		if (StringUtils.isNotBlank(specEpi)){
1013
			tags.add(new TaggedText(TagEnum.name, specEpi));
1014
		}
1015
		return tags;
1016
	}
1017
	
1018
	private String getGenusAndSpeciesPart(NonViralName<?> nonViralName) {
1019
		String result;
1020
		//Uninomial
1021
		result = getUninomialPart(nonViralName);
1022
		
1023
		//InfraGenericEpi
1024
		boolean hasInfraGenericEpi = StringUtils.isNotBlank(nonViralName.getInfraGenericEpithet());
1025
		if (hasInfraGenericEpi){
1026
			String infrGenEpi = nonViralName.getInfraGenericEpithet().trim();
1027
			if (nonViralName.isBinomHybrid()){
1028
				infrGenEpi = NonViralNameParserImplRegExBase.hybridSign + infrGenEpi; 
1029
			}
1030
			result += " (" + infrGenEpi + ")";
1031
		}
1032
		//Species Epi
1033
		String specEpi = CdmUtils.Nz(nonViralName.getSpecificEpithet()).trim();
1034
		if (! hasInfraGenericEpi && nonViralName.isBinomHybrid() || 
1035
				hasInfraGenericEpi && nonViralName.isTrinomHybrid()){
1036
			specEpi = NonViralNameParserImplRegExBase.hybridSign +  specEpi; 
1037
		}
1038
		result += " " + (specEpi).replace("null", "");
1039
		return result;
1040
	}
1041

    
1042
	
1043
	/**
1044
	 * Adds the tag for the appended phrase if an appended phrase exists
1045
	 * @param tags
1046
	 * @param nonViralName
1047
	 */
1048
	protected void addAppendedTaggedPhrase(List<TaggedText> tags, NonViralName<?> nonViralName){
1049
		String appendedPhrase = nonViralName ==null ? null : nonViralName.getAppendedPhrase();
1050
		if (StringUtils.isNotEmpty(appendedPhrase)){
1051
			tags.add(new TaggedText(TagEnum.name, appendedPhrase));
1052
		}
1053
	}
1054
	
1055
	protected String addAppendedPhrase(String resultString, NonViralName<?> nonViralName){
1056
		String appendedPhrase = nonViralName ==null ? null : nonViralName.getAppendedPhrase();
1057
		if (resultString == null){
1058
			return appendedPhrase;
1059
		}else if(appendedPhrase == null || "".equals(appendedPhrase.trim())) {
1060
			return resultString;
1061
		}else if ("".equals(resultString)){
1062
			return resultString + appendedPhrase;
1063
		}else {
1064
			return resultString + " " + appendedPhrase;
1065
		}
1066
	}
1067

    
1068

    
1069
	public String getLastEpithet(T taxonNameBase) {
1070
		Rank rank = taxonNameBase.getRank();
1071
		if(rank.isGenus() || rank.isSupraGeneric()) {
1072
			return taxonNameBase.getGenusOrUninomial();
1073
		} else if(rank.isInfraGeneric()) {
1074
			return taxonNameBase.getInfraGenericEpithet();
1075
		} else if(rank.isSpecies()) {
1076
			return taxonNameBase.getSpecificEpithet();
1077
		} else {
1078
			return taxonNameBase.getInfraSpecificEpithet();
1079
		}
1080
	}
1081
}
(7-7/8)