Project

General

Profile

Download (32.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.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.common.UTF8;
22
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
23
import eu.etaxonomy.cdm.model.agent.INomenclaturalAuthor;
24
import eu.etaxonomy.cdm.model.common.CdmBase;
25
import eu.etaxonomy.cdm.model.common.Language;
26
import eu.etaxonomy.cdm.model.common.Representation;
27
import eu.etaxonomy.cdm.model.name.BotanicalName;
28
import eu.etaxonomy.cdm.model.name.HybridRelationship;
29
import eu.etaxonomy.cdm.model.name.INonViralName;
30
import eu.etaxonomy.cdm.model.name.NameRelationship;
31
import eu.etaxonomy.cdm.model.name.NameRelationshipType;
32
import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
33
import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
34
import eu.etaxonomy.cdm.model.name.NonViralName;
35
import eu.etaxonomy.cdm.model.name.Rank;
36
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
37
import eu.etaxonomy.cdm.model.reference.INomenclaturalReference;
38
import eu.etaxonomy.cdm.model.reference.Reference;
39
import eu.etaxonomy.cdm.strategy.cache.HTMLTagRules;
40
import eu.etaxonomy.cdm.strategy.cache.TagEnum;
41
import eu.etaxonomy.cdm.strategy.cache.TaggedCacheHelper;
42
import eu.etaxonomy.cdm.strategy.cache.TaggedText;
43
import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
44
import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImplRegExBase;
45

    
46

    
47
/**
48
 * This class is a default implementation for the INonViralNameCacheStrategy<T extends NonViralName>
49
 * interface.<BR>
50
 * The method implements a cache strategy for botanical names so no method has to be overwritten by
51
 * a subclass for botanic names.
52
 * Where differing from this default botanic name strategy other subclasses should overwrite the
53
 * existing methods, e.g. a CacheStrategy for zoological names should overwrite getAuthorAndExAuthor
54
 * @author a.mueller
55
 */
56
public class NonViralNameDefaultCacheStrategy<T extends INonViralName>
57
        extends NameCacheStrategyBase<T>
58
        implements INonViralNameCacheStrategy<T> {
59
	private static final Logger logger = Logger.getLogger(NonViralNameDefaultCacheStrategy.class);
60
	private static final long serialVersionUID = -6577757501563212669L;
61

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

    
64
    protected String NameAuthorSeperator = " ";
65
    protected String BasionymStart = "(";
66
    protected String BasionymEnd = ")";
67
    protected String ExAuthorSeperator = " ex ";
68
    private static String NOTHO = "notho";
69
    protected CharSequence BasionymAuthorCombinationAuthorSeperator = " ";
70

    
71
    @Override
72
    public  UUID getUuid(){
73
        return uuid;
74
    }
75

    
76

    
77
    /**
78
     * Factory method
79
     * @return NonViralNameDefaultCacheStrategy A new instance of  NonViralNameDefaultCacheStrategy
80
     */
81
    public static NonViralNameDefaultCacheStrategy NewInstance(){
82
        return new NonViralNameDefaultCacheStrategy();
83
    }
84

    
85
    /**
86
     * Factory method
87
     * @return NonViralNameDefaultCacheStrategy A new instance of  NonViralNameDefaultCacheStrategy
88
     */
89
    public static <T extends INonViralName> NonViralNameDefaultCacheStrategy<T> NewInstance(Class<T> clazz){
90
        return new NonViralNameDefaultCacheStrategy<T>();
91
    }
92

    
93
    /**
94
     * Constructor
95
     */
96
    protected NonViralNameDefaultCacheStrategy(){
97
        super();
98
    }
99

    
100
/* **************** GETTER / SETTER **************************************/
101

    
102
    /**
103
     * String that separates the NameCache part from the AuthorCache part
104
     * @return
105
     */
106
    public String getNameAuthorSeperator() {
107
        return NameAuthorSeperator;
108
    }
109

    
110

    
111
    public void setNameAuthorSeperator(String nameAuthorSeperator) {
112
        NameAuthorSeperator = nameAuthorSeperator;
113
    }
114

    
115

    
116
    /**
117
     * String the basionym author part starts with e.g. '('.
118
     * This should correspond with the {@link NonViralNameDefaultCacheStrategy#getBasionymEnd() basionymEnd} attribute
119
     * @return
120
     */
121
    public String getBasionymStart() {
122
        return BasionymStart;
123
    }
124

    
125

    
126
    public void setBasionymStart(String basionymStart) {
127
        BasionymStart = basionymStart;
128
    }
129

    
130

    
131
    /**
132
     * String the basionym author part ends with e.g. ')'.
133
     * This should correspond with the {@link NonViralNameDefaultCacheStrategy#getBasionymStart() basionymStart} attribute
134
     * @return
135
     */
136
    public String getBasionymEnd() {
137
        return BasionymEnd;
138
    }
139

    
140

    
141
    public void setBasionymEnd(String basionymEnd) {
142
        BasionymEnd = basionymEnd;
143
    }
144

    
145

    
146
    /**
147
     * String to separate ex author from author.
148
     * @return
149
     */
150
    public String getExAuthorSeperator() {
151
        return ExAuthorSeperator;
152
    }
153

    
154

    
155
    public void setExAuthorSeperator(String exAuthorSeperator) {
156
        ExAuthorSeperator = exAuthorSeperator;
157
    }
158

    
159

    
160
    /**
161
     * String that separates the basionym/original_combination author part from the combination author part
162
     * @return
163
     */
164
    public CharSequence getBasionymAuthorCombinationAuthorSeperator() {
165
        return BasionymAuthorCombinationAuthorSeperator;
166
    }
167

    
168

    
169
    public void setBasionymAuthorCombinationAuthorSeperator( CharSequence basionymAuthorCombinationAuthorSeperator) {
170
        BasionymAuthorCombinationAuthorSeperator = basionymAuthorCombinationAuthorSeperator;
171
    }
172

    
173

    
174
//** *****************************************************************************************/
175

    
176
    @Override
177
    public String getTitleCache(T nonViralName) {
178
    	return getTitleCache(nonViralName, null);
179
    }
180

    
181
    @Override
182
	public String getTitleCache(T nonViralName, HTMLTagRules htmlTagRules) {
183
    	List<TaggedText> tags = getTaggedTitle(nonViralName);
184
		if (tags == null){
185
			return null;
186
		}else{
187
			String result = createString(tags, htmlTagRules);
188
		    return result;
189
		}
190
    }
191

    
192
	@Override
193
	public String getFullTitleCache(T nonViralName, HTMLTagRules htmlTagRules) {
194
		List<TaggedText> tags = getTaggedFullTitle(nonViralName);
195
	    if (tags == null){
196
	    	return null;
197
	    }else{
198
	    	String result = createString(tags, htmlTagRules);
199
	    	return result;
200
	    }
201
	}
202

    
203
    @Override
204
    public String getFullTitleCache(T nonViralName) {
205
    	return getFullTitleCache(nonViralName, null);
206
    }
207

    
208

    
209
    /**
210
     * Generates and returns the "name cache" (only scientific name without author teams and year).
211
     * @see eu.etaxonomy.cdm.strategy.cache.name.INameCacheStrategy#getNameCache(eu.etaxonomy.cdm.model.name.TaxonNameBase)
212
     */
213
    @Override
214
    public String getNameCache(T nonViralName) {
215
        List<TaggedText> tags = getTaggedName(nonViralName);
216
        if (tags == null){
217
            return null;
218
        }else{
219
            String result = createString(tags);
220
            return result;
221
        }
222
    }
223

    
224

    
225

    
226

    
227

    
228

    
229

    
230
// ******************* Authorship ******************************/
231

    
232

    
233
    @Override
234
    public String getAuthorshipCache(T nonViralName) {
235
        if (nonViralName == null){
236
            return null;
237
        }
238
        //cache protected
239
        if (nonViralName.isProtectedAuthorshipCache() == true) {
240
            return nonViralName.getAuthorshipCache();
241
        }
242
        return getNonCacheAuthorshipCache(nonViralName);
243

    
244
    }
245

    
246
    /**
247
     * Returns the authorshipcache string for the atomized authorship fields. Does not use the authorship field.
248
     * @throws NullPointerException if nonViralName is null.
249
     * @param nonViralName
250
     * @return
251
     */
252
    protected String getNonCacheAuthorshipCache(T nonViralName){
253
        String result = "";
254
        INomenclaturalAuthor combinationAuthor = nonViralName.getCombinationAuthorship();
255
        INomenclaturalAuthor exCombinationAuthor = nonViralName.getExCombinationAuthorship();
256
        INomenclaturalAuthor basionymAuthor = nonViralName.getBasionymAuthorship();
257
        INomenclaturalAuthor exBasionymAuthor = nonViralName.getExBasionymAuthorship();
258
        String basionymPart = "";
259
        String authorPart = "";
260
        //basionym
261
        if (basionymAuthor != null || exBasionymAuthor != null){
262
            basionymPart = BasionymStart + getAuthorAndExAuthor(basionymAuthor, exBasionymAuthor) + BasionymEnd;
263
        }
264
        if (combinationAuthor != null || exCombinationAuthor != null){
265
            authorPart = getAuthorAndExAuthor(combinationAuthor, exCombinationAuthor);
266
        }
267
        result = CdmUtils.concat(BasionymAuthorCombinationAuthorSeperator, basionymPart, authorPart);
268
//        if ("".equals(result)){
269
//        	result = null;
270
//        }
271
        return result;
272
    }
273

    
274
    /**
275
     * Returns the AuthorCache part for a combination of an author and an ex author. This applies on combination authors
276
     * as well as on basionym/orginal combination authors.
277
     * @param author the author
278
     * @param exAuthor the ex-author
279
     * @return
280
     */
281
    protected String getAuthorAndExAuthor(INomenclaturalAuthor author, INomenclaturalAuthor exAuthor){
282
        String result = "";
283
        String authorString = "";
284
        String exAuthorString = "";
285
        if (author != null){
286
            authorString = CdmUtils.Nz(author.getNomenclaturalTitle());
287
        }
288
        if (exAuthor != null){
289
            exAuthorString = CdmUtils.Nz(exAuthor.getNomenclaturalTitle());
290
        }
291
        if (exAuthorString.length() > 0 ){
292
            exAuthorString = exAuthorString + ExAuthorSeperator;
293
        }
294
        result = exAuthorString + authorString;
295
        return result;
296
    }
297

    
298

    
299
    /**
300
     * Checks if the given name should include the author in it's cached version.<BR>
301
     * This is usually the case but not for <i>species aggregates</i>.
302
     * @param nonViralName
303
     * @return
304
     */
305
    protected boolean nameIncludesAuthorship(INonViralName nonViralName){
306
        Rank rank = nonViralName.getRank();
307
        if (rank != null && rank.isSpeciesAggregate()){
308
            return false;
309
        }else{
310
            return true;
311
        }
312
    }
313

    
314
// ************* TAGGED NAME ***************************************/
315

    
316
    @Override
317
    public List<TaggedText> getTaggedFullTitle(T nonViralName) {
318
        List<TaggedText> tags = new ArrayList<TaggedText>();
319

    
320
        //null
321
        if (nonViralName == null){
322
            return null;
323
        }
324

    
325
        //protected full title cache
326
        if (nonViralName.isProtectedFullTitleCache()){
327
            tags.add(new TaggedText(TagEnum.fullName, nonViralName.getFullTitleCache()));
328
            return tags;
329
        }
330

    
331
        //title cache
332
//		String titleCache = nonViralName.getTitleCache();
333
        List<TaggedText> titleTags = getTaggedTitle(nonViralName);
334
        tags.addAll(titleTags);
335

    
336

    
337
        //reference
338
        String microReference = nonViralName.getNomenclaturalMicroReference();
339
        INomenclaturalReference ref = nonViralName.getNomenclaturalReference();
340
        String referenceCache = null;
341
        if (ref != null){
342
            Reference reference = HibernateProxyHelper.deproxy(ref, Reference.class);
343
            referenceCache = reference.getNomenclaturalCitation(microReference);
344
        }
345
            //add to tags
346
        if (StringUtils.isNotBlank(referenceCache)){
347
            if (! referenceCache.trim().startsWith("in ")){
348
                String refConcat = ", ";
349
                tags.add(new TaggedText(TagEnum.separator, refConcat));
350
            }
351
            tags.add(new TaggedText(TagEnum.reference, referenceCache));
352
        }
353

    
354
        //nomenclatural status
355
        tags.addAll(getNomStatusTags(nonViralName, true, false));
356
        return tags;
357

    
358
    }
359

    
360

    
361
    /**
362
     * @param nonViralName
363
     * @param tags
364
     * @return
365
     */
366
    @Override
367
    public List<TaggedText> getNomStatusTags(T nonViralName, boolean includeSeparatorBefore,
368
            boolean includeSeparatorAfter) {
369
        Set<NomenclaturalStatus> ncStati = nonViralName.getStatus();
370
        Iterator<NomenclaturalStatus> iterator = ncStati.iterator();
371
        List<TaggedText> nomStatusTags = new ArrayList<TaggedText>();
372
        while (iterator.hasNext()) {
373
            NomenclaturalStatus ncStatus = iterator.next();
374
            // since the NewInstance method of nomencatural status allows null as parameter
375
            // we have to check for null values here
376
            String nomStatusStr = "not defined";
377
            if(ncStatus.getType() != null){
378
                NomenclaturalStatusType statusType =  ncStatus.getType();
379
                Language lang = Language.LATIN();
380
                Representation repr = statusType.getRepresentation(lang);
381
                if (repr != null){
382
                    nomStatusStr = repr.getAbbreviatedLabel();
383
                }else{
384
                    String message = "No latin representation available for nom. status. " + statusType.getTitleCache();
385
                    logger.warn(message);
386
                    throw new IllegalStateException(message);
387
                }
388
            }else if(StringUtils.isNotBlank(ncStatus.getRuleConsidered())){
389
                nomStatusStr = ncStatus.getRuleConsidered();
390
            }
391
            String statusSeparator = ", ";
392
            if (includeSeparatorBefore){
393
                nomStatusTags.add(new TaggedText(TagEnum.separator, statusSeparator));
394
            }
395
            nomStatusTags.add(new TaggedText(TagEnum.nomStatus, nomStatusStr));
396
            if (includeSeparatorAfter){
397
                nomStatusTags.add(new TaggedText(TagEnum.postSeparator, ","));
398
            }
399
        }
400
        return nomStatusTags;
401
    }
402

    
403
    @Override
404
    public List<TaggedText> getTaggedTitle(T nonViralName) {
405
        if (nonViralName == null){
406
            return null;
407
        }
408

    
409
        List<TaggedText> tags = new ArrayList<TaggedText>();
410

    
411
        //TODO how to handle protected fullTitleCache here?
412

    
413
        if (nonViralName.isProtectedTitleCache()){
414
            //protected title cache
415
            tags.add(new TaggedText(TagEnum.name, nonViralName.getTitleCache()));
416
            return tags;
417
        }else if (nonViralName.isHybridFormula()){
418
            //hybrid formula
419
            String hybridSeparator = NonViralNameParserImplRegExBase.hybridSign;
420
            boolean isFirst = true;
421
            List<HybridRelationship> rels = nonViralName.getOrderedChildRelationships();
422
            for (HybridRelationship rel: rels){
423
                if (! isFirst){
424
                    tags.add(new TaggedText(TagEnum.hybridSign, hybridSeparator));
425
                }
426
                isFirst = false;
427
                tags.addAll(getTaggedTitle((T)rel.getParentName()));
428
            }
429
            return tags;
430
        }else if (nonViralName.isAutonym()){
431
            //Autonym
432
            tags.addAll(handleTaggedAutonym(nonViralName));
433
        }else{ //not Autonym
434
//			String nameCache = nonViralName.getNameCache();  //OLD: CdmUtils.Nz(getNameCache(nonViralName));
435

    
436
            List<TaggedText> nameTags = getTaggedName(nonViralName);
437
            tags.addAll(nameTags);
438
            String authorCache = getAuthorshipCache(nonViralName);
439
            if (StringUtils.isNotBlank(authorCache)){
440
                tags.add(new TaggedText(TagEnum.authors, authorCache));
441
            }
442
        }
443
        return tags;
444
    }
445

    
446
    /**
447
     * Returns the tag list of the name part (without author and reference).
448
     * @param nonViralName
449
     * @return
450
     */
451
    @Override
452
    public List<TaggedText> getTaggedName(T nonViralName) {
453
        if (nonViralName == null){
454
            return null;
455
        }
456
        List<TaggedText> tags = new ArrayList<TaggedText>();
457
        Rank rank = nonViralName.getRank();
458

    
459
        if (nonViralName.isProtectedNameCache()){
460
            tags.add(new TaggedText(TagEnum.name, nonViralName.getNameCache()));
461
        }else if (rank == null){
462
            tags = getRanklessTaggedNameCache(nonViralName);
463
//		}else if (nonViralName.isInfragenericUnranked()){
464
//			result = getUnrankedInfragenericNameCache(nonViralName);
465
        }else if (rank.isInfraSpecific()){
466
            tags = getInfraSpeciesTaggedNameCache(nonViralName);
467
        }else if (rank.isSpecies() || isAggregateWithAuthorship(nonViralName, rank) ){ //exception see #4288
468
            tags = getSpeciesTaggedNameCache(nonViralName);
469
        }else if (rank.isInfraGeneric()){
470
            tags = getInfraGenusTaggedNameCache(nonViralName);
471
        }else if (rank.isGenus()){
472
            tags = getGenusOrUninomialTaggedNameCache(nonViralName);
473
        }else if (rank.isSupraGeneric()){
474
            tags = getGenusOrUninomialTaggedNameCache(nonViralName);
475
        }else{
476
            logger.warn("Name Strategy for Name (UUID: " + nonViralName.getUuid() +  ") not yet implemented");
477
        }
478
        //TODO handle appended phrase here instead of different places, check first if this is true for all
479
        //cases
480

    
481
        return tags;
482

    
483
    }
484

    
485

    
486

    
487

    
488
//***************************** PRIVATES ***************************************/
489

    
490

    
491
    private boolean isAggregateWithAuthorship(T nonViralName, Rank rank) {
492
		if (rank == null){
493
			return false;
494
		}else{
495
			return rank.isSpeciesAggregate() && ( isNotBlank(nonViralName.getAuthorshipCache()) || nonViralName.getNomenclaturalReference() != null );
496
		}
497
	}
498

    
499

    
500
	/**
501
     * Returns the tag list for an autonym taxon.
502
     *
503
     * @see NonViralName#isAutonym()
504
     * @see BotanicalName#isAutonym()
505
     * @param nonViralName
506
     * @return
507
     */
508
    private List<TaggedText> handleTaggedAutonym(T nonViralName) {
509
    	List<TaggedText> tags = null;
510
    	if (nonViralName.isInfraSpecific()){
511
	        //species part
512
	        tags = getSpeciesTaggedNameCache(nonViralName);
513

    
514
	        //author
515
	        String authorCache = getAuthorshipCache(nonViralName);
516
	        if (StringUtils.isNotBlank(authorCache)){
517
	            tags.add(new TaggedText(TagEnum.authors, authorCache));
518
	        }
519

    
520

    
521
	        //infra species marker
522
	        if (nonViralName.getRank() == null || !nonViralName.getRank().isInfraSpecific()){
523
	            //TODO handle exception
524
	            logger.warn("Rank for autonym does not exist or is not lower than species !!");
525
	        }else{
526
	            String infraSpeciesMarker = nonViralName.getRank().getAbbreviation();
527
	            if (StringUtils.isNotBlank(infraSpeciesMarker)){
528
	                tags.add(new TaggedText(TagEnum.rank, infraSpeciesMarker));
529
	            }
530
	        }
531

    
532
	        //infra species
533
	        String infraSpeciesPart = CdmUtils.Nz(nonViralName.getInfraSpecificEpithet()).trim();
534
	        if (StringUtils.isNotBlank(infraSpeciesPart)){
535
	            tags.add(new TaggedText(TagEnum.name, infraSpeciesPart));
536
	        }
537

    
538
        } else if (nonViralName.isInfraGeneric()){
539
        	//genus part
540
	       tags =getGenusOrUninomialTaggedNameCache(nonViralName);
541

    
542

    
543
	        //infra species marker
544
	        if (nonViralName.getRank() == null || !nonViralName.getRank().isInfraGeneric()){
545
	            //TODO handle exception
546
	            logger.warn("Rank for autonym does not exist or is not lower than species !!");
547
	        }else{
548
	        	Rank rank = nonViralName.getRank();
549
	            String infraGenericMarker = rank.getAbbreviation();
550
                if (rank.equals(Rank.SECTION_BOTANY()) || rank.equals(Rank.SUBSECTION_BOTANY())){
551
                	infraGenericMarker = infraGenericMarker.replace("(bot.)", "");
552
                }
553
	            if (StringUtils.isNotBlank(infraGenericMarker)){
554
	                tags.add(new TaggedText(TagEnum.rank, infraGenericMarker));
555
	            }
556
	        }
557

    
558
	        //infra species
559
	        String infraGenericPart = CdmUtils.Nz(nonViralName.getInfraGenericEpithet()).trim();
560
	        if (StringUtils.isNotBlank(infraGenericPart)){
561
	            tags.add(new TaggedText(TagEnum.name, infraGenericPart));
562
	        }
563

    
564
        }
565

    
566
        return tags;
567
    }
568

    
569

    
570

    
571
    /**
572
     * Returns the tag list for rankless taxa.
573
     * @param nonViralName
574
     * @return
575
     */
576
    protected List<TaggedText> getRanklessTaggedNameCache(INonViralName nonViralName){
577
        List<TaggedText> tags = getUninomialTaggedPart(nonViralName);
578
        String speciesEpi = CdmUtils.Nz(nonViralName.getSpecificEpithet()).trim();
579
        if (StringUtils.isNotBlank(speciesEpi)){
580
            tags.add(new TaggedText(TagEnum.name, speciesEpi));
581
        }
582

    
583
        String infraSpeciesEpi = CdmUtils.Nz(nonViralName.getInfraSpecificEpithet());
584
        if (StringUtils.isNotBlank(infraSpeciesEpi)){
585
            tags.add(new TaggedText(TagEnum.name, infraSpeciesEpi));
586
        }
587

    
588
        //result += " (rankless)";
589
        addAppendedTaggedPhrase(tags, nonViralName);
590
        return tags;
591
    }
592

    
593
    /**
594
     * Returns the tag list for the first epithet (including a hybrid sign if required).
595
     * @param nonViralName
596
     * @return
597
     */
598
    private List<TaggedText> getUninomialTaggedPart(INonViralName nonViralName) {
599
        List<TaggedText> tags = new ArrayList<TaggedText>();
600

    
601
        if (nonViralName.isMonomHybrid()){
602
            addHybridPrefix(tags);
603
        }
604

    
605
        String uninomial = CdmUtils.Nz(nonViralName.getGenusOrUninomial()).trim();
606
        if (StringUtils.isNotBlank(uninomial)){
607
            tags.add(new TaggedText(TagEnum.name, uninomial));
608
        }
609

    
610
        return tags;
611
    }
612

    
613
    /**
614
     * Returns the tag list for an genus or higher taxon.
615
     *
616
     * @param nonViralName
617
     * @return
618
     */
619
    protected List<TaggedText> getGenusOrUninomialTaggedNameCache(INonViralName nonViralName){
620
        List<TaggedText> tags = getUninomialTaggedPart(nonViralName);
621
        addAppendedTaggedPhrase(tags, nonViralName);
622
        return tags;
623
    }
624

    
625
    /**
626
     * Returns the tag list for an infrageneric taxon (including species aggregates).
627
     *
628
     * @see #getSpeciesAggregateTaggedCache(NonViralName)
629
     * @param nonViralName
630
     * @return
631
     */
632
    protected List<TaggedText> getInfraGenusTaggedNameCache(INonViralName nonViralName){
633
        Rank rank = nonViralName.getRank();
634
        if (rank != null && rank.isSpeciesAggregate() && isBlank(nonViralName.getAuthorshipCache())){
635
            return getSpeciesAggregateTaggedCache(nonViralName);
636
        }
637

    
638
        //genus
639
        List<TaggedText> tags = getUninomialTaggedPart(nonViralName);
640

    
641
        //marker
642
        String infraGenericMarker;
643
        if (rank != null){
644
            try {
645
                infraGenericMarker = rank.getInfraGenericMarker();
646
                if (rank.equals(Rank.SECTION_BOTANY()) || rank.equals(Rank.SUBSECTION_BOTANY())){
647
                	infraGenericMarker = infraGenericMarker.replace("(bot.)", "");
648
                }
649
            } catch (UnknownCdmTypeException e) {
650
                infraGenericMarker = "'unhandled infrageneric rank'";
651
            }
652
        }else{
653
        	infraGenericMarker = "'undefined infrageneric rank'";
654
        }
655
        String infraGenEpi = CdmUtils.Nz(nonViralName.getInfraGenericEpithet()).trim();
656
        if (nonViralName.isBinomHybrid()){
657
            infraGenericMarker = CdmUtils.concat("", NOTHO, infraGenericMarker);
658
        }
659

    
660
        addInfraGenericPart(nonViralName, tags, infraGenericMarker, infraGenEpi);
661

    
662
        addAppendedTaggedPhrase(tags, nonViralName);
663
        return tags;
664
    }
665

    
666

    
667
	/**
668
	 * Default implementation for the infrageneric part of a name.
669
	 * This is usually the infrageneric marker and the infrageneric epitheton. But may be
670
	 * implemented differently e.g. for zoological names the infrageneric epitheton
671
	 * may be surrounded by brackets and the marker left out.
672
	 * @param nonViralName
673
	 * @param tags
674
	 * @param infraGenericMarker
675
	 */
676
	protected void addInfraGenericPart(
677
	        @SuppressWarnings("unused") INonViralName name,
678
	        List<TaggedText> tags,
679
	        String infraGenericMarker,
680
	        String infraGenEpi) {
681
		//add marker
682
		tags.add(new TaggedText(TagEnum.rank, infraGenericMarker));
683

    
684
		//add epitheton
685
		if (StringUtils.isNotBlank(infraGenEpi)){
686
            tags.add(new TaggedText(TagEnum.name, infraGenEpi));
687
        }
688
	}
689

    
690
    /**
691
     * Returns the tag list for a species aggregate (or similar) taxon.<BR>
692
     * Possible ranks for a <i>species aggregate</i> are "aggr.", "species group", ...
693
     * @param nonViralName
694
     * @return
695
     */
696
    protected List<TaggedText> getSpeciesAggregateTaggedCache(INonViralName nonViralName){
697
        if (! isBlank(nonViralName.getAuthorshipCache())){
698
        	List<TaggedText> result = getSpeciesTaggedNameCache(nonViralName);
699
        	return result;
700
        }
701

    
702

    
703
    	List<TaggedText> tags = getGenusAndSpeciesTaggedPart(nonViralName);
704

    
705
        addSpeciesAggregateTaggedEpithet(tags, nonViralName);
706
        addAppendedTaggedPhrase(tags, nonViralName);
707
        return tags;
708
    }
709

    
710
    /**
711
     * Adds the aggregate tag to the tag list.
712
     * @param tags
713
     * @param nonViralName
714
     */
715
    private void addSpeciesAggregateTaggedEpithet(List<TaggedText> tags, INonViralName nonViralName) {
716
        String marker;
717
        try {
718
            marker = nonViralName.getRank().getInfraGenericMarker();
719
        } catch (UnknownCdmTypeException e) {
720
            marker = "'unknown aggregat type'";
721
        }
722
        if (StringUtils.isNotBlank(marker)){
723
            tags.add(new TaggedText(TagEnum.rank, marker));
724
        }
725
    }
726

    
727

    
728
    /**
729
     * Returns the tag list for a species taxon.
730
     * @param nonViralName
731
     * @return
732
     */
733
    protected List<TaggedText> getSpeciesTaggedNameCache(INonViralName nonViralName){
734
        List<TaggedText> tags = getGenusAndSpeciesTaggedPart(nonViralName);
735
        addAppendedTaggedPhrase(tags, nonViralName);
736
        return tags;
737
    }
738

    
739
    /**
740
     * Creates the tag list for an infraspecific taxon. In include is true the result will contain
741
     * @param nonViralName
742
     * @return
743
     */
744
    protected List<TaggedText> getInfraSpeciesTaggedNameCache(T nonViralName){
745
        return getInfraSpeciesTaggedNameCache(nonViralName, true);
746
    }
747

    
748
    /**
749
     * Creates the tag list for an infraspecific taxon. If include is true the result will contain
750
     * the infraspecific marker (e.g. "var.")
751
     * @param nonViralName
752
     * @param includeMarker
753
     * @return
754
     */
755
    protected List<TaggedText> getInfraSpeciesTaggedNameCache(INonViralName nonViralName, boolean includeMarker){
756
        List<TaggedText> tags = getGenusAndSpeciesTaggedPart(nonViralName);
757
        if (includeMarker || nonViralName.isTrinomHybrid()){
758
            String marker = (nonViralName.getRank().getAbbreviation()).trim().replace("null", "");
759
            if (nonViralName.isTrinomHybrid()){
760
                marker = CdmUtils.concat("", NOTHO, marker);
761
            }
762
            if (StringUtils.isNotBlank(marker)){
763
                tags.add(new TaggedText(TagEnum.rank, marker));
764
            }
765

    
766
        }
767
        String infrSpecEpi = CdmUtils.Nz(nonViralName.getInfraSpecificEpithet());
768

    
769
        infrSpecEpi = infrSpecEpi.trim().replace("null", "");
770

    
771
        if (StringUtils.isNotBlank(infrSpecEpi)){
772
            tags.add(new TaggedText(TagEnum.name, infrSpecEpi));
773
        }
774

    
775
        addAppendedTaggedPhrase(tags, nonViralName);
776
        return tags;
777
    }
778

    
779

    
780
    /**
781
     * Adds a tag for the hybrid sign and an empty separator to avoid trailing whitespaces.
782
     * @param tags
783
     */
784
    private void addHybridPrefix(List<TaggedText> tags) {
785
        tags.add(new TaggedText(TagEnum.hybridSign, NonViralNameParserImplRegExBase.hybridSign));
786
        tags.add(new TaggedText(TagEnum.separator, "")); //no whitespace separator
787
    }
788

    
789
    /**
790
     * Creates the tag list for the genus and species part.
791
     * @param nonViralName
792
     * @return
793
     */
794
    private List<TaggedText> getGenusAndSpeciesTaggedPart(INonViralName nonViralName) {
795
        //Uninomial
796
        List<TaggedText> tags = getUninomialTaggedPart(nonViralName);
797

    
798
        //InfraGenericEpi
799
        boolean hasInfraGenericEpi = StringUtils.isNotBlank(nonViralName.getInfraGenericEpithet());
800
        if (hasInfraGenericEpi){
801
            String infrGenEpi = nonViralName.getInfraGenericEpithet().trim();
802
            if (nonViralName.isBinomHybrid()){
803
                //maybe not correct but not really expected to happen
804
                infrGenEpi = UTF8.HYBRID + infrGenEpi;
805
            }
806
            infrGenEpi = "(" + infrGenEpi + ")";
807
            tags.add(new TaggedText(TagEnum.name, infrGenEpi));
808
        }
809

    
810
        //Species Epi
811
        String specEpi = CdmUtils.Nz(nonViralName.getSpecificEpithet()).trim();
812
        if (! hasInfraGenericEpi && nonViralName.isBinomHybrid() ||
813
                hasInfraGenericEpi && nonViralName.isTrinomHybrid()){
814
            addHybridPrefix(tags);
815
        }
816
        if (StringUtils.isNotBlank(specEpi)){
817
            tags.add(new TaggedText(TagEnum.name, specEpi));
818
        }
819
        return tags;
820
    }
821

    
822
    /**
823
     * Adds the tag for the appended phrase if an appended phrase exists
824
     * @param tags
825
     * @param nonViralName
826
     */
827
    protected void addAppendedTaggedPhrase(List<TaggedText> tags, INonViralName nonViralName){
828
        String appendedPhrase = nonViralName ==null ? null : nonViralName.getAppendedPhrase();
829
        String originalName = getOriginalNameString(nonViralName, tags);
830
        if (StringUtils.isNotBlank(originalName)){
831
            tags.add(new TaggedText(TagEnum.name, originalName));
832
        }
833
        if (StringUtils.isNotEmpty(appendedPhrase)){
834
            tags.add(new TaggedText(TagEnum.name, appendedPhrase));
835
        }
836
    }
837

    
838
    private String getOriginalNameString(INonViralName currentName, List<TaggedText> originalNameTaggs) {
839
		List<String> originalNameStrings = new ArrayList<>(1);
840
		currentName = CdmBase.deproxy(currentName);
841
		//Hibernate.initialize(currentName.getRelationsToThisName());
842
    	for (NameRelationship nameRel : currentName.getRelationsToThisName()){  //handle list, just in case we have strange data; this may result in strange looking results
843
			NameRelationshipType type = nameRel.getType();
844
    		if(type != null && type.equals(NameRelationshipType.ORIGINAL_SPELLING())){
845
    			String originalNameString;
846
    			TaxonNameBase<?,?> originalName = nameRel.getFromName();
847
    			if (!originalName.isInstanceOf(NonViralName.class)){
848
    				originalNameString = originalName.getTitleCache();
849
    			}else{
850
    				INonViralName originalNvName = CdmBase.deproxy(originalName);
851
    				originalNameString = makeOriginalNameString(currentName, originalNvName, originalNameTaggs);
852
    			}
853
    			originalNameStrings.add("'" + originalNameString +"'");
854
    		}
855
		}
856
    	if (originalNameStrings.size() > 0){
857
    		String result = CdmUtils.concat("", originalNameStrings.toArray(new String[originalNameStrings.size()])) ;
858
	    	return result;
859
    	}else{
860
    		return null;
861
    	}
862
	}
863

    
864

    
865
	private String makeOriginalNameString(INonViralName currentName, INonViralName originalName,
866
	        List<TaggedText> currentNameTags) {
867
		//use cache if necessary
868
		String cacheToUse = null;
869
		if (originalName.isProtectedNameCache() && StringUtils.isNotBlank(originalName.getNameCache())){
870
			cacheToUse = originalName.getNameCache();
871
		}else if (originalName.isProtectedTitleCache() && StringUtils.isNotBlank(originalName.getTitleCache())){
872
			cacheToUse = originalName.getTitleCache();
873
		}else if (originalName.isProtectedFullTitleCache() && StringUtils.isNotBlank(originalName.getFullTitleCache())){
874
			cacheToUse = originalName.getFullTitleCache();
875
		}
876
		if (cacheToUse != null){
877
			return cacheToUse;
878
		}
879
		//use atomized data
880
		//get originalNameParts array
881
		String originalNameString = originalName.getNameCache();
882
		if (originalNameString == null){
883
			originalNameString = originalName.getTitleCache();
884
		}
885
		if (originalNameString == null){  //should not happen
886
			originalNameString = originalName.getFullTitleCache();
887
		}
888
		String[] originalNameSplit = originalNameString.split("\\s+");
889

    
890
		//get current name parts
891
		String currentNameString = createString(currentNameTags);
892
		String[] currentNameSplit = currentNameString.split("\\s+");
893

    
894
		//compute string
895
		String result = originalNameString;
896
		for (int i = 0; i < Math.min(originalNameSplit.length, currentNameSplit.length); i++){
897
			if (originalNameSplit[i].equals(currentNameSplit[i])){
898
				result = result.replaceFirst(originalNameSplit[i], "").trim();
899
			}
900
		}
901
		//old
902
//		if (originalName.getGenusOrUninomial() != null && originalName.getGenusOrUninomial().equals(currentName.getGenusOrUninomial())){
903
//
904
//		}
905
		return result;
906
	}
907

    
908

    
909
	@Override
910
    public String getLastEpithet(T taxonNameBase) {
911
        Rank rank = taxonNameBase.getRank();
912
        if(rank.isGenus() || rank.isSupraGeneric()) {
913
            return taxonNameBase.getGenusOrUninomial();
914
        } else if(rank.isInfraGeneric()) {
915
            return taxonNameBase.getInfraGenericEpithet();
916
        } else if(rank.isSpecies()) {
917
            return taxonNameBase.getSpecificEpithet();
918
        } else {
919
            return taxonNameBase.getInfraSpecificEpithet();
920
        }
921
    }
922

    
923

    
924
    /**
925
     * @param tags
926
     * @return
927
     */
928
    private String createString(List<TaggedText> tags) {
929
        return TaggedCacheHelper.createString(tags);
930
    }
931

    
932
    /**
933
     * @param tags
934
     * @param htmlTagRules
935
     * @return
936
     */
937
    private String createString(List<TaggedText> tags, HTMLTagRules htmlTagRules) {
938
        return TaggedCacheHelper.createString(tags, htmlTagRules);
939
    }
940

    
941

    
942

    
943
}
(7-7/9)