Project

General

Profile

Download (26.7 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2007 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9
package eu.etaxonomy.cdm.strategy.cache.name;
10

    
11
import java.util.ArrayList;
12
import java.util.List;
13
import java.util.UUID;
14

    
15
import org.apache.log4j.Logger;
16

    
17
import eu.etaxonomy.cdm.common.CdmUtils;
18
import eu.etaxonomy.cdm.common.UTF8;
19
import eu.etaxonomy.cdm.model.agent.INomenclaturalAuthor;
20
import eu.etaxonomy.cdm.model.name.HybridRelationship;
21
import eu.etaxonomy.cdm.model.name.INonViralName;
22
import eu.etaxonomy.cdm.model.name.Rank;
23
import eu.etaxonomy.cdm.model.name.TaxonName;
24
import eu.etaxonomy.cdm.strategy.cache.TagEnum;
25
import eu.etaxonomy.cdm.strategy.cache.TaggedText;
26
import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
27
import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImplRegExBase;
28

    
29

    
30
/**
31
 * This class is a default implementation for the INonViralNameCacheStrategy<T extends NonViralName>
32
 * interface.<BR>
33
 * The method implements a cache strategy for botanical names so no method has to be overwritten by
34
 * a subclass for botanic names.
35
 * Where differing from this default botanic name strategy other subclasses should overwrite the
36
 * existing methods, e.g. a CacheStrategy for zoological names should overwrite getAuthorAndExAuthor
37
 * @author a.mueller
38
 */
39
public class TaxonNameDefaultCacheStrategy
40
        extends NameCacheStrategyBase
41
        implements INonViralNameCacheStrategy {
42

    
43
    private static final Logger logger = Logger.getLogger(TaxonNameDefaultCacheStrategy.class);
44
	private static final long serialVersionUID = -6577757501563212669L;
45

    
46
    final static UUID uuid = UUID.fromString("1cdda0d1-d5bc-480f-bf08-40a510a2f223");
47

    
48
    protected String nameAuthorSeperator = " ";
49
    protected String basionymStart = "(";
50
    protected String basionymEnd = ")";
51
    protected String exAuthorSeperator = " ex ";
52
    private static String NOTHO = "notho";
53
    protected CharSequence basionymAuthorCombinationAuthorSeperator = " ";
54

    
55
    protected String zooAuthorYearSeperator = ", ";
56

    
57
    @Override
58
    public UUID getUuid(){
59
        return uuid;
60
    }
61

    
62
// ************************** FACTORY  ******************************/
63

    
64
    public static TaxonNameDefaultCacheStrategy NewInstance(){
65
        return new TaxonNameDefaultCacheStrategy();
66
    }
67

    
68

    
69
// ************ CONSTRUCTOR *******************/
70

    
71
    protected TaxonNameDefaultCacheStrategy(){
72
        super();
73
    }
74

    
75
/* **************** GETTER / SETTER **************************************/
76

    
77
    /**
78
     * String that separates the NameCache part from the AuthorCache part
79
     * @return
80
     */
81
    public String getNameAuthorSeperator() {
82
        return nameAuthorSeperator;
83
    }
84
    public void setNameAuthorSeperator(String nameAuthorSeperator) {
85
        this.nameAuthorSeperator = nameAuthorSeperator;
86
    }
87

    
88

    
89
    /**
90
     * String the basionym author part starts with e.g. '('.
91
     * This should correspond with the {@link TaxonNameDefaultCacheStrategy#getBasionymEnd() basionymEnd} attribute
92
     * @return
93
     */
94
    public String getBasionymStart() {
95
        return basionymStart;
96
    }
97
    public void setBasionymStart(String basionymStart) {
98
        this.basionymStart = basionymStart;
99
    }
100

    
101
    /**
102
     * String the basionym author part ends with e.g. ')'.
103
     * This should correspond with the {@link TaxonNameDefaultCacheStrategy#getBasionymStart() basionymStart} attribute
104
     * @return
105
     */
106
    public String getBasionymEnd() {
107
        return basionymEnd;
108
    }
109
    public void setBasionymEnd(String basionymEnd) {
110
        this.basionymEnd = basionymEnd;
111
    }
112

    
113

    
114
    /**
115
     * String to separate ex author from author.
116
     * @return
117
     */
118
    public String getExAuthorSeperator() {
119
        return exAuthorSeperator;
120
    }
121
    public void setExAuthorSeperator(String exAuthorSeperator) {
122
        this.exAuthorSeperator = exAuthorSeperator;
123
    }
124

    
125

    
126
    /**
127
     * String that separates the basionym/original_combination author part from the combination author part
128
     * @return
129
     */
130
    public CharSequence getBasionymAuthorCombinationAuthorSeperator() {
131
        return basionymAuthorCombinationAuthorSeperator;
132
    }
133

    
134

    
135
    public void setBasionymAuthorCombinationAuthorSeperator( CharSequence basionymAuthorCombinationAuthorSeperator) {
136
        this.basionymAuthorCombinationAuthorSeperator = basionymAuthorCombinationAuthorSeperator;
137
    }
138

    
139
    public String getZooAuthorYearSeperator() {
140
        return zooAuthorYearSeperator;
141
    }
142
    public void setZooAuthorYearSeperator(String authorYearSeperator) {
143
        this.zooAuthorYearSeperator = authorYearSeperator;
144
    }
145

    
146
// ******************* Authorship ******************************/
147

    
148
    @Override
149
    public String getAuthorshipCache(TaxonName taxonName) {
150
        if (taxonName == null){
151
            return null;
152
        }else if (taxonName.getNameType().isViral()){
153
            return null;
154
        }else if(taxonName.isProtectedAuthorshipCache() == true) {
155
            //cache protected
156
            return taxonName.getAuthorshipCache();
157
        }else{
158
            return getNonCacheAuthorshipCache(taxonName);
159
        }
160
    }
161

    
162
    /**
163
     * Returns the authorshipcache string for the atomized authorship fields. Does not use the authorship field.
164
     * @throws NullPointerException if nonViralName is null.
165
     * @param taxonName
166
     * @return
167
     */
168
    protected String getNonCacheAuthorshipCache(TaxonName nonViralName){
169
        if (nonViralName.getNameType().isZoological()){
170
            return this.getZoologicalNonCacheAuthorshipCache(nonViralName);
171
        }else{
172
            String result = "";
173
            INomenclaturalAuthor combinationAuthor = nonViralName.getCombinationAuthorship();
174
            INomenclaturalAuthor exCombinationAuthor = nonViralName.getExCombinationAuthorship();
175
            INomenclaturalAuthor basionymAuthor = nonViralName.getBasionymAuthorship();
176
            INomenclaturalAuthor exBasionymAuthor = nonViralName.getExBasionymAuthorship();
177
            String basionymPart = "";
178
            String authorPart = "";
179
            //basionym
180
            if (basionymAuthor != null || exBasionymAuthor != null){
181
                basionymPart = basionymStart + getAuthorAndExAuthor(basionymAuthor, exBasionymAuthor) + basionymEnd;
182
            }
183
            if (combinationAuthor != null || exCombinationAuthor != null){
184
                authorPart = getAuthorAndExAuthor(combinationAuthor, exCombinationAuthor);
185
            }
186
            result = CdmUtils.concat(basionymAuthorCombinationAuthorSeperator, basionymPart, authorPart);
187
//        if ("".equals(result)){
188
//        	result = null;
189
//        }
190
            return result;
191
        }
192
    }
193

    
194
    protected String getZoologicalNonCacheAuthorshipCache(TaxonName nonViralName) {
195
        if (nonViralName == null){
196
            return null;
197
        }
198
        String result = "";
199
        INomenclaturalAuthor combinationAuthor = nonViralName.getCombinationAuthorship();
200
        INomenclaturalAuthor exCombinationAuthor = nonViralName.getExCombinationAuthorship();
201
        INomenclaturalAuthor basionymAuthor = nonViralName.getBasionymAuthorship();
202
        INomenclaturalAuthor exBasionymAuthor = nonViralName.getExBasionymAuthorship();
203
        Integer publicationYear = nonViralName.getPublicationYear();
204
        Integer originalPublicationYear = nonViralName.getOriginalPublicationYear();
205

    
206
        String basionymPart = "";
207
        String authorPart = "";
208
        //basionym
209
        if (basionymAuthor != null || exBasionymAuthor != null || originalPublicationYear != null ){
210
            String authorAndEx = getAuthorAndExAuthor(basionymAuthor, exBasionymAuthor);
211
            String originalPublicationYearString = originalPublicationYear == null ? null : String.valueOf(originalPublicationYear);
212
            String authorAndExAndYear = CdmUtils.concat(zooAuthorYearSeperator, authorAndEx, originalPublicationYearString );
213
            basionymPart = basionymStart + authorAndExAndYear + basionymEnd;
214
        }
215
        if (combinationAuthor != null || exCombinationAuthor != null){
216
            String authorAndEx = getAuthorAndExAuthor(combinationAuthor, exCombinationAuthor);
217
            String publicationYearString = publicationYear == null ? null : String.valueOf(publicationYear);
218
            authorPart = CdmUtils.concat(zooAuthorYearSeperator, authorAndEx, publicationYearString);
219
        }
220
        result = CdmUtils.concat(basionymAuthorCombinationAuthorSeperator, basionymPart, authorPart);
221
        if (result == null){
222
            result = "";
223
        }
224
        return result;
225
    }
226

    
227

    
228
    /**
229
     * Returns the AuthorCache part for a combination of an author and an ex author. This applies on
230
     * combination authors as well as on basionym/orginal combination authors.
231
     * The correct order is exAuthor ex author though some botanist do not know about and do it the
232
     * other way round. (see 46.4-46.6 ICBN (Vienna Code, 2006))
233
     */
234
    protected String getAuthorAndExAuthor(INomenclaturalAuthor author, INomenclaturalAuthor exAuthor){
235
        String authorString = "";
236
        String exAuthorString = "";
237
        if (author != null){
238
            authorString = getNomAuthorTitle(author);
239
        }
240
        if (exAuthor != null){
241
            exAuthorString = getNomAuthorTitle(exAuthor);
242
            exAuthorString += exAuthorSeperator;
243
        }
244
        String result = exAuthorString + authorString;
245
        return result;
246
    }
247

    
248
    private String getNomAuthorTitle(INomenclaturalAuthor author) {
249
        return CdmUtils.Nz(author.getNomenclaturalTitleCache());
250
    }
251

    
252
    /**
253
     * Checks if the given name should include the author in it's cached version.<BR>
254
     * This is usually the case but not for <i>species aggregates</i>.
255
     * @param nonViralName
256
     * @return
257
     */
258
    protected boolean nameIncludesAuthorship(INonViralName nonViralName){
259
        Rank rank = nonViralName.getRank();
260
        if (rank != null && rank.isSpeciesAggregate()){
261
            return false;
262
        }else{
263
            return true;
264
        }
265
    }
266

    
267
// ************* TAGGED NAME ***************************************/
268

    
269
    @Override
270
    protected List<TaggedText> doGetTaggedTitle(TaxonName taxonName) {
271
        List<TaggedText> tags = new ArrayList<>();
272
        if (taxonName.getNameType().isViral()){
273
            String acronym = taxonName.getAcronym();
274
            if (isNotBlank(taxonName.getAcronym())){
275
                //this is not according to the code
276
                tags.add(new TaggedText(TagEnum.name, acronym));
277
            }
278
            return tags;
279
        }else if (taxonName.isHybridFormula()){
280
            //hybrid formula
281
            String hybridSeparator = NonViralNameParserImplRegExBase.hybridSign;
282
            boolean isFirst = true;
283
            List<HybridRelationship> rels = taxonName.getOrderedChildRelationships();
284
            for (HybridRelationship rel: rels){
285
                if (! isFirst){
286
                    tags.add(new TaggedText(TagEnum.hybridSign, hybridSeparator));
287
                }
288
                isFirst = false;
289
                tags.addAll(getTaggedTitle(rel.getParentName()));
290
            }
291
            return tags;
292
        }else if (taxonName.isAutonym()){
293
            //Autonym
294
            tags.addAll(handleTaggedAutonym(taxonName));
295
        }else{ //not Autonym
296
             List<TaggedText> nameTags = getTaggedName(taxonName);
297
            tags.addAll(nameTags);
298
            String authorCache = getAuthorshipCache(taxonName);
299
            if (isNotBlank(authorCache)){
300
                tags.add(new TaggedText(TagEnum.authors, authorCache));
301
            }
302
        }
303
        return tags;
304
    }
305

    
306
    /**
307
     * Returns the tag list of the name part (without author and reference).
308
     * @param taxonName
309
     * @return
310
     */
311
    @Override
312
    public List<TaggedText> getTaggedName(TaxonName taxonName) {
313
        if (taxonName == null){
314
            return null;
315
        }else if (taxonName.isViral()){
316
            return null;
317
        }
318
        List<TaggedText> tags = new ArrayList<>();
319
        Rank rank = taxonName.getRank();
320

    
321
        if (taxonName.isProtectedNameCache()){
322
            tags.add(new TaggedText(TagEnum.name, taxonName.getNameCache()));
323
        }else if (taxonName.isHybridFormula()){
324
            //hybrid formula
325
            String hybridSeparator = NonViralNameParserImplRegExBase.hybridSign;
326
            boolean isFirst = true;
327
            List<HybridRelationship> rels = taxonName.getOrderedChildRelationships();
328
            for (HybridRelationship rel: rels){
329
                if (! isFirst){
330
                    tags.add(new TaggedText(TagEnum.hybridSign, hybridSeparator));
331
                }
332
                isFirst = false;
333
                tags.addAll(getTaggedName(rel.getParentName()));
334
            }
335
            return tags;
336

    
337
        }else if (rank == null){
338
            tags = getRanklessTaggedNameCache(taxonName);
339
//		}else if (nonViralName.isInfragenericUnranked()){
340
//			result = getUnrankedInfragenericNameCache(nonViralName);
341
        }else if (rank.isInfraSpecific()){
342
            tags = getInfraSpeciesTaggedNameCache(taxonName);
343
        }else if (rank.isSpecies() || isAggregateWithAuthorship(taxonName, rank) ){ //exception see #4288
344
            tags = getSpeciesTaggedNameCache(taxonName);
345
        }else if (rank.isInfraGeneric()){
346
            tags = getInfraGenusTaggedNameCache(taxonName);
347
        }else if (rank.isGenus()){
348
            tags = getGenusOrUninomialTaggedNameCache(taxonName);
349
        }else if (rank.isSupraGeneric()){
350
            tags = getGenusOrUninomialTaggedNameCache(taxonName);
351
        }else{
352
            tags = getRanklessTaggedNameCache(taxonName);
353
            logger.warn("Rank does not belong to a rank class: " + rank.getTitleCache() + ". Used rankless nameCache for name " + taxonName.getUuid());
354
        }
355
        //TODO handle appended phrase here instead of different places, check first if this is true for all
356
        //cases
357

    
358
        return tags;
359
    }
360

    
361
//***************************** PRIVATES ***************************************/
362

    
363
    private boolean isAggregateWithAuthorship(TaxonName nonViralName, Rank rank) {
364
		if (rank == null){
365
			return false;
366
		}else{
367
			return rank.isSpeciesAggregate() && ( isNotBlank(nonViralName.getAuthorshipCache()) || nonViralName.getNomenclaturalReference() != null );
368
		}
369
	}
370

    
371
	/**
372
     * Returns the tag list for an autonym taxon.
373
     *
374
     * @see NonViralName#isAutonym()
375
     * @see BotanicalName#isAutonym()
376
     * @param nonViralName
377
     * @return
378
     */
379
    private List<TaggedText> handleTaggedAutonym(TaxonName nonViralName) {
380
    	List<TaggedText> tags = null;
381
    	if (nonViralName.isInfraSpecific()){
382
	        //species part
383
	        tags = getSpeciesTaggedNameCache(nonViralName);
384

    
385
	        //author
386
	        String authorCache = getAuthorshipCache(nonViralName);
387
	        if (isNotBlank(authorCache)){
388
	            tags.add(new TaggedText(TagEnum.authors, authorCache));
389
	        }
390

    
391
	        //infra species marker
392
	        if (nonViralName.getRank() == null || !nonViralName.getRank().isInfraSpecific()){
393
	            //TODO handle exception
394
	            logger.warn("Rank for autonym does not exist or is not lower than species !!");
395
	        }else{
396
	            String infraSpeciesMarker = nonViralName.getRank().getAbbreviation();
397
	            if (nonViralName.isTrinomHybrid()){
398
	                infraSpeciesMarker = CdmUtils.concat("", NOTHO, infraSpeciesMarker);
399
	            }
400
	            if (isNotBlank(infraSpeciesMarker)){
401
	                tags.add(new TaggedText(TagEnum.rank, infraSpeciesMarker));
402
	            }
403
	        }
404

    
405
	        //infra species
406
	        String infraSpeciesPart = CdmUtils.Nz(nonViralName.getInfraSpecificEpithet()).trim();
407
	        if (isNotBlank(infraSpeciesPart)){
408
	            tags.add(new TaggedText(TagEnum.name, infraSpeciesPart));
409
	        }
410

    
411
        } else if (nonViralName.isInfraGeneric()){
412
        	//genus part
413
	       tags =getGenusOrUninomialTaggedNameCache(nonViralName);
414

    
415
	       //author
416
           String authorCache = getAuthorshipCache(nonViralName);
417
           if (isNotBlank(authorCache)){
418
               tags.add(new TaggedText(TagEnum.authors, authorCache));
419
           }
420

    
421
	        //infra species marker
422
	        if (nonViralName.getRank() == null || !nonViralName.getRank().isInfraGeneric()){
423
	            //TODO handle exception
424
	            logger.warn("Rank for autonym does not exist or is not lower than species !!");
425
	        }else{
426
	        	Rank rank = nonViralName.getRank();
427
	            String infraGenericMarker = rank.getAbbreviation();
428
                if (rank.equals(Rank.SECTION_BOTANY()) || rank.equals(Rank.SUBSECTION_BOTANY())){
429
                	infraGenericMarker = infraGenericMarker.replace("(bot.)", "");
430
                }
431
	            if (isNotBlank(infraGenericMarker)){
432
	                tags.add(new TaggedText(TagEnum.rank, infraGenericMarker));
433
	            }
434
	        }
435

    
436
	        //infra genus
437
	        String infraGenericPart = CdmUtils.Nz(nonViralName.getInfraGenericEpithet()).trim();
438
	        if (isNotBlank(infraGenericPart)){
439
	            tags.add(new TaggedText(TagEnum.name, infraGenericPart));
440
	        }
441
        }
442

    
443
        return tags;
444
    }
445

    
446

    
447

    
448
    /**
449
     * Returns the tag list for rankless taxa.
450
     * @param nonViralName
451
     * @return
452
     */
453
    protected List<TaggedText> getRanklessTaggedNameCache(INonViralName nonViralName){
454
        List<TaggedText> tags = getUninomialTaggedPart(nonViralName);
455
        String speciesEpi = CdmUtils.Nz(nonViralName.getSpecificEpithet()).trim();
456
        if (isNotBlank(speciesEpi)){
457
            tags.add(new TaggedText(TagEnum.name, speciesEpi));
458
        }
459

    
460
        String infraSpeciesEpi = CdmUtils.Nz(nonViralName.getInfraSpecificEpithet());
461
        if (isNotBlank(infraSpeciesEpi)){
462
            tags.add(new TaggedText(TagEnum.name, infraSpeciesEpi));
463
        }
464

    
465
        //result += " (rankless)";
466
        addAppendedTaggedPhrase(tags, nonViralName);
467
        return tags;
468
    }
469

    
470
    /**
471
     * Returns the tag list for the first epithet (including a hybrid sign if required).
472
     * @param nonViralName
473
     * @return
474
     */
475
    private List<TaggedText> getUninomialTaggedPart(INonViralName nonViralName) {
476
        List<TaggedText> tags = new ArrayList<>();
477

    
478
        if (nonViralName.isMonomHybrid()){
479
            addHybridPrefix(tags);
480
        }
481

    
482
        String uninomial = CdmUtils.Nz(nonViralName.getGenusOrUninomial()).trim();
483
        if (isNotBlank(uninomial)){
484
            tags.add(new TaggedText(TagEnum.name, uninomial));
485
        }
486

    
487
        return tags;
488
    }
489

    
490
    /**
491
     * Returns the tag list for an genus or higher taxon.
492
     *
493
     * @param nonViralName
494
     * @return
495
     */
496
    protected List<TaggedText> getGenusOrUninomialTaggedNameCache(INonViralName nonViralName){
497
        List<TaggedText> tags = getUninomialTaggedPart(nonViralName);
498
        addAppendedTaggedPhrase(tags, nonViralName);
499
        return tags;
500
    }
501

    
502
    /**
503
     * Returns the tag list for an infrageneric taxon (including species aggregates).
504
     *
505
     * @see #getSpeciesAggregateTaggedCache(NonViralName)
506
     * @param nonViralName
507
     * @return
508
     */
509
    protected List<TaggedText> getInfraGenusTaggedNameCache(INonViralName nonViralName){
510
        Rank rank = nonViralName.getRank();
511
        if (rank != null && rank.isSpeciesAggregate() && isBlank(nonViralName.getAuthorshipCache())){
512
            return getSpeciesAggregateTaggedCache(nonViralName);
513
        }
514

    
515
        //genus
516
        List<TaggedText> tags = getUninomialTaggedPart(nonViralName);
517

    
518
        //marker
519
        String infraGenericMarker;
520
        if (rank != null){
521
            try {
522
                infraGenericMarker = rank.getInfraGenericMarker();
523
                if (rank.equals(Rank.SECTION_BOTANY()) || rank.equals(Rank.SUBSECTION_BOTANY())){
524
                	infraGenericMarker = infraGenericMarker.replace("(bot.)", "");
525
                }
526
            } catch (UnknownCdmTypeException e) {
527
                infraGenericMarker = "'unhandled infrageneric rank'";
528
            }
529
        }else{
530
        	infraGenericMarker = "'undefined infrageneric rank'";
531
        }
532
        String infraGenEpi = CdmUtils.Nz(nonViralName.getInfraGenericEpithet()).trim();
533
        if (nonViralName.isBinomHybrid()){
534
            infraGenericMarker = CdmUtils.concat("", NOTHO, infraGenericMarker);
535
        }
536

    
537
        addInfraGenericPart(nonViralName, tags, infraGenericMarker, infraGenEpi);
538

    
539
        addAppendedTaggedPhrase(tags, nonViralName);
540
        return tags;
541
    }
542

    
543

    
544
	/**
545
	 * Default implementation for the infrageneric part of a name.
546
	 * This is usually the infrageneric marker and the infrageneric epitheton. But may be
547
	 * implemented differently e.g. for zoological names the infrageneric epitheton
548
	 * may be surrounded by brackets and the marker left out.
549
	 * @param nonViralName
550
	 * @param tags
551
	 * @param infraGenericMarker
552
	 */
553
	protected void addInfraGenericPart(
554
	        @SuppressWarnings("unused") INonViralName name,
555
	        List<TaggedText> tags,
556
	        String infraGenericMarker,
557
	        String infraGenEpi) {
558
		//add marker
559
		tags.add(new TaggedText(TagEnum.rank, infraGenericMarker));
560

    
561
		//add epitheton
562
		if (isNotBlank(infraGenEpi)){
563
            tags.add(new TaggedText(TagEnum.name, infraGenEpi));
564
        }
565
	}
566

    
567
    /**
568
     * Returns the tag list for a species aggregate (or similar) taxon.<BR>
569
     * Possible ranks for a <i>species aggregate</i> are "aggr.", "species group", ...
570
     * @param nonViralName
571
     * @return
572
     */
573
    protected List<TaggedText> getSpeciesAggregateTaggedCache(INonViralName nonViralName){
574
        if (! isBlank(nonViralName.getAuthorshipCache())){
575
        	List<TaggedText> result = getSpeciesTaggedNameCache(nonViralName);
576
        	return result;
577
        }
578

    
579

    
580
    	List<TaggedText> tags = getGenusAndSpeciesTaggedPart(nonViralName);
581

    
582
        addSpeciesAggregateTaggedEpithet(tags, nonViralName);
583
        addAppendedTaggedPhrase(tags, nonViralName);
584
        return tags;
585
    }
586

    
587
    /**
588
     * Adds the aggregate tag to the tag list.
589
     * @param tags
590
     * @param nonViralName
591
     */
592
    private void addSpeciesAggregateTaggedEpithet(List<TaggedText> tags, INonViralName nonViralName) {
593
        String marker;
594
        try {
595
            marker = nonViralName.getRank().getInfraGenericMarker();
596
        } catch (UnknownCdmTypeException e) {
597
            marker = "'unknown aggregat type'";
598
        }
599
        if (isNotBlank(marker)){
600
            tags.add(new TaggedText(TagEnum.rank, marker));
601
        }
602
    }
603

    
604

    
605
    /**
606
     * Returns the tag list for a species taxon.
607
     * @param nonViralName
608
     * @return
609
     */
610
    protected List<TaggedText> getSpeciesTaggedNameCache(INonViralName nonViralName){
611
        List<TaggedText> tags = getGenusAndSpeciesTaggedPart(nonViralName);
612
        addAppendedTaggedPhrase(tags, nonViralName);
613
        return tags;
614
    }
615

    
616
    protected List<TaggedText> getInfraSpeciesTaggedNameCache(TaxonName name){
617
        if (name.getNameType().isZoological()){
618
            boolean includeMarker =includeInfraSpecificMarkerForZooNames(name);
619
            return getInfraSpeciesTaggedNameCache(name, includeMarker);
620
        }else{
621
            return getInfraSpeciesTaggedNameCache(name, true);
622
        }
623
    }
624

    
625
    protected boolean includeInfraSpecificMarkerForZooNames(TaxonName name){
626
        return ! (name.isAutonym());  //only exclude marker if autonym, see also ZooNameNoMarkerCacheStrategy
627
    }
628

    
629
    /**
630
     * Creates the tag list for an infraspecific taxon. If include is true the result will contain
631
     * the infraspecific marker (e.g. "var.")
632
     * @param nonViralName
633
     * @param includeMarker
634
     * @return
635
     */
636
    protected List<TaggedText> getInfraSpeciesTaggedNameCache(INonViralName nonViralName, boolean includeMarker){
637
        List<TaggedText> tags = getGenusAndSpeciesTaggedPart(nonViralName);
638
        if (includeMarker || nonViralName.isTrinomHybrid()){
639
            String marker = (nonViralName.getRank().getAbbreviation()).trim().replace("null", "");
640
            if (nonViralName.isTrinomHybrid()){
641
                marker = CdmUtils.concat("", NOTHO, marker);
642
            }
643
            if (isNotBlank(marker)){
644
                tags.add(new TaggedText(TagEnum.rank, marker));
645
            }
646

    
647
        }
648
        String infrSpecEpi = CdmUtils.Nz(nonViralName.getInfraSpecificEpithet());
649

    
650
        infrSpecEpi = infrSpecEpi.trim().replace("null", "");
651

    
652
        if (isNotBlank(infrSpecEpi)){
653
            tags.add(new TaggedText(TagEnum.name, infrSpecEpi));
654
        }
655

    
656
        addAppendedTaggedPhrase(tags, nonViralName);
657
        return tags;
658
    }
659

    
660

    
661
    /**
662
     * Adds a tag for the hybrid sign and an empty separator to avoid trailing whitespaces.
663
     * @param tags
664
     */
665
    private void addHybridPrefix(List<TaggedText> tags) {
666
        tags.add(new TaggedText(TagEnum.hybridSign, NonViralNameParserImplRegExBase.hybridSign));
667
        tags.add(new TaggedText(TagEnum.separator, "")); //no whitespace separator
668
    }
669

    
670
    /**
671
     * Creates the tag list for the genus and species part.
672
     * @param nonViralName
673
     * @return
674
     */
675
    private List<TaggedText> getGenusAndSpeciesTaggedPart(INonViralName nonViralName) {
676
        //Uninomial
677
        List<TaggedText> tags = getUninomialTaggedPart(nonViralName);
678

    
679
        //InfraGenericEpi
680
        boolean hasInfraGenericEpi = isNotBlank(nonViralName.getInfraGenericEpithet());
681
        if (hasInfraGenericEpi){
682
            String infrGenEpi = nonViralName.getInfraGenericEpithet().trim();
683
            if (nonViralName.isBinomHybrid()){
684
                //maybe not correct but not really expected to happen
685
                infrGenEpi = UTF8.HYBRID + infrGenEpi;
686
            }
687
            infrGenEpi = "(" + infrGenEpi + ")";
688
            tags.add(new TaggedText(TagEnum.name, infrGenEpi));
689
        }
690

    
691
        //Species Epi
692
        String specEpi = CdmUtils.Nz(nonViralName.getSpecificEpithet()).trim();
693
        if (! hasInfraGenericEpi && nonViralName.isBinomHybrid() ||
694
                hasInfraGenericEpi && nonViralName.isTrinomHybrid()){
695
            addHybridPrefix(tags);
696
        }
697
        if (isNotBlank(specEpi)){
698
            tags.add(new TaggedText(TagEnum.name, specEpi));
699
        }
700
        return tags;
701
    }
702

    
703
    /**
704
     * Adds the tag for the appended phrase if an appended phrase exists
705
     * @param tags
706
     * @param nonViralName
707
     */
708
    protected void addAppendedTaggedPhrase(List<TaggedText> tags, INonViralName nonViralName){
709
        String appendedPhrase = nonViralName ==null ? null : nonViralName.getAppendedPhrase();
710
        if (isNotBlank(appendedPhrase)){
711
            tags.add(new TaggedText(TagEnum.name, appendedPhrase));
712
        }
713
    }
714

    
715
	@Override
716
    public String getLastEpithet(TaxonName taxonName) {
717
        Rank rank = taxonName.getRank();
718
        if(rank.isGenus() || rank.isSupraGeneric()) {
719
            return taxonName.getGenusOrUninomial();
720
        } else if(rank.isInfraGeneric()) {
721
            return taxonName.getInfraGenericEpithet();
722
        } else if(rank.isSpecies()) {
723
            return taxonName.getSpecificEpithet();
724
        } else {
725
            return taxonName.getInfraSpecificEpithet();
726
        }
727
    }
728

    
729

    
730
}
(6-6/7)