ref #6682 revert relType DTO
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / dto / TaxonRelationshipsDTO.java
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.api.service.dto;
10
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.Set;
14 import java.util.UUID;
15
16 import org.joda.time.DateTime;
17
18 import eu.etaxonomy.cdm.common.CdmUtils;
19 import eu.etaxonomy.cdm.format.taxon.TaxonRelationshipFormatter;
20 import eu.etaxonomy.cdm.model.common.Language;
21 import eu.etaxonomy.cdm.model.common.RelationshipBase.Direction;
22 import eu.etaxonomy.cdm.model.common.Representation;
23 import eu.etaxonomy.cdm.model.taxon.Taxon;
24 import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
25 import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
26 import eu.etaxonomy.cdm.persistence.dto.TermDto;
27 import eu.etaxonomy.cdm.strategy.cache.TagEnum;
28 import eu.etaxonomy.cdm.strategy.cache.TaggedCacheHelper;
29 import eu.etaxonomy.cdm.strategy.cache.TaggedText;
30
31 /**
32 * DTO to transfer a list of taxon relationships for a given taxon.
33 *
34 * @author a.mueller
35 * @since 15.08.2018
36 */
37 public class TaxonRelationshipsDTO {
38
39 private static final String SENSU_SEPARATOR = ", ";
40
41 public class TaxonRelation{
42
43 private UUID relationUuid;
44 private boolean doubtful = false;
45 private boolean misapplication = false;
46 private boolean synonym = false;
47 private Direction direction;
48 private UUID taxonUuid;
49 private String cache;
50 private List<TaggedText> taggedText;
51 //TODO maybe this will be changed in future
52 private TermDto type;
53 private UUID typeUuid;
54
55
56 public TaxonRelation(TaxonRelationship relation, Direction direction, List<Language> languages) {
57 Taxon relatedTaxon = direction == Direction.relatedTo? relation.getToTaxon()
58 : relation.getFromTaxon();
59 this.taxonUuid = relatedTaxon.getUuid();
60 this.doubtful = relation.isDoubtful();
61 this.relationUuid = relation.getUuid();
62 this.direction = direction;
63 TaxonRelationshipType relType = relation.getType();
64
65 if (relType != null){
66 this.misapplication = relType.isMisappliedNameOrInvalidDesignation();
67 this.synonym = relType.isAnySynonym();
68 this.typeUuid = relType.getUuid();
69 // TODO there must be a better DTO which also includes
70 Set<Representation> representations = direction.isDirect() ? relType.getRepresentations() : relType.getInverseRepresentations();
71 UUID vocUuid = relType.getVocabulary() != null ? relType.getVocabulary().getUuid(): null;
72 TermDto termDto = new TermDto(relType.getUuid(), representations, null, vocUuid, relType.getOrderIndex());
73 this.type = termDto;
74 // TODO localize
75 // termDto.localize(representation_L10n);
76 }
77 List<TaggedText> tags = new TaxonRelationshipFormatter().getTaggedText(
78 relation, direction == Direction.relatedFrom, languages);
79 this.taggedText = tags;
80 this.setCache(TaggedCacheHelper.createString(tags));
81 }
82
83
84 public UUID getTaxonUuid() {
85 return taxonUuid;
86 }
87 public void setTaxonUuid(UUID taxonUuid) {
88 this.taxonUuid = taxonUuid;
89 }
90 public boolean isDoubtful() {
91 return doubtful;
92 }
93 public void setDoubtful(boolean doubtful) {
94 this.doubtful = doubtful;
95 }
96 public UUID getRelationUuid() {
97 return relationUuid;
98 }
99 public void setRelationUuid(UUID relationUuid) {
100 this.relationUuid = relationUuid;
101 }
102
103 public Direction getDirection() {
104 return direction;
105 }
106 public void setDirection(Direction direction) {
107 this.direction = direction;
108 }
109
110
111
112 @Override
113 public String toString(){
114 return taxonUuid == null? super.toString() : taxonUuid.toString();
115 }
116
117 public String getCache() {
118 return cache;
119 }
120 public void setCache(String cache) {
121 this.cache = cache;
122 }
123
124 public List<TaggedText> getTaggedText() {
125 return taggedText;
126 }
127 // public void setTaggedText(List<TaggedText> taggedText) {
128 // this.taggedText = taggedText;
129 // }
130
131 public boolean isMisapplication() {
132 return misapplication;
133 }
134 public void setMisapplication(boolean misapplication) {
135 this.misapplication = misapplication;
136 }
137
138 public boolean isSynonym() {
139 return synonym;
140 }
141 public void setSynonym(boolean synonym) {
142 this.synonym = synonym;
143 }
144
145 public TermDto getType() {
146 return type;
147 }
148 public void setType(TermDto type) {
149 this.type = type;
150 }
151
152
153 /**
154 * @return the typeUuid
155 */
156 public UUID getTypeUuid() {
157 return typeUuid;
158 }
159
160
161 /**
162 * @param typeUuid the typeUuid to set
163 */
164 public void setTypeUuid(UUID typeUuid) {
165 this.typeUuid = typeUuid;
166 }
167
168 }
169
170 private List<TaxonRelation> relations = new ArrayList<>();
171
172 private List<List<TaggedText>> misapplications = new ArrayList<>();
173
174 private DateTime date = DateTime.now();
175
176 //** ******************* CONSTRUCTOR **************************/
177
178 public TaxonRelationshipsDTO() {}
179
180 // public TaxonRelationshipsDTO(UUID taxonUuid) {
181 // IncludedTaxon originalTaxon = new TaxonRelationshipsDTO(taxonUuid, false);
182 // includedTaxa.add(originalTaxon);
183 // }
184
185 // ************************** GETTER / SETTER ***********************/
186
187 public List<TaxonRelation> getRelations() {
188 return relations;
189 }
190
191 public void setIncludedTaxa(List<TaxonRelation> relations) {
192 this.relations = relations;
193 }
194
195 public void addRelation(TaxonRelation relation){
196 relations.add(relation);
197 }
198
199 /**
200 * @param relation
201 * @param direction
202 */
203 public TaxonRelation addRelation(TaxonRelationship relation, Direction direction, List<Language> languages) {
204 TaxonRelation newRelation = new TaxonRelation(relation, direction, languages);
205 relations.add(newRelation);
206 return newRelation;
207 }
208
209
210 /**
211 *
212 */
213 public void createMisapplicationString() {
214 List<List<TaggedText>> result = new ArrayList<>();
215
216 for (TaxonRelation relation: relations){
217 if (relation.isMisapplication()){
218 List<TaggedText> tags = relation.getTaggedText();
219
220 boolean isDuplicate = false;
221 for (List<TaggedText> existing: result){
222 isDuplicate = mergeIfDuplicate(existing, tags);
223 if (isDuplicate){
224 break;
225 }
226 }
227 if (!isDuplicate){
228 List<TaggedText> newTags = new ArrayList<>(tags.size());
229 newTags.addAll(tags);
230 result.add(newTags);
231 }
232 }
233 }
234 this.setMisapplications(result);
235 }
236
237 /**
238 * Checks if all tags are equal, except for the sensuReference tags
239 * @param existing
240 * @param tags
241 * @return
242 */
243 private boolean mergeIfDuplicate(List<TaggedText> first, List<TaggedText> second) {
244 int i = 0;
245 int j = 0;
246 int sensuEndInFirst = -1;
247 int sensuStartInSecond = -1;
248 int senusEndInSecond = -1;
249
250 boolean sensuHandled = false;
251 boolean isDuplicate = true;
252 while (isDuplicate && i < first.size() && j< second.size()){
253 if (tagEqualsMisapplied(first.get(i), second.get(i))){
254 i++;j++;
255 }else if (!sensuHandled){
256 while (i < first.size() && tagIsSensu(first.get(i))){
257 i++;
258 sensuEndInFirst = i;
259 }
260 sensuStartInSecond = j;
261 while (j< second.size() && tagIsSensu(second.get(j))){
262 j++;
263 senusEndInSecond = j;
264 }
265 sensuHandled = true;
266 }else{
267 isDuplicate = false;
268 i++;j++; //not really necessary
269 }
270
271 }
272 isDuplicate = isDuplicate && i == first.size() && j == second.size();
273 if (isDuplicate && sensuEndInFirst > -1 && sensuStartInSecond > -1){
274 first.addAll(sensuEndInFirst, second.subList(sensuStartInSecond, senusEndInSecond));
275 first.add(sensuEndInFirst, TaggedText.NewSeparatorInstance(SENSU_SEPARATOR));
276 return true;
277 }else{
278 return false;
279 }
280 }
281
282 /**
283 * @param taggedText
284 * @return
285 */
286 private boolean tagIsSensu(TaggedText tag) {
287 if (tag.getType() == TagEnum.secReference ||
288 tag.getType() == TagEnum.secMicroReference ||
289 isSensuSeparator(tag)){
290 return true;
291 }
292 return false;
293 }
294
295 /**
296 * @param tag
297 * @return
298 */
299 private boolean isSensuSeparator(TaggedText tag) {
300 if (SENSU_SEPARATOR.equals(tag.getText())
301 && tag.getType() == TagEnum.separator) {
302 return true;
303 }
304 return false;
305 }
306
307 /**
308 * @param x
309 * @param y
310 * @return
311 */
312 private boolean tagEqualsMisapplied(TaggedText x, TaggedText y) {
313 if (CdmUtils.nullSafeEqual(x.getText(),y.getText())
314 && x.getType().equals(y.getType())
315 && CdmUtils.nullSafeEqual(x.getEntityReference(),y.getEntityReference())){
316 return true;
317 }else{
318 return false;
319 }
320 }
321
322 public DateTime getDate() {
323 return date;
324 }
325 public void setDate(DateTime date) {
326 this.date = date;
327 }
328
329 public int getSize(){
330 return relations.size();
331 }
332 //
333 // public boolean contains(UUID taxonUuid) {
334 // for (TaxonRelation relation: relations){
335 // if (taxon.taxonUuid.equals(taxonUuid)){
336 // return true;
337 // }
338 // }
339 // return false;
340 // }
341
342 @Override
343 public String toString(){
344 String result = "";
345 for (TaxonRelation relation : relations){
346 result += relation.toString() + ",";
347 }
348 if (result.length() > 0){
349 result = result.substring(0, result.length() - 1);
350 }
351
352 result = "[" + result + "]";
353 return result;
354 }
355
356 /**
357 * @return the misapplications
358 */
359 public List<List<TaggedText>> getMisapplications() {
360 return misapplications;
361 }
362
363 /**
364 * @param misapplications the misapplications to set
365 */
366 public void setMisapplications(List<List<TaggedText>> misapplications) {
367 this.misapplications = misapplications;
368 }
369
370
371 }