Project

General

Profile

Download (11.4 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2018 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.format.taxon;
10

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

    
14
import org.apache.commons.lang3.StringUtils;
15

    
16
import eu.etaxonomy.cdm.common.CdmUtils;
17
import eu.etaxonomy.cdm.common.UTF8;
18
import eu.etaxonomy.cdm.model.agent.Person;
19
import eu.etaxonomy.cdm.model.agent.Team;
20
import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
21
import eu.etaxonomy.cdm.model.common.CdmBase;
22
import eu.etaxonomy.cdm.model.common.Language;
23
import eu.etaxonomy.cdm.model.name.TaxonName;
24
import eu.etaxonomy.cdm.model.reference.Reference;
25
import eu.etaxonomy.cdm.model.taxon.Taxon;
26
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
27
import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
28
import eu.etaxonomy.cdm.model.term.Representation;
29
import eu.etaxonomy.cdm.ref.TypedEntityReference;
30
import eu.etaxonomy.cdm.strategy.cache.TagEnum;
31
import eu.etaxonomy.cdm.strategy.cache.TaggedText;
32
import eu.etaxonomy.cdm.strategy.cache.TaggedTextBuilder;
33
import eu.etaxonomy.cdm.strategy.cache.agent.TeamDefaultCacheStrategy;
34

    
35
/**
36
 * Formatter for TaxonRelationships.
37
 *
38
 * @author a.mueller
39
 * @since 13.08.2018
40
 */
41
public class TaxonRelationshipFormatter {
42

    
43
    private static final String DOUBTFUL_TAXON_MARKER = "?" + UTF8.NARROW_NO_BREAK;
44
    private static final String REL_SEC = ", rel. sec. ";
45
    private static final String ERR_SEC = ", err. sec. ";
46
    private static final String SYN_SEC = ", syn. sec. ";
47
    private static final String UNKNOWN_SEC = "???";
48
    private static final String NON_SEPARATOR = ", non ";
49
    private static final String QUOTE_START = "\"";   //TODO
50
    private static final String QUOTE_END = "\"";   //TODO
51
    private static final String AUCT = "auct.";
52
    private static final String SENSU_SEPARATOR = " sensu ";
53
    private static final String SEC_SEPARATOR = " sec. ";
54
    private static final String DETAIL_SEPARATOR = ": ";
55
    private static final String INVERT_SYMBOL = "<-"; //TODO
56
    private static final String UNDEFINED_SYMBOL = "??";  //TODO
57

    
58
    public List<TaggedText> getTaggedText(TaxonRelationship taxonRelationship, boolean reverse, List<Language> languages) {
59
        return getTaggedText(taxonRelationship, reverse, languages, false);
60
    }
61

    
62
    public List<TaggedText> getTaggedText(TaxonRelationship taxonRelationship, boolean reverse,
63
            List<Language> languages, boolean withoutName) {
64

    
65
        if (taxonRelationship == null){
66
            return null;
67
        }
68

    
69
        TaxonRelationshipType type = taxonRelationship.getType();
70
        boolean isMisapplied = type == null ? false : type.isMisappliedNameOrInvalidDesignation() && reverse;
71
        boolean isSynonym = type == null? false : type.isAnySynonym();
72

    
73
        Taxon relatedTaxon = reverse? taxonRelationship.getFromTaxon()
74
                : taxonRelationship.getToTaxon();
75

    
76
        if (relatedTaxon == null){
77
            return null;
78
        }
79

    
80
        String doubtfulTaxonStr = relatedTaxon.isDoubtful() ? DOUBTFUL_TAXON_MARKER : "";
81
        String doubtfulRelationStr = taxonRelationship.isDoubtful() ? "?" : "";
82

    
83
        TaxonName name = relatedTaxon.getName();
84

    
85
        TaggedTextBuilder builder = new TaggedTextBuilder();
86

    
87
        //rel symbol
88
        String symbol = doubtfulRelationStr + getSymbol(type, reverse, languages);
89
        builder.add(TagEnum.symbol, symbol);
90

    
91
        //name
92
        if (!withoutName){
93
            if (isMisapplied){
94
                //starting quote
95
                String startQuote = " " + doubtfulTaxonStr + QUOTE_START;
96
                builder.addSeparator(startQuote);
97

    
98
                //name cache
99
                List<TaggedText> nameCacheTags = getNameCacheTags(name);
100
                builder.addAll(nameCacheTags);
101

    
102
                //end quote
103
                String endQuote = QUOTE_END;
104
                builder.add(TagEnum.postSeparator, endQuote);
105
            }else{
106
                builder.addSeparator(" " + doubtfulTaxonStr);
107
                //name full title cache
108
                List<TaggedText> nameCacheTags = getNameTitleCacheTags(name);
109
                builder.addAll(nameCacheTags);
110
            }
111
        }else{
112
            if (isNotBlank(doubtfulTaxonStr)){
113
                builder.addSeparator(" " + doubtfulTaxonStr);
114
            }
115
        }
116

    
117
        //sec/sensu (+ Separatoren?)
118
        if (isNotBlank(relatedTaxon.getAppendedPhrase())){
119
            builder.addWhitespace();
120
            builder.add(TagEnum.appendedPhrase, relatedTaxon.getAppendedPhrase());
121
        }
122
        List<TaggedText> secTags = getReferenceTags(relatedTaxon.getSec(), relatedTaxon.getSecMicroReference(),
123
               /* isMisapplied,*/ false);
124
        if (!secTags.isEmpty()) {
125
            builder.addSeparator(isMisapplied? SENSU_SEPARATOR : SEC_SEPARATOR);
126
            builder.addAll(secTags);
127
        }else if (isBlank(relatedTaxon.getAppendedPhrase())) {
128
            if (isMisapplied){
129
                builder.addWhitespace();
130
                //TODO type unclear sensuReference(?)
131
                builder.add(TagEnum.appendedPhrase, AUCT);
132
            }else{
133
                builder.addSeparator(SEC_SEPARATOR + UNKNOWN_SEC);
134
            }
135
        }
136

    
137
//        //, non author
138
        if (isMisapplied && name != null){
139
            if (isNotBlank(name.getAuthorshipCache())){
140
                builder.addSeparator(NON_SEPARATOR);
141
                builder.add(TagEnum.authors, name.getAuthorshipCache().trim());
142
            }
143
        }
144

    
145
        List<TaggedText> relSecTags = getReferenceTags(taxonRelationship.getCitation(),
146
                taxonRelationship.getCitationMicroReference(),true);
147
        if (!relSecTags.isEmpty()){
148
            builder.addSeparator(isSynonym ? SYN_SEC : isMisapplied ? ERR_SEC : REL_SEC);
149
            builder.addAll(relSecTags);
150
        }
151

    
152
        return builder.getTaggedText();
153
    }
154

    
155
    private List<TaggedText> getReferenceTags(Reference ref, String detail, /*boolean isSensu,*/ boolean isRelation) {
156
        List<TaggedText> result = new ArrayList<>();
157
        String secRef;
158

    
159
        if (ref != null){
160
            TeamOrPersonBase<?> author = ref.getAuthorship();
161
            //TODO distinguish linked and unlinked usage,
162
            // if reference is not linked short citation should only be used
163
            //   if both author and year exists, also initials should be added in this case
164
            //
165
            if (ref.isProtectedTitleCache() == false &&
166
                    author != null &&
167
                    isNotBlank(author.getTitleCache())){
168
                //TODO move to authorFormatter
169
                String familyNames = getFamilyNames(author);
170
                if (isNotBlank(familyNames)){
171
                    secRef = familyNames;
172
                }else{
173
                    secRef = ref.getAuthorship().getTitleCache();
174
                }
175
                if (isNotBlank(ref.getYear())){
176
                   secRef += " " + ref.getYear();
177
                }
178
            }else{
179
                secRef = ref.getTitleCache();
180
            }
181
            TagEnum secType = /*isSensu? TagEnum.sensuReference : */ isRelation? TagEnum.relSecReference : TagEnum.secReference;
182
            TaggedText refTag = TaggedText.NewInstance(secType, secRef);
183
            refTag.setEntityReference(new TypedEntityReference<>(CdmBase.deproxy(ref).getClass(), ref.getUuid()));
184
            result.add(refTag);
185
        }
186
        if (isNotBlank(detail)){
187
            result.add(TaggedText.NewSeparatorInstance(DETAIL_SEPARATOR));
188
            TagEnum detailType = /*isSensu? TagEnum.sensuMicroReference : */ isRelation? TagEnum.relSecMicroReference :TagEnum.secMicroReference;
189
            TaggedText microTag = TaggedText.NewInstance(detailType, detail);
190
            result.add(microTag);
191
        }
192
        return result;
193
    }
194

    
195
    private String getFamilyNames(TeamOrPersonBase<?> author) {
196
        if (author.isInstanceOf(Person.class)){
197
            Person person = CdmBase.deproxy(author, Person.class);
198
            return isNotBlank(person.getFamilyName())? person.getFamilyName() : null;
199
        }else{
200
            Team team = CdmBase.deproxy(author, Team.class);
201
            String result = null;
202
            int n = team.getTeamMembers().size();
203
            int index = 1;
204
            if (team.isHasMoreMembers()){
205
                n++;
206
            }
207
            for (Person member : team.getTeamMembers()){
208
                String name = isNotBlank(member.getFamilyName())? member.getFamilyName(): member.getTitleCache();
209
                String separator = index < n ? TeamDefaultCacheStrategy.STD_TEAM_CONCATINATION : TeamDefaultCacheStrategy.FINAL_TEAM_CONCATINATION;
210
                result = CdmUtils.concat(separator, result, name);
211
                index++;
212
            }
213
            if (team.isHasMoreMembers()){
214
                //TODO or et al.???
215
                result += TeamDefaultCacheStrategy.ET_AL_TEAM_CONCATINATION_FULL + "al.";
216
            }
217
            return result;
218
        }
219
    }
220

    
221
    private List<TaggedText> getNameCacheTags(TaxonName name) {
222
        List<TaggedText> result = name.getCacheStrategy().getTaggedName(name);
223
        return result;
224
    }
225

    
226
    private List<TaggedText> getNameTitleCacheTags(TaxonName name) {
227

    
228
        //TODO full title?
229
        List<TaggedText> result = name.getCacheStrategy().getTaggedFullTitle(name);
230
        return result;
231
    }
232

    
233
    /**
234
     * @param type the taxon relationship type
235
     * @param reverse is the relationship used reverse
236
     * @param languages list of preferred languages
237
     * @return the symbol for the taxon relationship
238
     */
239
    private String getSymbol(TaxonRelationshipType type, boolean reverse, List<Language> languages) {
240
        if (type == null){
241
            return UNDEFINED_SYMBOL;
242
        }
243

    
244
        //symbol
245
        String symbol = reverse? type.getInverseSymbol():type.getSymbol();
246
        if (isNotBlank(symbol)){
247
            return symbol;
248
        }
249

    
250
        boolean isSymmetric = type.isSymmetric();
251
        //symmetric inverted symbol
252
        String invertedSymbol = reverse? type.getSymbol() : type.getInverseSymbol();
253
        if (isSymmetric && isNotBlank(invertedSymbol)){
254
            return invertedSymbol;
255
        }
256

    
257
        //abbrev label
258
        Representation representation = reverse? type.getPreferredRepresentation(languages): type.getPreferredInverseRepresentation(languages);
259
        String abbrevLabel = representation.getAbbreviatedLabel();
260
        if (isNotBlank(abbrevLabel)){
261
            return abbrevLabel;
262
        }
263

    
264
        //symmetric inverted abbrev label
265
        Representation invertedRepresentation = reverse? type.getPreferredInverseRepresentation(languages):type.getPreferredRepresentation(languages);
266
        String invertedAbbrevLabel = invertedRepresentation.getAbbreviatedLabel();
267
        if (isSymmetric && isNotBlank(invertedAbbrevLabel)){
268
            return invertedAbbrevLabel;
269
        }
270

    
271
        //non symmetric inverted symbol
272
        if (!isSymmetric && isNotBlank(invertedSymbol)){
273
            return INVERT_SYMBOL + invertedSymbol;
274
        }
275

    
276
        //non symmetric inverted abbrev label
277
        if (!isSymmetric && isNotBlank(invertedAbbrevLabel)){
278
            return INVERT_SYMBOL + invertedAbbrevLabel;
279
        }
280

    
281
        return UNDEFINED_SYMBOL;
282
    }
283

    
284
    private boolean isNotBlank(String str) {
285
        return StringUtils.isNotBlank(str);
286
    }
287

    
288
    private boolean isBlank(String str) {
289
        return StringUtils.isBlank(str);
290
    }
291
}
    (1-1/1)