Project

General

Profile

Download (11.5 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.lang.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
 * @author a.mueller
37
 * @since 13.08.2018
38
 *
39
 */
40
public class TaxonRelationshipFormatter {
41

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

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

    
64

    
65

    
66
    public List<TaggedText> getTaggedText(TaxonRelationship taxonRelationship, boolean reverse, List<Language> languages, boolean withoutName) {
67

    
68
        if (taxonRelationship == null){
69
            return null;
70
        }
71

    
72
        TaxonRelationshipType type = taxonRelationship.getType();
73
        boolean isMisapplied = type == null ? false : type.isMisappliedNameOrInvalidDesignation() && reverse;
74
        boolean isSynonym = type == null? false : type.isAnySynonym();
75

    
76

    
77
        Taxon relatedTaxon = reverse? taxonRelationship.getFromTaxon()
78
                : taxonRelationship.getToTaxon();
79

    
80
        if (relatedTaxon == null){
81
            return null;
82
        }
83

    
84
        String doubtfulTaxonStr = relatedTaxon.isDoubtful() ? DOUBTFUL_TAXON_MARKER : "";
85
        String doubtfulRelationStr = taxonRelationship.isDoubtful() ? "?" : "";
86

    
87

    
88
        TaxonName name = relatedTaxon.getName();
89

    
90
        TaggedTextBuilder builder = new TaggedTextBuilder();
91

    
92
        //rel symbol
93
        String symbol = doubtfulRelationStr + getSymbol(type, reverse, languages);
94
        builder.add(TagEnum.symbol, symbol);
95

    
96
        //name
97
        if (!withoutName){
98
            if (isMisapplied){
99
                //starting quote
100
                String startQuote = " " + doubtfulTaxonStr + QUOTE_START;
101
                builder.addSeparator(startQuote);
102

    
103
                //name cache
104
                List<TaggedText> nameCacheTags = getNameCacheTags(name);
105
                builder.addAll(nameCacheTags);
106

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

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

    
142
//        //, non author
143
        if (isMisapplied && name != null){
144
            if (isNotBlank(name.getAuthorshipCache())){
145
                builder.addSeparator(NON_SEPARATOR);
146
                builder.add(TagEnum.authors, name.getAuthorshipCache().trim());
147
            }
148
        }
149

    
150
        List<TaggedText> relSecTags = getReferenceTags(taxonRelationship.getCitation(),
151
                taxonRelationship.getCitationMicroReference(),true);
152
        if (!relSecTags.isEmpty()){
153
            builder.addSeparator(isSynonym ? SYN_SEC : isMisapplied ? ERR_SEC : REL_SEC);
154
            builder.addAll(relSecTags);
155
        }
156

    
157
        return builder.getTaggedText();
158
    }
159

    
160
    private List<TaggedText> getReferenceTags(Reference ref, String detail, /*boolean isSensu,*/ boolean isRelation) {
161
        List<TaggedText> result = new ArrayList<>();
162
        String secRef;
163

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

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

    
230

    
231
    /**
232
     * @param name
233
     * @return
234
     */
235
    private List<TaggedText> getNameCacheTags(TaxonName name) {
236
        List<TaggedText> result = name.getCacheStrategy().getTaggedName(name);
237
        return result;
238
    }
239

    
240
    private List<TaggedText> getNameTitleCacheTags(TaxonName name) {
241

    
242
        //TODO full title?
243
        List<TaggedText> result = name.getCacheStrategy().getTaggedFullTitle(name);
244
        return result;
245
    }
246

    
247

    
248
    /**
249
     * @param type the taxon relationship type
250
     * @param reverse is the relationship used reverse
251
     * @param languages list of preferred languages
252
     * @return the symbol for the taxon relationship
253
     */
254
    private String getSymbol(TaxonRelationshipType type, boolean reverse, List<Language> languages) {
255
        if (type == null){
256
            return UNDEFINED_SYMBOL;
257
        }
258

    
259
        //symbol
260
        String symbol = reverse? type.getInverseSymbol():type.getSymbol();
261
        if (isNotBlank(symbol)){
262
            return symbol;
263
        }
264

    
265
        boolean isSymmetric = type.isSymmetric();
266
        //symmetric inverted symbol
267
        String invertedSymbol = reverse? type.getSymbol() : type.getInverseSymbol();
268
        if (isSymmetric && isNotBlank(invertedSymbol)){
269
            return invertedSymbol;
270
        }
271

    
272
        //abbrev label
273
        Representation representation = reverse? type.getPreferredRepresentation(languages): type.getPreferredInverseRepresentation(languages);
274
        String abbrevLabel = representation.getAbbreviatedLabel();
275
        if (isNotBlank(abbrevLabel)){
276
            return abbrevLabel;
277
        }
278

    
279
        //symmetric inverted abbrev label
280
        Representation invertedRepresentation = reverse? type.getPreferredInverseRepresentation(languages):type.getPreferredRepresentation(languages);
281
        String invertedAbbrevLabel = invertedRepresentation.getAbbreviatedLabel();
282
        if (isSymmetric && isNotBlank(invertedAbbrevLabel)){
283
            return invertedAbbrevLabel;
284
        }
285

    
286
        //non symmetric inverted symbol
287
        if (!isSymmetric && isNotBlank(invertedSymbol)){
288
            return INVERT_SYMBOL + invertedSymbol;
289
        }
290

    
291
        //non symmetric inverted abbrev label
292
        if (!isSymmetric && isNotBlank(invertedAbbrevLabel)){
293
            return INVERT_SYMBOL + invertedAbbrevLabel;
294
        }
295

    
296
        return UNDEFINED_SYMBOL;
297
    }
298

    
299
    private boolean isNotBlank(String str) {
300
        return StringUtils.isNotBlank(str);
301
    }
302

    
303
    private boolean isBlank(String str) {
304
        return StringUtils.isBlank(str);
305
    }
306
}
    (1-1/1)