001/*
002 * Copyright 2014 Global Biodiversity Information Facility (GBIF)
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.gbif.api.model.checklistbank;
017
018import org.gbif.api.model.common.LinneanClassification;
019import org.gbif.api.model.common.LinneanClassificationKeys;
020import org.gbif.api.util.ClassificationUtils;
021import org.gbif.api.vocabulary.Rank;
022import org.gbif.api.vocabulary.TaxonomicStatus;
023
024import java.io.Serializable;
025import java.util.List;
026import javax.annotation.Nullable;
027import javax.validation.constraints.Max;
028import javax.validation.constraints.Min;
029
030import com.google.common.base.Objects;
031import org.codehaus.jackson.annotate.JsonProperty;
032
033/**
034 * The resulting lookup of a name usage match.
035 * A single name usage key with its linnean classification and a confidence value for the match.
036 */
037public class NameUsageMatch implements LinneanClassification, LinneanClassificationKeys, Serializable {
038
039  private static final long serialVersionUID = -8927655067465421358L;
040
041  private Integer usageKey;
042  private String scientificName;
043  private String canonicalName;
044  private Rank rank;
045  private TaxonomicStatus status; // ACCEPTED, SYNONYM or DOUBTFUL only!
046  private Integer confidence;
047  private String note;
048  private MatchType matchType = MatchType.NONE;
049  private List<NameUsageMatch> alternatives;
050  // for LinneanClassification
051  private String kingdom;
052  private String phylum;
053  @JsonProperty("class")
054  private String clazz;
055  private String order;
056  private String family;
057  private String genus;
058  private String subgenus;
059  private String species;
060  // for LinneanClassificationKeys
061  private Integer kingdomKey;
062  private Integer phylumKey;
063  private Integer classKey;
064  private Integer orderKey;
065  private Integer familyKey;
066  private Integer genusKey;
067  private Integer subgenusKey;
068  private Integer speciesKey;
069
070  /**
071   * The confidence that the lookup was correct.
072   * A value between 0 and 100 with higher values being better matches.
073   *
074   * @return the lookup confidence
075   */
076  @Min(0)
077  @Max(100)
078  public Integer getConfidence() {
079    return confidence;
080  }
081
082  /**
083   * @param confidence the confidence to set
084   */
085  public void setConfidence(Integer confidence) {
086    this.confidence = confidence;
087  }
088
089  /**
090   * @return the type of match for this result
091   */
092  public MatchType getMatchType() {
093    return matchType;
094  }
095
096  public void setMatchType(MatchType matchType) {
097    this.matchType = matchType;
098  }
099
100  /**
101   * @return the rank of the matching usage
102   */
103  @Nullable
104  public Rank getRank() {
105    return rank;
106  }
107
108  public void setRank(Rank rank) {
109    this.rank = rank;
110  }
111
112  /**
113   * The scientific name of the looked up name usage.
114   *
115   * @return the scientific name of the matched usage
116   */
117  @Nullable
118  public String getScientificName() {
119    return scientificName;
120  }
121
122  public void setScientificName(String scientificName) {
123    this.scientificName = scientificName;
124  }
125
126  /**
127   * The key of the name usage that has been looked up.
128   *
129   * @return the usageKey
130   */
131  @Nullable
132  public Integer getUsageKey() {
133    return usageKey;
134  }
135
136  /**
137   * @param usageKey the usageKey to set
138   */
139  public void setUsageKey(Integer usageKey) {
140    this.usageKey = usageKey;
141  }
142
143  /**
144   * @return true if its a synonym
145   */
146  public boolean isSynonym() {
147    return status != null && status.isSynonym();
148  }
149
150  /**
151   * The taxonomic status of the backbone usage. This field is required and only 3 values are allowed:
152   * <ul>
153   *   <li>accepted: regular accepted taxon</li>
154   *   <li>synonym: any kind of synonym</li>
155   *   <li>doubtful: treated as accepted but in doubt for some reason</li>
156   * </ul>
157   */
158  public TaxonomicStatus getStatus() {
159    return status;
160  }
161
162  public void setStatus(TaxonomicStatus status) {
163    this.status = status;
164  }
165
166  @Override
167  @Nullable
168  public String getKingdom() {
169    return kingdom;
170  }
171
172  @Override
173  public void setKingdom(String kingdom) {
174    this.kingdom = kingdom;
175  }
176
177  @Override
178  @Nullable
179  public String getPhylum() {
180    return phylum;
181  }
182
183  @Override
184  public void setPhylum(String phylum) {
185    this.phylum = phylum;
186  }
187
188  @Override
189  @Nullable
190  public String getClazz() {
191    return clazz;
192  }
193
194  @Override
195  public void setClazz(String clazz) {
196    this.clazz = clazz;
197  }
198
199  @Override
200  @Nullable
201  public String getOrder() {
202    return order;
203  }
204
205  @Override
206  public void setOrder(String order) {
207    this.order = order;
208  }
209
210  @Override
211  @Nullable
212  public String getFamily() {
213    return family;
214  }
215
216  @Override
217  public void setFamily(String family) {
218    this.family = family;
219  }
220
221  @Override
222  @Nullable
223  public String getGenus() {
224    return genus;
225  }
226
227  @Override
228  public void setGenus(String genus) {
229    this.genus = genus;
230  }
231
232  @Override
233  @Nullable
234  public String getSubgenus() {
235    return subgenus;
236  }
237
238  @Override
239  public void setSubgenus(String subgenus) {
240    this.subgenus = subgenus;
241  }
242
243  @Override
244  @Nullable
245  public String getSpecies() {
246    return species;
247  }
248
249  @Override
250  public void setSpecies(String species) {
251    this.species = species;
252  }
253
254  @Override
255  @Nullable
256  public Integer getKingdomKey() {
257    return kingdomKey;
258  }
259
260  @Override
261  public void setKingdomKey(Integer kingdomKey) {
262    this.kingdomKey = kingdomKey;
263  }
264
265  @Override
266  @Nullable
267  public Integer getPhylumKey() {
268    return phylumKey;
269  }
270
271  @Override
272  public void setPhylumKey(Integer phylumKey) {
273    this.phylumKey = phylumKey;
274  }
275
276  @Override
277  @Nullable
278  public Integer getClassKey() {
279    return classKey;
280  }
281
282  @Override
283  public void setClassKey(Integer classKey) {
284    this.classKey = classKey;
285  }
286
287  @Override
288  @Nullable
289  public Integer getOrderKey() {
290    return orderKey;
291  }
292
293  @Override
294  public void setOrderKey(Integer orderKey) {
295    this.orderKey = orderKey;
296  }
297
298  @Override
299  @Nullable
300  public Integer getFamilyKey() {
301    return familyKey;
302  }
303
304  @Override
305  public void setFamilyKey(Integer familyKey) {
306    this.familyKey = familyKey;
307  }
308
309  @Override
310  @Nullable
311  public Integer getGenusKey() {
312    return genusKey;
313  }
314
315  @Override
316  public void setGenusKey(Integer genusKey) {
317    this.genusKey = genusKey;
318  }
319
320  @Override
321  @Nullable
322  public Integer getSubgenusKey() {
323    return subgenusKey;
324  }
325
326  @Override
327  public void setSubgenusKey(Integer subgenusKey) {
328    this.subgenusKey = subgenusKey;
329  }
330
331  @Override
332  @Nullable
333  public Integer getSpeciesKey() {
334    return speciesKey;
335  }
336
337  @Override
338  public void setSpeciesKey(Integer speciesKey) {
339    this.speciesKey = speciesKey;
340  }
341
342  @Override
343  @Nullable
344  public String getHigherRank(Rank rank) {
345    return ClassificationUtils.getHigherRank(this, rank);
346  }
347
348  @Override
349  public Integer getHigherRankKey(Rank rank) {
350    return ClassificationUtils.getHigherRankKey(this, rank);
351  }
352
353  @Nullable
354  public String getCanonicalName() {
355    return canonicalName;
356  }
357
358  public void setCanonicalName(String canonicalName) {
359    this.canonicalName = canonicalName;
360  }
361
362  /**
363   * Optional notes on the matching.
364   */
365  @Nullable
366  public String getNote() {
367    return note;
368  }
369
370  public void setNote(String note) {
371    this.note = note;
372  }
373
374  /**
375   * @return a list of alternative matches considered
376   */
377  @Nullable
378  public List<NameUsageMatch> getAlternatives() {
379    return alternatives;
380  }
381
382  public void setAlternatives(List<NameUsageMatch> alternatives) {
383    this.alternatives = alternatives;
384  }
385
386  @Override
387  public int hashCode() {
388    return Objects
389      .hashCode(
390        usageKey,
391        scientificName,
392        canonicalName,
393        rank,
394        status,
395        confidence,
396        note,
397        matchType,
398        alternatives,
399        kingdom,
400        phylum,
401        clazz,
402        order,
403        family,
404        genus,
405        subgenus,
406        species,
407        kingdomKey,
408        phylumKey,
409        classKey,
410        orderKey,
411        familyKey,
412        genusKey,
413        subgenusKey,
414        speciesKey
415      );
416  }
417
418  @Override
419  public boolean equals(Object obj) {
420    if (this == obj) {
421      return true;
422    }
423    if (obj == null) {
424      return false;
425    }
426    if (getClass() != obj.getClass()) {
427      return false;
428    }
429    final NameUsageMatch other = (NameUsageMatch) obj;
430    return Objects.equal(this.usageKey, other.usageKey)
431           && Objects.equal(this.scientificName, other.scientificName)
432           && Objects.equal(this.canonicalName, other.canonicalName)
433           && Objects.equal(this.rank, other.rank)
434           && Objects.equal(this.status, other.status)
435           && Objects.equal(this.confidence, other.confidence)
436           && Objects.equal(this.note, other.note)
437           && Objects.equal(this.matchType, other.matchType)
438           && Objects.equal(this.alternatives, other.alternatives)
439           && Objects.equal(this.kingdom, other.kingdom)
440           && Objects.equal(this.phylum, other.phylum)
441           && Objects.equal(this.clazz, other.clazz)
442           && Objects.equal(this.order, other.order)
443           && Objects.equal(this.family, other.family)
444           && Objects.equal(this.genus, other.genus)
445           && Objects.equal(this.subgenus, other.subgenus)
446           && Objects.equal(this.species, other.species)
447           && Objects.equal(this.kingdomKey, other.kingdomKey)
448           && Objects.equal(this.phylumKey, other.phylumKey)
449           && Objects.equal(this.classKey, other.classKey)
450           && Objects.equal(this.orderKey, other.orderKey)
451           && Objects.equal(this.familyKey, other.familyKey)
452           && Objects.equal(this.genusKey, other.genusKey)
453           && Objects.equal(this.subgenusKey, other.subgenusKey)
454           && Objects.equal(this.speciesKey, other.speciesKey);
455  }
456
457  @Override
458  public String toString() {
459    return Objects.toStringHelper(this)
460    .add("usageKey", usageKey)
461    .add("scientificName", scientificName)
462    .add("canonicalName", canonicalName)
463    .add("rank", rank)
464    .add("status", status)
465    .add("confidence", confidence)
466    .add("note", note)
467    .add("matchType", matchType)
468    .add("alternatives", alternatives)
469    .add("kingdom", kingdom)
470    .add("phylum", phylum)
471    .add("clazz", clazz)
472    .add("order", order)
473    .add("family", family)
474    .add("genus", genus)
475    .add("subgenus", subgenus)
476    .add("species", species)
477    .add("kingdomKey", kingdomKey)
478    .add("phylumKey", phylumKey)
479    .add("classKey", classKey)
480    .add("orderKey", orderKey)
481    .add("familyKey", familyKey)
482    .add("genusKey", genusKey)
483    .add("subgenusKey", subgenusKey)
484    .add("speciesKey", speciesKey)
485    .toString();
486  }
487
488  public enum MatchType {
489
490    /**
491     * An exact, straight match.
492     */
493    EXACT,
494    /**
495     * A fuzzy, non exact match.
496     */
497    FUZZY,
498    /**
499     * Matching on a higher rank than the lowest name given.
500     */
501    HIGHERRANK,
502    /**
503     * No match or matching several names with too little information to keep apart.
504     */
505    NONE
506
507  }
508
509}