View Javadoc
1   package fr.ifremer.tutti.service.catches;
2   
3   /*
4    * #%L
5    * Tutti :: Service
6    * %%
7    * Copyright (C) 2012 - 2014 Ifremer
8    * %%
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU General Public License as
11   * published by the Free Software Foundation, either version 3 of the 
12   * License, or (at your option) any later version.
13   * 
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Public License for more details.
18   * 
19   * You should have received a copy of the GNU General Public 
20   * License along with this program.  If not, see
21   * <http://www.gnu.org/licenses/gpl-3.0.html>.
22   * #L%
23   */
24  
25  import fr.ifremer.tutti.persistence.entities.data.BatchContainer;
26  import fr.ifremer.tutti.persistence.entities.data.CatchBatch;
27  import fr.ifremer.tutti.persistence.entities.data.MarineLitterBatch;
28  import fr.ifremer.tutti.persistence.entities.data.SampleCategoryModelEntry;
29  import fr.ifremer.tutti.persistence.entities.data.SpeciesBatch;
30  import fr.ifremer.tutti.persistence.entities.data.SpeciesBatchFrequency;
31  import fr.ifremer.tutti.persistence.entities.referential.Species;
32  import fr.ifremer.tutti.service.AbstractTuttiService;
33  import fr.ifremer.tutti.service.DecoratorService;
34  import fr.ifremer.tutti.service.PersistenceService;
35  import fr.ifremer.tutti.service.TuttiServiceContext;
36  import fr.ifremer.tutti.service.ValidationService;
37  import fr.ifremer.tutti.type.WeightUnit;
38  import fr.ifremer.tutti.util.Numbers;
39  import org.apache.commons.collections4.CollectionUtils;
40  import org.apache.commons.lang3.tuple.Pair;
41  import org.nuiton.decorator.Decorator;
42  import org.nuiton.validator.NuitonValidatorResult;
43  
44  import java.io.Serializable;
45  import java.util.List;
46  
47  /**
48   * @author Kevin Morin - kmorin@codelutin.com
49   * @since 1.3
50   */
51  public class WeightComputingService extends AbstractTuttiService {
52  
53      protected PersistenceService persistenceService;
54  
55      protected ValidationService validationService;
56  
57      protected DecoratorService decoratorService;
58  
59      private Decorator<Species> speciesDecorator;
60  
61      private int currentSpeciesRowIndex;
62      private int currentBenthosRowIndex;
63  
64      @Override
65      public void setServiceContext(TuttiServiceContext context) {
66          super.setServiceContext(context);
67          persistenceService = getService(PersistenceService.class);
68          validationService = getService(ValidationService.class);
69          decoratorService = getService(DecoratorService.class);
70      }
71  
72      /**
73       * Compute the weights of the catch batch (not the ones of the species, benthos nor marine litter batches)
74       *
75       * @param catchBatch            the catch batch with the weights to compute
76       * @param rootSpeciesBatch      the species batches with already computed weights
77       * @param rootBenthosBatch      the benthos batches with already computed weights
78       * @param rootMarineLitterBatch the marine litter batches with already computed weights
79       */
80      public void computeCatchBatchWeights(CatchBatch catchBatch,
81                                           BatchContainer<SpeciesBatch> rootSpeciesBatch,
82                                           BatchContainer<SpeciesBatch> rootBenthosBatch,
83                                           BatchContainer<MarineLitterBatch> rootMarineLitterBatch) {
84  
85          // Species
86          Float speciesTotalComputedSortedWeight = 0f;
87          Float speciesTotalComputedUnsortedWeight = 0f;
88  
89          if (rootSpeciesBatch != null) {
90              Pair<Float, Float> pair = computeTotalComputedSortedAndUnsortedWeights(rootSpeciesBatch);
91              speciesTotalComputedSortedWeight = pair.getLeft();
92              speciesTotalComputedUnsortedWeight = pair.getRight();
93          }
94  
95          Float speciesInertWeight = catchBatch.getSpeciesTotalInertWeight();
96          if (speciesInertWeight != null) {
97              speciesTotalComputedSortedWeight += speciesInertWeight;
98          } else {
99              catchBatch.setSpeciesTotalInertComputedWeight(0f);
100         }
101 
102         Float speciesLivingNotItemizedWeight = catchBatch.getSpeciesTotalLivingNotItemizedWeight();
103         if (speciesLivingNotItemizedWeight != null) {
104             speciesTotalComputedSortedWeight += speciesLivingNotItemizedWeight;
105         } else {
106             catchBatch.setSpeciesTotalLivingNotItemizedComputedWeight(0f);
107         }
108 
109         catchBatch.setSpeciesTotalSampleSortedComputedWeight(WeightUnit.KG.round(speciesTotalComputedSortedWeight));
110 
111         Float speciesTotalSortedWeight = catchBatch.getSpeciesTotalSortedWeight();
112         if (speciesTotalSortedWeight == null) {
113             speciesTotalSortedWeight = speciesTotalComputedSortedWeight;
114             catchBatch.setSpeciesTotalSortedComputedWeight(WeightUnit.KG.round(speciesTotalSortedWeight));
115 
116         } else if (WeightUnit.KG.isSmallerThan(speciesTotalSortedWeight, speciesTotalComputedSortedWeight)) {
117 
118             throw SpeciesWeightComputingException.forIncoherentTotalSorted(getSpeciesWeightUnit(),
119                                                                            speciesTotalSortedWeight,
120                                                                            speciesTotalComputedSortedWeight);
121 
122         }
123         catchBatch.setSpeciesTotalUnsortedComputedWeight(WeightUnit.KG.round(speciesTotalComputedUnsortedWeight));
124 
125         if (speciesTotalSortedWeight == null) {
126             speciesTotalSortedWeight = catchBatch.getSpeciesTotalSortedComputedWeight();
127         }
128 
129         // Benthos
130         Float benthosTotalComputedSortedWeight = 0f;
131         Float benthosTotalComputedUnsortedWeight = 0f;
132 
133         if (rootBenthosBatch != null) {
134 
135             Pair<Float, Float> pair = computeTotalComputedSortedAndUnsortedWeights(rootBenthosBatch);
136             benthosTotalComputedSortedWeight = pair.getLeft();
137             benthosTotalComputedUnsortedWeight = pair.getRight();
138 
139         }
140 
141         Float benthosInertWeight = catchBatch.getBenthosTotalInertWeight();
142         if (benthosInertWeight != null) {
143             benthosTotalComputedSortedWeight += benthosInertWeight;
144         } else {
145             catchBatch.setBenthosTotalInertComputedWeight(0f);
146         }
147 
148         Float benthosLivingNotItemizedWeight = catchBatch.getBenthosTotalLivingNotItemizedWeight();
149         if (benthosLivingNotItemizedWeight != null) {
150             benthosTotalComputedSortedWeight += benthosLivingNotItemizedWeight;
151         } else {
152             catchBatch.setBenthosTotalLivingNotItemizedComputedWeight(0f);
153         }
154 
155         catchBatch.setBenthosTotalSampleSortedComputedWeight(WeightUnit.KG.round(benthosTotalComputedSortedWeight));
156 
157         Float benthosTotalSortedWeight = catchBatch.getBenthosTotalSortedWeight();
158         if (benthosTotalSortedWeight == null) {
159             benthosTotalSortedWeight = benthosTotalComputedSortedWeight;
160             catchBatch.setBenthosTotalSortedComputedWeight(WeightUnit.KG.round(benthosTotalSortedWeight));
161 
162         } else if (WeightUnit.KG.isSmallerThan(benthosTotalSortedWeight, benthosTotalComputedSortedWeight)) {
163 
164             throw BenthosWeightComputingException.forIncoherentTotalSorted(
165                     getBenthosWeightUnit(),
166                     benthosTotalSortedWeight,
167                     benthosTotalComputedSortedWeight);
168 
169         }
170         catchBatch.setBenthosTotalUnsortedComputedWeight(WeightUnit.KG.round(benthosTotalComputedUnsortedWeight));
171 
172         if (benthosTotalSortedWeight == null) {
173             benthosTotalSortedWeight = catchBatch.getBenthosTotalSortedComputedWeight();
174         }
175 
176         // Marine litter
177         Float marineLitterTotalComputedWeight = 0f;
178 
179         if (rootMarineLitterBatch != null) {
180 
181             for (MarineLitterBatch row : rootMarineLitterBatch.getChildren()) {
182                 Float rowWeight = row.getWeight();
183                 if (rowWeight == null) {
184                     marineLitterTotalComputedWeight = null;
185                     break;
186                 }
187                 marineLitterTotalComputedWeight += rowWeight;
188             }
189 
190         }
191         if (marineLitterTotalComputedWeight != null) {
192 
193             marineLitterTotalComputedWeight = WeightUnit.KG.round(marineLitterTotalComputedWeight);
194             catchBatch.setMarineLitterTotalComputedWeight(marineLitterTotalComputedWeight);
195 
196         }
197 
198         Float marineLitterTotalWeight = catchBatch.getMarineLitterTotalWeight();
199         if (marineLitterTotalWeight != null
200                 && marineLitterTotalComputedWeight != null
201                 && WeightUnit.KG.isSmallerThan(marineLitterTotalWeight, marineLitterTotalComputedWeight)) {
202 
203             throw MarineLitterWeightComputingException.forIncoherentTotal(getMarineLitterWeightUnit(),
204                                                                           marineLitterTotalWeight,
205                                                                           marineLitterTotalComputedWeight);
206 
207         }
208         // nothing to do with the marine litter weight, it is an isolated weight
209 
210         // Catch
211         Float totalUnsortedWeight = catchBatch.getSpeciesTotalUnsortedComputedWeight() + catchBatch.getBenthosTotalUnsortedComputedWeight();
212 
213         Float totalSortedSortedWeight = speciesTotalSortedWeight + benthosTotalSortedWeight;
214 
215         catchBatch.setCatchTotalSortedSortedComputedWeight(WeightUnit.KG.round(totalSortedSortedWeight));
216         catchBatch.setCatchTotalUnsortedComputedWeight(WeightUnit.KG.round(totalUnsortedWeight));
217 
218         Float totalWeight = catchBatch.getCatchTotalWeight();
219         Float rejectedWeight = catchBatch.getCatchTotalRejectedWeight();
220 
221         if (rejectedWeight == null && totalWeight != null) {
222 
223             Float computedTotalWeight = WeightUnit.KG.round(totalUnsortedWeight + totalSortedSortedWeight);
224 
225             if (WeightUnit.KG.isNotEquals(totalWeight, computedTotalWeight)) {
226 
227                 throw CatchWeightComputingException.forIncoherentTotal(getCatchWeightUnit(),
228                                                                        totalWeight,
229                                                                        computedTotalWeight);
230 
231             }
232 
233             //FIXME voir avec Vincent si on calcule le poids rejeté
234             catchBatch.setCatchTotalRejectedComputedWeight(WeightUnit.KG.round(totalWeight - totalUnsortedWeight - totalSortedSortedWeight));
235 
236         } else if (totalWeight == null) {
237             if (rejectedWeight == null) {
238                 rejectedWeight = 0f;
239                 catchBatch.setCatchTotalRejectedComputedWeight(0f);
240             }
241             catchBatch.setCatchTotalComputedWeight(WeightUnit.KG.round(totalUnsortedWeight + totalSortedSortedWeight + rejectedWeight));
242 
243         } else {
244 
245             Float computedTotalWeight = WeightUnit.KG.round(totalUnsortedWeight + totalSortedSortedWeight + rejectedWeight);
246             if (WeightUnit.KG.isNotEquals(totalWeight, computedTotalWeight)) {
247 
248                 throw CatchWeightComputingException.forIncoherentTotalWithRejected(getCatchWeightUnit(),
249                                                                                    totalWeight,
250                                                                                    computedTotalWeight);
251             }
252 
253         }
254 
255         Float totalSortedWeight = totalSortedSortedWeight;
256         if (rejectedWeight != null) {
257             totalSortedWeight += rejectedWeight;
258         }
259         catchBatch.setCatchTotalSortedComputedWeight(WeightUnit.KG.round(totalSortedWeight));
260 
261         Float catchRate;
262 
263         if (WeightUnit.KG.isZero(totalSortedSortedWeight)) {
264             catchRate = 0f;
265         } else {
266             catchRate = totalSortedWeight / totalSortedSortedWeight;
267         }
268 
269         Float speciesTotalWeight = speciesTotalSortedWeight * catchRate + speciesTotalComputedUnsortedWeight;
270         catchBatch.setSpeciesTotalComputedWeight(WeightUnit.KG.round(speciesTotalWeight));
271 
272         Float benthosTotalWeight = benthosTotalSortedWeight * catchRate + benthosTotalComputedUnsortedWeight;
273         catchBatch.setBenthosTotalComputedWeight(WeightUnit.KG.round(benthosTotalWeight));
274     }
275 
276     public BatchContainer<SpeciesBatch> getComputedSpeciesBatches(Integer operationId) {
277 
278         BatchContainer<SpeciesBatch> rootSpeciesBatch = null;
279 
280         if (persistenceService.isFishingOperationWithCatchBatch(operationId)) {
281             rootSpeciesBatch = persistenceService.getRootSpeciesBatch(operationId, false);
282 
283             currentSpeciesRowIndex = 0;
284             if (rootSpeciesBatch != null) {
285                 rootSpeciesBatch.getChildren().forEach(this::computeSpeciesBatch);
286             }
287         }
288 
289         return rootSpeciesBatch;
290 
291     }
292 
293     public Float computeSpeciesBatch(SpeciesBatch batch) {
294 
295         Float result = null;
296         int thisIndex = currentSpeciesRowIndex++;
297         Float categoryWeight = batch.getSampleCategoryWeight();
298         Float rowWeight = batch.getWeight();
299 
300         NuitonValidatorResult validation = validationService.validateEditSpeciesBatch(batch);
301         if (!validation.isValid()) {
302 
303             List<String> messages = validation.getErrorMessages(SpeciesBatch.PROPERTY_WEIGHT);
304             throw SpeciesWeightComputingException.forValidationMessage(
305                     getSpeciesWeightUnit(),
306                     messages.get(0),
307                     decorateSpecies(batch.getSpecies()),
308                     getCategoryLabel(batch.getSampleCategoryId()),
309                     decorateCategoryValue(batch.getSampleCategoryValue()),
310                     batch.getWeight(),
311                     batch.getSampleCategoryWeight(),
312                     thisIndex);
313         }
314 
315         List<SpeciesBatch> children = batch.getChildBatchs();
316         // if the row is not a leaf
317         if (batch.sizeChildBatchs() > 0) {
318             Float sum = 0f;
319             // make the sum of the children weights
320             for (SpeciesBatch child : children) {
321                 Float weight = computeSpeciesBatch(child);
322                 if (weight == null) {
323                     sum = null;
324                     break;
325                 }
326                 sum += weight;
327             }
328             sum = WeightUnit.KG.round(sum);
329 
330             if (sum != null) {
331                 if (categoryWeight == null) {
332                     batch.setSampleCategoryComputedWeight(sum);
333 
334                 } else if (WeightUnit.KG.isSmallerThan(categoryWeight, sum)) {
335 
336                     throw SpeciesWeightComputingException.forIncoherentParentCategoryWeight(
337                             getSpeciesWeightUnit(),
338                             decorateSpecies(batch.getSpecies()),
339                             getCategoryLabel(batch.getSampleCategoryId()),
340                             decorateCategoryValue(batch.getSampleCategoryValue()),
341                             categoryWeight,
342                             sum,
343                             thisIndex);
344 
345                 } else {
346                     sum = categoryWeight;
347                 }
348                 result = sum;
349             }
350 
351         } else {// the row is a leaf
352 
353             batch.setComputedWeight(null);
354 
355             List<SpeciesBatchFrequency> frequencies = persistenceService.getAllSpeciesBatchFrequency(batch.getIdAsInt());
356 
357             if (CollectionUtils.isNotEmpty(frequencies)) {
358                 // if there are frequencies, then compute their weight
359                 Float frequencyWeight = sumFrequenciesWeight(frequencies);
360 
361                 if (categoryWeight == null && rowWeight != null) {
362 //                    throw new TuttiBusinessException(t("tutti.service.operations.computeWeights.error.incoherentRowWeightCategory"));
363 
364                 } else if (rowWeight != null && frequencyWeight != null && WeightUnit.KG.isNotEquals(rowWeight, frequencyWeight)) {
365 
366                     throw SpeciesWeightComputingException.forIncoherentRowWeightFrequency(getSpeciesWeightUnit(),
367                                                                                           decorateSpecies(batch.getSpecies()),
368                                                                                           getCategoryLabel(batch.getSampleCategoryId()),
369                                                                                           decorateCategoryValue(batch.getSampleCategoryValue()),
370                                                                                           frequencyWeight,
371                                                                                           rowWeight,
372                                                                                           thisIndex);
373 
374                 } else if (categoryWeight == null && frequencyWeight != null) {
375                     // if the category weight is null and the frequencies have a weight,
376                     // then this weight is the result
377                     batch.setSampleCategoryComputedWeight(frequencyWeight);
378                     result = frequencyWeight;
379 
380                 } else if (frequencyWeight != null && WeightUnit.KG.isNotEquals(frequencyWeight, categoryWeight)) {
381 
382                     // if the weight of the frequencies is different from the category
383                     // weight, then set the weight of the sample
384                     if (WeightUnit.KG.isGreaterThan(frequencyWeight, categoryWeight)) {
385 
386                         throw SpeciesWeightComputingException.forIncoherentCategoryWeight(getSpeciesWeightUnit(),
387                                                                                           decorateSpecies(batch.getSpecies()),
388                                                                                           getCategoryLabel(batch.getSampleCategoryId()),
389                                                                                           decorateCategoryValue(batch.getSampleCategoryValue()),
390                                                                                           frequencyWeight,
391                                                                                           categoryWeight,
392                                                                                           thisIndex);
393 
394                     } else if (rowWeight == null) {
395                         batch.setComputedWeight(frequencyWeight);
396 
397                     }
398                     result = categoryWeight;
399 
400                 } else {
401                     result = categoryWeight;
402                 }
403 
404                 // compute number from frequencies
405                 Integer frequencyNumber = sumFrequenciesNumber(frequencies);
406                 batch.setComputedNumber(frequencyNumber);
407 
408             } else {
409                 result = categoryWeight;
410             }
411         }
412         if (WeightUnit.KG.isNullOrZero(result)) {
413 
414             throw SpeciesWeightComputingException.forNoWeight(decorateSpecies(batch.getSpecies()),
415                                                               getCategoryLabel(batch.getSampleCategoryId()),
416                                                               decorateCategoryValue(batch.getSampleCategoryValue()),
417                                                               thisIndex);
418         }
419 
420         return WeightUnit.KG.round(result);
421     }
422 
423     public BatchContainer<SpeciesBatch> getComputedBenthosBatches(Integer operationId) {
424 
425         BatchContainer<SpeciesBatch> rootBenthosBatch = null;
426 
427         if (persistenceService.isFishingOperationWithCatchBatch(operationId)) {
428 
429             rootBenthosBatch = persistenceService.getRootBenthosBatch(operationId, false);
430 
431             currentBenthosRowIndex = 0;
432             if (rootBenthosBatch != null) {
433                 rootBenthosBatch.getChildren().forEach(this::computeBenthosBatch);
434             }
435         }
436 
437         return rootBenthosBatch;
438 
439     }
440 
441     public Float computeBenthosBatch(SpeciesBatch batch) {
442 
443         Float result = null;
444         int thisIndex = currentBenthosRowIndex++;
445         Float categoryWeight = batch.getSampleCategoryWeight();
446         Float rowWeight = batch.getWeight();
447 
448         NuitonValidatorResult validation = validationService.validateEditBenthosBatch(batch);
449         if (!validation.isValid()) {
450             List<String> messages = validation.getErrorMessages(SpeciesBatch.PROPERTY_WEIGHT);
451 
452             throw BenthosWeightComputingException.forValidationMessage(getBenthosWeightUnit(),
453                                                                        messages.get(0),
454                                                                        decorateSpecies(batch.getSpecies()),
455                                                                        getCategoryLabel(batch.getSampleCategoryId()),
456                                                                        decorateCategoryValue(batch.getSampleCategoryValue()),
457                                                                        batch.getWeight(),
458                                                                        batch.getSampleCategoryWeight(),
459                                                                        thisIndex);
460         }
461 
462         List<SpeciesBatch> children = batch.getChildBatchs();
463         // if the row is not a leaf
464         if (!batch.isChildBatchsEmpty()) {
465             Float sum = 0f;
466             // make the sum of the children weights
467             for (SpeciesBatch child : children) {
468                 Float weight = computeBenthosBatch(child);
469                 if (weight == null) {
470                     sum = null;
471                     break;
472                 }
473                 sum += weight;
474             }
475             sum = WeightUnit.KG.round(sum);
476 
477             if (sum != null) {
478                 if (categoryWeight == null) {
479                     batch.setSampleCategoryComputedWeight(sum);
480 
481                 } else if (WeightUnit.KG.isSmallerThan(categoryWeight, sum)) {
482 
483                     throw BenthosWeightComputingException.forIncoherentParentCategoryWeight(getBenthosWeightUnit(),
484                                                                                             decorateSpecies(batch.getSpecies()),
485                                                                                             getCategoryLabel(batch.getSampleCategoryId()),
486                                                                                             decorateCategoryValue(batch.getSampleCategoryValue()),
487                                                                                             categoryWeight,
488                                                                                             sum,
489                                                                                             thisIndex);
490 
491                 } else {
492                     sum = categoryWeight;
493                 }
494                 result = sum;
495 
496             }
497 
498         } else {// the row is a leaf
499 
500             batch.setComputedWeight(null);
501 
502             List<SpeciesBatchFrequency> frequencies = persistenceService.getAllBenthosBatchFrequency(batch.getIdAsInt());
503 
504             if (CollectionUtils.isNotEmpty(frequencies)) {
505                 // if there are frequencies, then compute their weight
506                 Float frequencyWeight = sumFrequenciesWeight(frequencies);
507 
508                 if (categoryWeight == null && rowWeight != null) {
509 //                    throw new TuttiBusinessException(t("tutti.service.operations.computeWeights.error.incoherentRowWeightCategory"));
510 
511                 } else if (rowWeight != null && frequencyWeight != null && WeightUnit.KG.isNotEquals(rowWeight, frequencyWeight)) {
512 
513                     throw BenthosWeightComputingException.forIncoherentRowWeightFrequency(getBenthosWeightUnit(),
514                                                                                           decorateSpecies(batch.getSpecies()),
515                                                                                           getCategoryLabel(batch.getSampleCategoryId()),
516                                                                                           decorateCategoryValue(batch.getSampleCategoryValue()),
517                                                                                           rowWeight,
518                                                                                           categoryWeight,
519                                                                                           thisIndex);
520 
521                 } else if (categoryWeight == null && frequencyWeight != null) {
522                     // if the category weight is null and the frequencies have a weight,
523                     // then this weight is the result
524                     batch.setSampleCategoryComputedWeight(frequencyWeight);
525                     result = frequencyWeight;
526 
527                 } else if (frequencyWeight != null && WeightUnit.KG.isNotEquals(frequencyWeight, categoryWeight)) {
528 
529                     // if the weight of the frequencies is different from the category
530                     // weight, then set the weight of the sample
531                     if (WeightUnit.KG.isGreaterThan(frequencyWeight, categoryWeight)) {
532 
533                         throw BenthosWeightComputingException.forIncoherentCategoryWeight(getBenthosWeightUnit(),
534                                                                                           decorateSpecies(batch.getSpecies()),
535                                                                                           getCategoryLabel(batch.getSampleCategoryId()),
536                                                                                           decorateCategoryValue(batch.getSampleCategoryValue()),
537                                                                                           frequencyWeight,
538                                                                                           categoryWeight,
539                                                                                           thisIndex);
540 
541                     } else if (rowWeight == null) {
542                         batch.setComputedWeight(frequencyWeight);
543 
544                     }
545                     result = categoryWeight;
546 
547                 } else {
548                     result = categoryWeight;
549                 }
550 
551                 // compute number from frequencies
552                 Integer frequencyNumber = sumFrequenciesNumber(frequencies);
553                 batch.setComputedNumber(frequencyNumber);
554             } else {
555                 result = categoryWeight;
556             }
557         }
558         if (WeightUnit.KG.isNullOrZero(result)) {
559 
560             throw BenthosWeightComputingException.forNoWeight(decorateSpecies(batch.getSpecies()),
561                                                               getCategoryLabel(batch.getSampleCategoryId()),
562                                                               decorateCategoryValue(batch.getSampleCategoryValue()),
563                                                               thisIndex);
564         }
565 
566         return WeightUnit.KG.round(result);
567 
568     }
569 
570     public BatchContainer<MarineLitterBatch> getComputedMarineLitterBatches(Integer fishingOperationId, Float marineLitterWeight) {
571 
572         BatchContainer<MarineLitterBatch> rootMarineLitterBatch = persistenceService.getRootMarineLitterBatch(fishingOperationId);
573 
574         if (rootMarineLitterBatch != null) {
575             boolean checkWeight = marineLitterWeight == null;
576 
577             List<MarineLitterBatch> children = rootMarineLitterBatch.getChildren();
578             for (int i = 0; i < children.size(); i++) {
579                 MarineLitterBatch batch = children.get(i);
580 
581                 if (checkWeight && WeightUnit.KG.isNullOrZero(batch.getWeight())) {
582                     throw MarineLitterWeightComputingException.forNoWeight(i);
583                 }
584             }
585         }
586 
587         return rootMarineLitterBatch;
588 
589     }
590 
591     private Pair<Float, Float> computeTotalComputedSortedAndUnsortedWeights(BatchContainer<SpeciesBatch> rootSpeciesBatch) {
592 
593         Float speciesTotalComputedSortedWeight = 0f;
594         Float speciesTotalComputedUnsortedWeight = 0f;
595 
596         for (SpeciesBatch speciesBatch : rootSpeciesBatch.getChildren()) {
597             Float weight = Numbers.getValueOrComputedValue(speciesBatch.getSampleCategoryWeight(),
598                                                            speciesBatch.getSampleCategoryComputedWeight());
599             if (weight == null) {
600                 break;
601             }
602 
603             if (persistenceService.isVracBatch(speciesBatch)) {
604                 speciesTotalComputedSortedWeight += weight;
605             } else {
606                 speciesTotalComputedUnsortedWeight += weight;
607             }
608 
609         }
610 
611         return Pair.of(speciesTotalComputedSortedWeight, speciesTotalComputedUnsortedWeight);
612 
613     }
614 
615     private String getCategoryLabel(Integer sampleCategoryId) {
616         SampleCategoryModelEntry category = context.getSampleCategoryModel().getCategoryById(sampleCategoryId);
617         return category.getLabel();
618     }
619 
620     private Integer sumFrequenciesNumber(List<SpeciesBatchFrequency> frequencies) {
621         Integer frequencyNumber = 0;
622         for (SpeciesBatchFrequency frequency : frequencies) {
623             Integer c = frequency.getNumber();
624             frequencyNumber += c;
625         }
626         return frequencyNumber;
627     }
628 
629     private Float sumFrequenciesWeight(List<SpeciesBatchFrequency> frequencies) {
630         Float frequencyWeight = 0f;
631         for (SpeciesBatchFrequency frequency : frequencies) {
632             Float w = frequency.getWeight();
633             if (w == null) {
634 
635                 // can't sum when a null value appears
636                 frequencyWeight = null;
637                 break;
638 
639             } else if (frequencyWeight != null) {
640 
641                 // still can sum weights
642                 frequencyWeight += w;
643             }
644         }
645         frequencyWeight = WeightUnit.KG.round(frequencyWeight);
646         return frequencyWeight;
647     }
648 
649     private String decorateSpecies(Species species) {
650         if (speciesDecorator == null) {
651             speciesDecorator = decoratorService.getDecoratorByType(Species.class);
652         }
653         return speciesDecorator.toString(species);
654     }
655 
656     private String decorateCategoryValue(Serializable sampleCategoryValue) {
657         return decoratorService.getDecorator(sampleCategoryValue).toString(sampleCategoryValue);
658     }
659 
660     private WeightUnit getSpeciesWeightUnit() {
661         return context.getConfig().getSpeciesWeightUnit();
662     }
663 
664     private WeightUnit getBenthosWeightUnit() {
665         return context.getConfig().getBenthosWeightUnit();
666     }
667 
668     private WeightUnit getMarineLitterWeightUnit() {
669         return context.getConfig().getMarineLitterWeightUnit();
670     }
671 
672     private WeightUnit getCatchWeightUnit() {
673         return WeightUnit.KG;
674     }
675 
676 }