Project

General

Profile

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

    
12
import java.util.ArrayList;
13
import java.util.List;
14
import java.util.Set;
15
import java.util.UUID;
16

    
17
import org.apache.log4j.Logger;
18

    
19
import eu.etaxonomy.cdm.common.CdmUtils;
20
import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
21
import eu.etaxonomy.cdm.model.name.TaxonName;
22
import eu.etaxonomy.cdm.model.taxon.Synonym;
23
import eu.etaxonomy.cdm.model.taxon.SynonymType;
24
import eu.etaxonomy.cdm.model.taxon.Taxon;
25
import eu.etaxonomy.cdm.strategy.StrategyBase;
26

    
27
/**
28
 * This class tries to guess all basionym relationships for the synonyms of a given taxon
29
 * by evaluating the name parts including authors.
30
 * It adds all {@link TaxonName taxon names} that seem to belong to the same
31
 * basionym to the homotypic group of this basionym and creates the basionym relationship
32
 * if not yet added/created.<BR>
33
 * Also it changes the {@link SynonymType synonym type} of the synonyms
34
 * that are homotypic to the accepted taxon to
35
 * {@link SynonymType#HOMOTYPIC_SYNONYM_OF() homotypic synonym of}.
36
 *
37
 * NOTE: It is still unclear where to put this kind of operations.
38
 * The base class, package and even the module may change in future.
39
 *
40
 * @author a.mueller
41
 * @date 22.04.2017
42
 *
43
 */
44
public class BasionymRelationCreator extends StrategyBase {
45

    
46
    private static final long serialVersionUID = -4711438819176248413L;
47
    @SuppressWarnings("unused")
48
    private static final Logger logger = Logger.getLogger(BasionymRelationCreator.class);
49

    
50
    private UUID uuid = UUID.fromString("e9e1d1f5-e398-4ba7-81a6-92875573d7cb");
51

    
52
    /**
53
     * {@inheritDoc}
54
     */
55
    @Override
56
    protected UUID getUuid() {
57
        return uuid;
58
    }
59

    
60
    public void invoke (Taxon taxon){
61
        Set<Synonym> synonyms = taxon.getSynonyms();
62

    
63
        //compare accepted against synonyms
64
        for (Synonym synonym: synonyms){
65
            TaxonName<?, ?> basionym = compareHomotypic(taxon.getName(), synonym.getName());
66
            if (basionym != null){
67
                synonym.setType(SynonymType.HOMOTYPIC_SYNONYM_OF());
68
                adaptHomotypicGroup(basionym, taxon.getName(), synonym.getName());
69
            }
70
        }
71
        List<Synonym> synonymList = new ArrayList<>(synonyms);
72

    
73
        //compareEachSynonymAgainstEachOther;
74
        for (int i = 0; i < synonymList.size()-1; i++){
75
            for (int j = i + 1; j < synonymList.size(); j++){
76
                Synonym syn1 = synonymList.get(i);
77
                Synonym syn2 = synonymList.get(j);
78
                TaxonName<?, ?> basionym = compareHomotypic(syn1.getName(), syn2.getName());
79
                if (basionym != null){
80
                    adaptHomotypicGroup(basionym, syn1.getName(), syn2.getName());
81
                    if (taxon.getName().getBasionyms().contains(basionym)){
82
                        syn1.setType(SynonymType.HOMOTYPIC_SYNONYM_OF());
83
                        syn2.setType(SynonymType.HOMOTYPIC_SYNONYM_OF());
84
                    }
85
                }
86
            }
87
        }
88
    }
89

    
90
    /**
91
     * @param basionym
92
     * @param name
93
     * @param name2
94
     */
95
    private void adaptHomotypicGroup(TaxonName<?, ?> basionym,
96
            TaxonName<?,?> name1, TaxonName<?,?> name2) {
97
        if (basionym.equals(name1)){
98
            if (!name2.getBasionyms().contains(name1)){
99
                name2.addBasionym(name1);
100
            }
101
        }else if (basionym.equals(name2)){
102
            if (!name1.getBasionyms().contains(name2)){
103
                name1.addBasionym(name2);
104
            }
105
        }
106
    }
107

    
108
    /**
109
     * @param name
110
     * @param name2
111
     */
112
    private TaxonName<?,?> compareHomotypic(TaxonName<?,?> name1, TaxonName<?,?> name2) {
113
        if (name1 == null || name2 == null){
114
            return null;
115
        }
116
        TaxonName<?,?> basionymCandidate = checkAuthors(name1, name2);
117
        if (basionymCandidate == null){
118
            return null;
119
        }else{
120
            TaxonName<?,?> newCombinationCandidate
121
                = basionymCandidate == name1? name2: name1;
122
            boolean isBasionym = compareNameParts(basionymCandidate, newCombinationCandidate);
123
            if (isBasionym){
124
                return basionymCandidate;
125
            }else{
126
                return null;
127
            }
128
        }
129
    }
130

    
131
    /**
132
     * @param basionymCandiate
133
     * @param newCombinationCandidate
134
     */
135
    private boolean compareNameParts(TaxonName<?, ?> basionymCandidate,
136
            TaxonName<?, ?> newCombinationCandidate) {
137
        if (basionymCandidate.isGenusOrSupraGeneric() || newCombinationCandidate.isGenusOrSupraGeneric()){
138
            return false;
139
        }else if (matchLastNamePart(basionymCandidate, newCombinationCandidate)){
140
            return true;
141
        }
142
        return false;
143
    }
144

    
145
    /**
146
     * @param name1
147
     * @param name2
148
     * @return
149
     */
150
    private TaxonName<?,?> checkAuthors(TaxonName<?, ?> name1, TaxonName<?, ?> name2) {
151
        if (hasBasionymAuthorOf(name1, name2)){
152
            return name1;
153
        }else if (hasBasionymAuthorOf(name2, name1)){
154
            return name2;
155
        }else{
156
            return null;
157
        }
158
    }
159

    
160
    /**
161
     * @param name1
162
     * @param name2
163
     * @return
164
     */
165
    private boolean hasBasionymAuthorOf(TaxonName<?,?> name1, TaxonName<?,?> name2) {
166
        TeamOrPersonBase<?> basAuthor2 = name2.getBasionymAuthorship();
167
        TeamOrPersonBase<?> combinationAuthor = name1.getCombinationAuthorship();
168
        TeamOrPersonBase<?> basAuthor1 = name1.getBasionymAuthorship();
169
        if (basAuthor2 != null && basAuthor1 == null){
170
            if (matches(basAuthor2, combinationAuthor)){
171
                return true;
172
            }
173
        }
174
        return false;
175
    }
176

    
177
    /**
178
     * @param basAuthor
179
     * @param combinationAuthor
180
     * @return
181
     */
182
    private boolean matches(TeamOrPersonBase<?> basAuthor, TeamOrPersonBase<?> combinationAuthor) {
183
        //TODO better do with a CDM matcher that also compares other fields and
184
        //returns false if other fields are contradictory
185
        if (basAuthor == null || combinationAuthor == null){
186
            return false;
187
        }else if (basAuthor == combinationAuthor || basAuthor.equals(combinationAuthor)){
188
            return true;
189
        }else if (CdmUtils.nonEmptyEquals(basAuthor.getNomenclaturalTitle(), combinationAuthor.getNomenclaturalTitle())){
190
            return true;
191
        }else{
192
            return false;
193
        }
194
    }
195

    
196
    /**
197
     * @param basionymName
198
     * @param newCombination
199
     * @return
200
     */
201
    public static boolean matchLastNamePart(TaxonName<?,?> name1, TaxonName<?,?> name2) {
202
        String lastNamePart1 = name1.getLastNamePart();
203
        String lastNamePart2 = name2.getLastNamePart();
204
        if (lastNamePart1 != null && lastNamePart2 != null){
205
            lastNamePart1 = normalizeBasionymNamePart(lastNamePart1);
206
            lastNamePart2 = normalizeBasionymNamePart(lastNamePart2);
207
            return (lastNamePart1.equals(lastNamePart2));
208
        }else{
209
            return false;
210
        }
211
    }
212

    
213
    /**
214
     * @param lastNamePart1
215
     * @return
216
     */
217
    private static  String normalizeBasionymNamePart(String lastNamePart) {
218
        String namePart = lastNamePart.toLowerCase()
219
                .replaceAll("(um|us|a|is|e|os|on|or)$", "")
220
                .replaceAll("er$", "r")    //e.g. ruber <-> rubra
221
                .replaceAll("ese$", "s");  //e.g.  cayanensis <-> cayanenese
222
                //TODO tampensis / tampense
223
        return namePart;
224
    }
225

    
226
}
    (1-1/1)