Project

General

Profile

Download (9.14 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

    
10
package eu.etaxonomy.cdm.model.taxon;
11

    
12
import java.io.Serializable;
13
import java.util.Comparator;
14
import java.util.Set;
15

    
16
import org.apache.log4j.Logger;
17
import org.joda.time.DateTime;
18

    
19
import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
20
import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
21
import eu.etaxonomy.cdm.model.name.Rank;
22
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
23
import eu.etaxonomy.cdm.model.name.ZoologicalName;
24
import eu.etaxonomy.cdm.model.reference.Reference;
25

    
26
/**
27
 * This class makes available a method to compare two {@link TaxonBase taxa} by
28
 * comparing the publication dates of the corresponding
29
 * {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon names}.
30
 *
31
 * @author a.mueller
32
 * @created 11.06.2008
33
 */
34
public class TaxonComparator implements Comparator<TaxonBase>, Serializable {
35
	private static final long serialVersionUID = -1433623743189043446L;
36
	@SuppressWarnings("unused")
37
	private static final Logger logger = Logger.getLogger(TaxonComparator.class);
38

    
39
	private boolean includeRanks = false;
40

    
41
    /**
42
     * @param includeRanks
43
     */
44
    public TaxonComparator() {
45
        super();
46
    }
47

    
48
    /**
49
     * @param includeRanks
50
     */
51
    public TaxonComparator(boolean includeRanks) {
52
        super();
53
        this.includeRanks = includeRanks;
54
    }
55

    
56

    
57
    /**
58
     * Returns an integer generated by comparing first the nomenclatural status and then the
59
     * {@link eu.etaxonomy.cdm.model.name.INomenclaturalReference#getYear() publication years}
60
     * of both {@link eu.etaxonomy.cdm.model.name.TaxonNameBase taxon names}
61
     * used in the given {@link TaxonBase taxa}.
62
     * If 1 name has status of type nom. inval. or nom. nudum the name is put to the end of a
63
     * list (returns +1 for a status in taxon1 and -1 for a status in taxon2). If both do have
64
     * no status or the same status, the publication date is taken for comparison.
65
     * Nom. nudum is handled as more "severe" status then nom.inval.
66
     *
67
     * Returns a negative value if the publication year corresponding to the
68
     * first given taxon precedes the publication year corresponding to the
69
     * second given taxon. Returns a positive value if the contrary is true and
70
     * 0 if both publication years and the date, when they are created, are identical.
71
     * In case one of the publication
72
     * years is "null" and the other is not, the "empty" publication year will
73
     * be considered to be always preceded by the "not null" publication year.
74
     * If both publication years are "null" the creation date is used for the comparison
75
     *
76
     *
77
     * @see		java.lang.String#compareTo(String)
78
     * @see		java.util.Comparator#compare(java.lang.Object, java.lang.Object)
79
     */
80
    @Override
81
    public int compare(
82
            @SuppressWarnings("rawtypes") TaxonBase taxonBase1,
83
            @SuppressWarnings("rawtypes") TaxonBase taxonBase2) {
84
        int result;
85

    
86
        if (taxonBase1.equals(taxonBase2)){
87
        	return 0;
88
        }
89

    
90
        TaxonNameBase<?,?> name1 = taxonBase1.getName();
91
        TaxonNameBase<?,?> name2 = taxonBase2.getName();
92

    
93
        //set to end if a taxon has nomenclatural status "nom. inval." or "nom. nud."
94
        int statusCompareWeight = compareStatus(name1, name2);
95

    
96
        if (statusCompareWeight != 0){
97
        	return Integer.signum(statusCompareWeight);
98
        }
99

    
100
        //TODO discuss if we should also include nom. illeg. here on taxon level comparison
101
        result = compare(name1, name2, false);
102

    
103
        if (result == 0){
104
            DateTime date11 = taxonBase1.getCreated();
105
            DateTime date12 = taxonBase2.getCreated();
106
            if (date11 == null && date12 == null) {
107
                result = 0;
108
            }else if (date11 == null) {
109
                return 1;
110
            }else if (date12 == null) {
111
                return -1;
112
            }else{
113
            	result = date11.compareTo(date12);
114
            }
115
        }
116
        if (result == 0){
117
        	//the Comparator contract
118
        	return taxonBase1.getUuid().compareTo(taxonBase1.getUuid());
119
        }else{
120
        	return result;
121
        }
122
    }
123

    
124

    
125
    /**
126
     * @param taxonNameBase
127
     * @param taxonNameBase2
128
     * @param statusCompareWeight
129
     * @return
130
     */
131
    protected int compareStatus(TaxonNameBase<?,?> taxonNameBase, TaxonNameBase<?,?> taxonNameBase2) {
132
        int statusCompareWeight = 0;
133
        statusCompareWeight += computeStatusCompareWeight(taxonNameBase);
134
        statusCompareWeight -= computeStatusCompareWeight(taxonNameBase2);
135
        return statusCompareWeight;
136
    }
137

    
138

    
139
	/**
140
	 * @param taxonBase1
141
	 * @param statusCompareWeight
142
	 * @return
143
	 */
144
	private int computeStatusCompareWeight(TaxonNameBase<?,?> taxonNameBase) {
145
		int result = 0;
146
		if (taxonNameBase == null || taxonNameBase.getStatus() == null){
147
			return 0;
148
		}
149
		Set<NomenclaturalStatus> status1 = taxonNameBase.getStatus();
150
        for (NomenclaturalStatus nomStatus1 : status1){
151
            if (nomStatus1.getType() != null){
152
            	if (nomStatus1.getType().equals(NomenclaturalStatusType.INVALID())){
153
            		result += 1;
154
            	}else if(nomStatus1.getType().equals(NomenclaturalStatusType.NUDUM())){
155
            		result += 2;
156
                }
157
            }
158
        }
159
		return result;
160
	}
161

    
162
    protected int compareNomIlleg(TaxonNameBase<?,?> taxonNameBase1, TaxonNameBase<?,?> taxonNameBase2) {
163
        int isNomIlleg1 = isNomIlleg(taxonNameBase1);
164
        int isNomIlleg2 = isNomIlleg(taxonNameBase2);
165
        return isNomIlleg1 - isNomIlleg2;
166
    }
167

    
168
    private int isNomIlleg(TaxonNameBase<?,?> taxonNameBase) {
169
        if (taxonNameBase == null || taxonNameBase.getStatus() == null){
170
            return 0;
171
        }
172
        Set<NomenclaturalStatus> status = taxonNameBase.getStatus();
173
        for (NomenclaturalStatus nomStatus : status){
174
            if (nomStatus.getType() != null){
175
                if (nomStatus.getType().equals(NomenclaturalStatusType.ILLEGITIMATE())){
176
                    return 1;
177
                }
178
            }
179
        }
180
        return 0;
181
    }
182

    
183

    
184
    private Integer getIntegerDate(TaxonNameBase<?,?> name){
185
        Integer result;
186

    
187
       if (name == null){
188
            result = null;
189
        }else{
190
            if (name instanceof ZoologicalName){
191
                result = (((ZoologicalName)name).getPublicationYear());
192
            }else{
193
                Reference<?> ref = (Reference<?>) name.getNomenclaturalReference();
194
                if (ref == null){
195
                    result = null;
196
                }else{
197
                    if (ref.getDatePublished() == null){
198
                    	Reference<?> inRef = ref.getInReference();
199
                    	if (inRef == null){
200
                            result = null;
201
                        }else{
202
                            if (inRef.getDatePublished() == null){
203
                            	result = null;
204
                            }else{
205
                            	result = ref.getInReference().getDatePublished().getStartYear();
206
                            }
207
                        }
208
                    }else{
209
                        result = ref.getDatePublished().getStartYear();
210
                    }
211
                }
212
            }
213
        }
214

    
215
        return result;
216
    }
217

    
218

    
219
    /**
220
     *
221
     * @param name1
222
     * @param name2
223
     * @param includeNomIlleg if true and if both names have no date or same date, the only
224
     * name having nom. illeg. state is handled as if the name was published later than the name
225
     * without status nom. illeg.
226
     * @return
227
     */
228
    protected int compare(TaxonNameBase<?,?> name1, TaxonNameBase<?,?> name2, boolean includeNomIlleg) {
229
        int result;
230

    
231
        //dates
232
        Integer intDate1 = getIntegerDate(name1);
233
        Integer intDate2 = getIntegerDate(name2);
234

    
235
        if (intDate1 == null && intDate2 == null){
236
            result = 0;
237
        }else if (intDate1 == null){
238
            return 1;
239
        }else if (intDate2 == null){
240
            return -1;
241
        }else{
242
            result = intDate1.compareTo(intDate2);
243
        }
244

    
245
        //nom. illeg.
246
        if (result == 0 && includeNomIlleg){
247
            result = compareNomIlleg(name1, name2);
248
            if (result != 0){
249
                return result;
250
            }
251
        }
252

    
253
        if (result == 0 && includeRanks){
254
            Rank rank1 = name1 == null? null : name1.getRank();
255
            Rank rank2 = name2 == null? null : name2.getRank();
256

    
257
            if (rank1 == null && rank2 == null){
258
                result = 0;
259
            }else if (rank1 == null){
260
                return 1;
261
            }else if (rank2 == null){
262
                return -1;
263
            }else{
264
                //for some strange reason compareTo for ranks returns 1 if rank2 is lower. So we add minus (-)
265
                result = - rank1.compareTo(rank2);
266
            }
267
        }
268

    
269
        if (result == 0 && name1 != null && name2 != null){
270
            result = name1.compareTo(name2);
271
            if (result != 0){
272
                return result;
273
            }
274
        }
275
        return result;
276
    }
277

    
278

    
279
}
(12-12/21)