View Javadoc
1   package fr.ifremer.tutti.service.export;
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 com.google.common.base.Predicate;
26  import com.google.common.collect.Lists;
27  import com.google.common.collect.Maps;
28  import com.google.common.collect.Multimap;
29  import fr.ifremer.tutti.persistence.entities.data.BatchContainer;
30  import fr.ifremer.tutti.persistence.entities.data.CatchBatch;
31  import fr.ifremer.tutti.persistence.entities.data.FishingOperation;
32  import fr.ifremer.tutti.persistence.entities.data.MarineLitterBatch;
33  import fr.ifremer.tutti.persistence.entities.data.SpeciesBatch;
34  import fr.ifremer.tutti.persistence.entities.data.SpeciesBatchFrequency;
35  import fr.ifremer.tutti.persistence.entities.referential.Species;
36  import fr.ifremer.tutti.service.PersistenceService;
37  import fr.ifremer.tutti.service.catches.WeightComputingService;
38  import fr.ifremer.tutti.util.Numbers;
39  import org.apache.commons.collections4.CollectionUtils;
40  
41  import java.util.Collection;
42  import java.util.List;
43  import java.util.Map;
44  
45  /**
46   * Contains the global context for a catch export.
47   *
48   * Created on 11/21/13.
49   *
50   * @author Tony Chemit - chemit@codelutin.com
51   * @since 3.0-rc-1
52   */
53  public class ExportCatchContext {
54  
55      final FishingOperation fishingOperation;
56  
57      final CatchBatch catchBatch;
58  
59      final BatchContainer<SpeciesBatch> rootSpeciesBatch;
60  
61      final BatchContainer<SpeciesBatch> rootBenthosBatch;
62  
63      final BatchContainer<MarineLitterBatch> marineLitterBatches;
64  
65      final Multimap<Species, SpeciesBatchFrequency> speciesFrequencies;
66  
67      final Multimap<Species, SpeciesBatchFrequency> benthosFrequencies;
68  
69      final Predicate<SpeciesBatch> vracPredicate;
70  
71      public static ExportCatchContext newExportContext(PersistenceService persistenceService,
72                                                        WeightComputingService weightComputingService,
73                                                        Integer fishingOperationId,
74                                                        boolean loadFrequencies) {
75  
76          FishingOperation fishingOperation =
77                  persistenceService.getFishingOperation(fishingOperationId);
78  
79          CatchBatch catchBatch =
80                  persistenceService.getCatchBatchFromFishingOperation(fishingOperationId);
81  
82          BatchContainer<SpeciesBatch> rootSpeciesBatch =
83                  weightComputingService.getComputedSpeciesBatches(fishingOperationId);
84  
85          BatchContainer<SpeciesBatch> rootBenthosBatch =
86                  weightComputingService.getComputedBenthosBatches(fishingOperationId);
87  
88          BatchContainer<MarineLitterBatch> marineLitterBatches =
89                  weightComputingService.getComputedMarineLitterBatches(
90                          fishingOperationId,
91                          catchBatch.getMarineLitterTotalWeight());
92          weightComputingService.computeCatchBatchWeights(catchBatch,
93                                                          rootSpeciesBatch,
94                                                          rootBenthosBatch,
95                                                          marineLitterBatches);
96  
97          Multimap<Species, SpeciesBatchFrequency> speciesFrequencies;
98          Multimap<Species, SpeciesBatchFrequency> benthosFrequencies;
99  
100         if (loadFrequencies) {
101 
102             speciesFrequencies = persistenceService.getAllSpeciesBatchFrequencyForBatch(rootSpeciesBatch);
103             benthosFrequencies = persistenceService.getAllBenthosBatchFrequencyForBatch(rootBenthosBatch);
104         } else {
105             speciesFrequencies = null;
106             benthosFrequencies = null;
107         }
108 
109         Predicate<SpeciesBatch> vracPredicate = persistenceService.getVracBatchPredicate();
110 
111         return new ExportCatchContext(vracPredicate,
112                                       fishingOperation,
113                                       catchBatch,
114                                       rootSpeciesBatch,
115                                       speciesFrequencies,
116                                       rootBenthosBatch,
117                                       benthosFrequencies,
118                                       marineLitterBatches);
119 
120     }
121 
122     private ExportCatchContext(Predicate<SpeciesBatch> vracPredicate,
123                                FishingOperation fishingOperation,
124                                CatchBatch catchBatch,
125                                BatchContainer<SpeciesBatch> rootSpeciesBatch,
126                                Multimap<Species, SpeciesBatchFrequency> speciesFrequencies,
127                                BatchContainer<SpeciesBatch> rootBenthosBatch,
128                                Multimap<Species, SpeciesBatchFrequency> benthosFrequencies,
129                                BatchContainer<MarineLitterBatch> marineLitterBatches) {
130         this.vracPredicate = vracPredicate;
131         this.fishingOperation = fishingOperation;
132         this.catchBatch = catchBatch;
133         this.rootSpeciesBatch = rootSpeciesBatch;
134         this.speciesFrequencies = speciesFrequencies;
135         this.benthosFrequencies = benthosFrequencies;
136         this.rootBenthosBatch = rootBenthosBatch;
137         this.marineLitterBatches = marineLitterBatches;
138     }
139 
140     public FishingOperation getFishingOperation() {
141         return fishingOperation;
142     }
143 
144     public float getCatchTotalWeight() {
145         return Numbers.getValueOrComputedValue(
146                 catchBatch.getCatchTotalWeight(),
147                 catchBatch.getCatchTotalComputedWeight());
148     }
149 
150     public float getCatchTotalSortedWeight() {
151         return catchBatch.getSpeciesTotalSampleSortedComputedWeight() +
152                 catchBatch.getBenthosTotalSampleSortedComputedWeight() +
153                 catchBatch.getSpeciesTotalUnsortedComputedWeight() +
154                 catchBatch.getBenthosTotalUnsortedComputedWeight();
155     }
156 
157     public float getSpeciesTotalSortedWeight() {
158         return Numbers.getValueOrComputedValue(
159                 catchBatch.getSpeciesTotalSortedWeight(),
160                 catchBatch.getSpeciesTotalSortedComputedWeight());
161     }
162 
163     public float getBenthosTotalSortedWeight() {
164         return Numbers.getValueOrComputedValue(
165                 catchBatch.getBenthosTotalSortedWeight(),
166                 catchBatch.getBenthosTotalSortedComputedWeight());
167     }
168 
169     public boolean withSpeciesBatches() {
170         return rootSpeciesBatch != null && !rootSpeciesBatch.isEmptyChildren();
171     }
172 
173     public boolean withBenthosBatches() {
174         return rootBenthosBatch != null && !rootBenthosBatch.isEmptyChildren();
175     }
176 
177     public boolean withSpeciesFrequencies() {
178         return speciesFrequencies != null && !speciesFrequencies.isEmpty();
179     }
180 
181     public boolean withBenthosFrequencies() {
182         return benthosFrequencies != null && !benthosFrequencies.isEmpty();
183     }
184 
185     public List<ExportBatchEntry> getSpeciesBatchEntry(boolean computeNumber) {
186         List<ExportBatchEntry> catchList = Lists.newArrayList();
187 
188         if (withSpeciesBatches()) {
189 
190             boolean withFrequencies = withSpeciesFrequencies();
191 
192             Map<Species, ExportBatchEntry> catches = Maps.newLinkedHashMap();
193 
194             // ratio total species weight / total sorted sampled species weight
195             float rate = getSpeciesElevationRate();
196 
197             List<SpeciesBatch> batches = rootSpeciesBatch.getChildren();
198             for (SpeciesBatch batch : batches) {
199 
200                 ExportBatchEntry aCatch = createExportBatchCatch(
201                         batch,
202                         catches,
203                         rate,
204                         computeNumber);
205 
206                 if (withFrequencies) {
207                     addFrequencies(aCatch, speciesFrequencies);
208                 }
209             }
210             catchList.addAll(catches.values());
211         }
212         return catchList;
213     }
214 
215     public List<ExportBatchEntry> getBenthosBatchEntry(boolean computeNumber) {
216         List<ExportBatchEntry> catchList = Lists.newArrayList();
217 
218         if (withBenthosBatches()) {
219 
220             boolean withFrequencies = withBenthosFrequencies();
221 
222             Map<Species, ExportBatchEntry> catches = Maps.newLinkedHashMap();
223 
224             // ratio total species weight / total sorted sampled species weight
225             float rate = getBenthosElevationRate();
226 
227             List<SpeciesBatch> batches = rootBenthosBatch.getChildren();
228             for (SpeciesBatch batch : batches) {
229 
230                 ExportBatchEntry aCatch = createExportBatchCatch(
231                         batch,
232                         catches,
233                         rate,
234                         computeNumber);
235 
236                 if (withFrequencies) {
237                     addFrequencies(aCatch, benthosFrequencies);
238                 }
239             }
240 
241             catchList.addAll(catches.values());
242         }
243         return catchList;
244     }
245 
246     public ExportBatchEntry getInertAndLivingNotItemizedCatch() {
247 
248         ExportBatchEntry result = new ExportBatchEntry(null);
249 
250         float speciesRatio = getSpeciesElevationRate();
251         float benthosRatio = getBenthosElevationRate();
252 
253         Float speciesInterWeight = Numbers.getValueOrComputedValue(
254                 catchBatch.getSpeciesTotalInertWeight(),
255                 catchBatch.getSpeciesTotalInertComputedWeight());
256 
257         if (speciesInterWeight != null) {
258             result.addSortedWeight(speciesInterWeight);
259             result.addTotalWeight(speciesInterWeight * speciesRatio);
260         }
261 
262         Float speciesLivingNotItemizedWeigth = Numbers.getValueOrComputedValue(
263                 catchBatch.getSpeciesTotalLivingNotItemizedWeight(),
264                 catchBatch.getSpeciesTotalLivingNotItemizedComputedWeight());
265 
266         if (speciesLivingNotItemizedWeigth != null) {
267             result.addSortedWeight(speciesLivingNotItemizedWeigth);
268             result.addTotalWeight(speciesLivingNotItemizedWeigth * speciesRatio);
269         }
270 
271         Float benthosInterWeight = Numbers.getValueOrComputedValue(
272                 catchBatch.getBenthosTotalInertWeight(),
273                 catchBatch.getBenthosTotalInertComputedWeight());
274 
275         if (benthosInterWeight != null) {
276             result.addSortedWeight(benthosInterWeight);
277             result.addTotalWeight(benthosInterWeight * benthosRatio);
278         }
279 
280         Float benthosLivingNotItemizedWeight = Numbers.getValueOrComputedValue(
281                 catchBatch.getBenthosTotalLivingNotItemizedWeight(),
282                 catchBatch.getBenthosTotalLivingNotItemizedComputedWeight());
283 
284         if (benthosLivingNotItemizedWeight != null) {
285             result.addSortedWeight(benthosLivingNotItemizedWeight);
286             result.addTotalWeight(benthosLivingNotItemizedWeight * benthosRatio);
287         }
288 
289         return result;
290     }
291 
292     public boolean isVracBatch(SpeciesBatch batch) {
293         return vracPredicate.apply(batch);
294     }
295 
296     protected float getSpeciesElevationRate() {
297 
298         float globalRatio = catchBatch.getCatchTotalSortedComputedWeight() / catchBatch.getCatchTotalSortedSortedComputedWeight();
299 
300         float speciesTotalSortedWeight = getSpeciesTotalSortedWeight();
301 
302         // ratio total species weight / total sorted sampled species weight
303         float result = globalRatio * speciesTotalSortedWeight;
304         if (catchBatch.getSpeciesTotalSampleSortedComputedWeight() > 0) {
305             result /= catchBatch.getSpeciesTotalSampleSortedComputedWeight();
306         }
307         return result;
308     }
309 
310     protected float getBenthosElevationRate() {
311 
312         float globalRatio = catchBatch.getCatchTotalSortedComputedWeight() / catchBatch.getCatchTotalSortedSortedComputedWeight();
313 
314         float benthosTotalSortedWeight = getBenthosTotalSortedWeight();
315 
316         // ratio total benthos weight / total sorted sampled benthos weight
317         float result = globalRatio * benthosTotalSortedWeight;
318         if (catchBatch.getBenthosTotalSampleSortedComputedWeight() > 0) {
319             result /= catchBatch.getBenthosTotalSampleSortedComputedWeight();
320         }
321         return result;
322     }
323 
324     protected ExportBatchEntry createExportBatchCatch(SpeciesBatch batch,
325                                                       Map<Species, ExportBatchEntry> catches,
326                                                       float ratio,
327                                                       boolean computeNumber) {
328 
329         Species species = batch.getSpecies();
330 
331         ExportBatchEntry ktch = catches.get(species);
332         if (ktch == null) {
333             ktch = new ExportBatchEntry(batch);
334             catches.put(species, ktch);
335         }
336 
337         float sortedWeight = Numbers.getValueOrComputedValue(
338                 batch.getSampleCategoryWeight(),
339                 batch.getSampleCategoryComputedWeight());
340 
341         ktch.addSortedWeight(sortedWeight);
342 
343         boolean isVracBatch = isVracBatch(batch);
344         float speciesTotalWeight = sortedWeight;
345         if (isVracBatch) {
346             speciesTotalWeight *= ratio;
347         }
348         ktch.addTotalWeight(speciesTotalWeight);
349 
350         if (computeNumber) {
351             float number = Math.round(computeNumber(batch, 1.0f));
352             if (isVracBatch) {
353                 number *= ratio;
354             }
355             ktch.addNumber(Math.round(number));
356         }
357         return ktch;
358     }
359 
360     protected float computeNumber(SpeciesBatch batch, float rf) {
361         float result;
362 
363         float weight = Numbers.getValueOrComputedValue(
364                 batch.getSampleCategoryWeight(),
365                 batch.getSampleCategoryComputedWeight());
366 
367         if (batch.isChildBatchsEmpty()) {
368 
369             // on a leaf, get his weight
370 
371             Integer number = Numbers.getValueOrComputedValue(
372                     batch.getNumber(),
373                     batch.getComputedNumber());
374             if (number == null) {
375 
376                 // no count
377                 number = 0;
378             }
379 
380             // get the sample weight
381             Float subweight = Numbers.getValueOrComputedValue(
382                     batch.getWeight(),
383                     batch.getComputedWeight());
384 
385             if (subweight != null) {
386 
387                 // with sub sample, update the raising factor
388                 rf *= weight / subweight;
389             }
390 
391             result = number.floatValue() * rf;
392         } else {
393 
394             // get total weight of all childs
395             float totalWeight = 0.f;
396             for (SpeciesBatch child : batch.getChildBatchs()) {
397                 totalWeight += Numbers.getValueOrComputedValue(
398                         child.getSampleCategoryWeight(),
399                         child.getSampleCategoryComputedWeight());
400             }
401 
402             result = 0f;
403 
404             float rf2 = rf * weight / totalWeight;
405             // sum result of each child
406             for (SpeciesBatch child : batch.getChildBatchs()) {
407 
408                 result += computeNumber(child, rf2);
409             }
410 
411         }
412         return result;
413     }
414 
415     protected <F extends SpeciesBatchFrequency> void addFrequencies(ExportBatchEntry aCatch,
416                                                                     Multimap<Species, F> frequencies) {
417         Species species = aCatch.getBatch().getSpecies();
418         Collection<F> batchFrequencies = frequencies.get(species);
419         if (CollectionUtils.isNotEmpty(batchFrequencies)) {
420             for (F batchFrequency : batchFrequencies) {
421                 Integer number = batchFrequency.getNumber();
422                 Float lengthStep = batchFrequency.getLengthStep();
423                 aCatch.addFrequency(lengthStep, number);
424             }
425         }
426     }
427 }