001/*
002 * Copyright 2020 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.Identifier;
019import org.gbif.api.vocabulary.IdentifierType;
020import org.gbif.api.vocabulary.ThreatStatus;
021
022import java.util.ArrayList;
023import java.util.LinkedHashSet;
024import java.util.List;
025import java.util.Objects;
026import java.util.Set;
027
028import javax.validation.constraints.NotNull;
029
030import org.apache.commons.lang3.StringUtils;
031
032import com.fasterxml.jackson.annotation.JsonIgnore;
033
034/**
035 * An extension to a NameUsage adding all further properties that are not eagerly loaded.
036 * Use this class to store the various subresources as you need them side by side with the NameUsage.
037 * Note that properties are not automatically/lazy loaded in any way.
038 * This is just a simple container class with a few convenience methods which needs to be populated manually via its
039 * setters or the constructor.
040 */
041@SuppressWarnings("unused")
042public class NameUsageContainer extends NameUsage {
043
044  private List<Description> descriptions = new ArrayList<>();
045  private List<Distribution> distributions = new ArrayList<>();
046  private List<Identifier> identifiers = new ArrayList<>();
047  private List<NameUsageMediaObject> media = new ArrayList<>();
048  private List<Reference> referenceList = new ArrayList<>();
049  private List<SpeciesProfile> speciesProfiles = new ArrayList<>();
050  private List<NameUsage> synonyms = new ArrayList<>();
051  private List<NameUsage> combinations = new ArrayList<>();
052  private List<TypeSpecimen> typeSpecimens = new ArrayList<>();
053  private List<VernacularName> vernacularNames = new ArrayList<>();
054
055  /**
056   * Default constructor.
057   */
058  public NameUsageContainer() {
059    //empty constructor
060  }
061
062  /**
063   * Constructs a NameUsageContainer from an existing NameUsage instance.
064   */
065  public NameUsageContainer(NameUsage usage) {
066    super(usage);
067  }
068
069  /**
070   * @return the list of Description
071   */
072  @NotNull
073  public List<Description> getDescriptions() {
074    return descriptions;
075  }
076
077  /**
078   * @param descriptions the list of Description
079   */
080  public void setDescriptions(List<Description> descriptions) {
081    this.descriptions = descriptions;
082  }
083
084  /**
085   * @return the list of Distribution
086   */
087  @NotNull
088  public List<Distribution> getDistributions() {
089    return distributions;
090  }
091
092  /**
093   * @param distributions the Distribution list to set
094   */
095  public void setDistributions(List<Distribution> distributions) {
096    this.distributions = distributions;
097  }
098
099  /**
100   * Convenience method that analyzes all species profile records and returns the distinct list of known habitats.
101   *
102   * @return list of unique habitats
103   */
104  @NotNull
105  public Set<String> getHabitats() {
106    Set<String> habitats = new LinkedHashSet<>();
107    for (SpeciesProfile sp : speciesProfiles) {
108      if (StringUtils.isNotEmpty(sp.getHabitat())) {
109        habitats.add(sp.getHabitat());
110      }
111    }
112    return habitats;
113  }
114
115  public List<NameUsageMediaObject> getMedia() {
116    return media;
117  }
118
119  public void setMedia(List<NameUsageMediaObject> media) {
120    this.media = media;
121  }
122
123  /**
124   * @return the list of all Identifier
125   */
126  @NotNull
127  public List<Identifier> getIdentifiers() {
128    return identifiers;
129  }
130
131  /**
132   * @param identifiers the Identifier list to set
133   */
134  public void setIdentifiers(List<Identifier> identifiers) {
135    this.identifiers = identifiers;
136  }
137
138  /**
139   * @return the list of all URL Identifier
140   */
141  @NotNull
142  @JsonIgnore
143  public List<Identifier> getIdentifierByType(final IdentifierType type) {
144    List<Identifier> ids = new ArrayList<>();
145    for (Identifier i : identifiers) {
146      if (type == i.getType()) {
147        ids.add(i);
148      }
149    }
150    return ids;
151  }
152
153  /**
154   * @return the list of Reference
155   */
156  @NotNull
157  public List<Reference> getReferenceList() {
158    return referenceList;
159  }
160
161  /**
162   * @param referenceList the Reference list to set
163   */
164  public void setReferenceList(List<Reference> referenceList) {
165    this.referenceList = referenceList;
166  }
167
168  /**
169   * @return the list of SpeciesProfile
170   */
171  @NotNull
172  public List<SpeciesProfile> getSpeciesProfiles() {
173    return speciesProfiles;
174  }
175
176  /**
177   * @param speciesProfiles the SpeciesProfile list to set
178   */
179  public void setSpeciesProfiles(List<SpeciesProfile> speciesProfiles) {
180    this.speciesProfiles = speciesProfiles;
181  }
182
183  /**
184   * @return the list of synonyms
185   */
186  public List<NameUsage> getSynonyms() {
187    return synonyms;
188  }
189
190  /**
191   * @param synonyms list of synonyms
192   */
193  public void setSynonyms(List<NameUsage> synonyms) {
194    this.synonyms = synonyms;
195  }
196
197  /**
198   * @return the list of combinations known for the basionym
199   */
200  @NotNull
201  public List<NameUsage> getCombinations() {
202    return combinations;
203  }
204
205  public void setCombinations(List<NameUsage> combinations) {
206    this.combinations = combinations;
207  }
208
209  /**
210   * @return the list of TypeSpecimen
211   */
212  @NotNull
213  public List<TypeSpecimen> getTypeSpecimens() {
214    return typeSpecimens;
215  }
216
217  /**
218   * @param typeSpecimens the TypeSpecimen list to set
219   */
220  public void setTypeSpecimens(List<TypeSpecimen> typeSpecimens) {
221    this.typeSpecimens = typeSpecimens;
222  }
223
224  /**
225   * @return the list of VernacularName
226   */
227  @NotNull
228  public List<VernacularName> getVernacularNames() {
229    return vernacularNames;
230  }
231
232  /**
233   * @param vernacularNames the VernacularName list to set
234   */
235  public void setVernacularNames(List<VernacularName> vernacularNames) {
236    this.vernacularNames = vernacularNames;
237  }
238
239  /**
240   * Convenience method that analyzes all species profile records and returns the distinct list of known living
241   * periods.
242   *
243   * @return list of unique living periods
244   */
245  @NotNull
246  public Set<String> getLivingPeriods() {
247    Set<String> periods = new LinkedHashSet<>();
248    for (SpeciesProfile sp : speciesProfiles) {
249      if (StringUtils.isNotEmpty(sp.getLivingPeriod())) {
250        periods.add(sp.getLivingPeriod());
251      }
252    }
253    return periods;
254  }
255
256  /**
257   * Convenience method that analyzes all distribution records and returns the distinct list of known threat status.
258   *
259   * @return list of unique threat status
260   */
261  @NotNull
262  public Set<ThreatStatus> getThreatStatus() {
263    Set<ThreatStatus> threats = new LinkedHashSet<>();
264    for (Distribution d : distributions) {
265      if (d.getThreatStatus() != null) {
266        threats.add(d.getThreatStatus());
267      }
268    }
269    return threats;
270  }
271
272  /**
273   * Convenience method that analyzes all species profile records for extinct.
274   * If several records contradict use the majority or if numbers are equal true.
275   *
276   * @return true if extinct
277   */
278  public Boolean isExtinct() {
279    int ctrue = 0;
280    int cfalse = 0;
281    for (SpeciesProfile sp : speciesProfiles) {
282      if (sp.isExtinct() == null) {
283        continue;
284      }
285
286      if (sp.isExtinct()) {
287        ctrue++;
288      } else if (!sp.isExtinct()) {
289        cfalse++;
290      }
291    }
292    return ctrue + cfalse == 0 ? null : ctrue >= cfalse;
293  }
294
295  /**
296   * Convenience method that analyzes all species profile records for freshwater habitat flags.
297   *
298   * @return true if freshwater
299   */
300  public Boolean isFreshwater() {
301    int ctrue = 0;
302    int cfalse = 0;
303    for (SpeciesProfile sp : speciesProfiles) {
304      if (sp.isFreshwater() == null) {
305        continue;
306      }
307
308      if (sp.isFreshwater()) {
309        ctrue++;
310      } else if (!sp.isFreshwater()) {
311        cfalse++;
312      }
313    }
314    return ctrue + cfalse == 0 ? null : ctrue >= cfalse;
315  }
316
317  /**
318   * Convenience method that analyzes all species profile records for marine habitat flags.
319   *
320   * @return true if marine
321   */
322  public Boolean isMarine() {
323    int ctrue = 0;
324    int cfalse = 0;
325    for (SpeciesProfile sp : speciesProfiles) {
326      if (sp.isMarine() == null) {
327        continue;
328      }
329
330      if (sp.isMarine()) {
331        ctrue++;
332      } else if (!sp.isMarine()) {
333        cfalse++;
334      }
335    }
336    return ctrue + cfalse == 0 ? null : ctrue >= cfalse;
337  }
338
339  /**
340   * Convenience method that analyzes all species profile records for terrestrial habitat flags.
341   *
342   * @return true if terrestrial
343   */
344  public Boolean isTerrestrial() {
345    int ctrue = 0;
346    int cfalse = 0;
347    for (SpeciesProfile sp : speciesProfiles) {
348      if (sp.isTerrestrial() == null) {
349        continue;
350      }
351
352      if (sp.isTerrestrial()) {
353        ctrue++;
354      } else if (!sp.isTerrestrial()) {
355        cfalse++;
356      }
357    }
358    return ctrue + cfalse == 0 ? null : ctrue >= cfalse;
359  }
360
361  @Override
362  public boolean equals(Object o) {
363    if (this == o) {
364      return true;
365    }
366    if (o == null || getClass() != o.getClass()) {
367      return false;
368    }
369    if (!super.equals(o)) {
370      return false;
371    }
372    NameUsageContainer that = (NameUsageContainer) o;
373    return Objects.equals(descriptions, that.descriptions) &&
374      Objects.equals(distributions, that.distributions) &&
375      Objects.equals(media, that.media) &&
376      Objects.equals(referenceList, that.referenceList) &&
377      Objects.equals(speciesProfiles, that.speciesProfiles) &&
378      Objects.equals(synonyms, that.synonyms) &&
379      Objects.equals(typeSpecimens, that.typeSpecimens) &&
380      Objects.equals(vernacularNames, that.vernacularNames);
381  }
382
383  @Override
384  public int hashCode() {
385    return Objects
386      .hash(super.hashCode(), descriptions, distributions, media, referenceList, speciesProfiles,
387        synonyms, typeSpecimens, vernacularNames);
388  }
389
390  @Override
391  public String toString() {
392    return "NameUsageContainer{" +
393      "descriptions=" + descriptions +
394      ", distributions=" + distributions +
395      ", identifiers=" + identifiers +
396      ", media=" + media +
397      ", referenceList=" + referenceList +
398      ", speciesProfiles=" + speciesProfiles +
399      ", synonyms=" + synonyms +
400      ", combinations=" + combinations +
401      ", typeSpecimens=" + typeSpecimens +
402      ", vernacularNames=" + vernacularNames +
403      "} " + super.toString();
404  }
405}