View Javadoc
1   package fr.ifremer.tutti.persistence.service;
2   
3   /*
4    * #%L
5    * Tutti :: Persistence
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  
26  import com.google.common.base.Preconditions;
27  import fr.ifremer.adagio.core.dao.data.batch.Batch;
28  import fr.ifremer.adagio.core.dao.data.batch.CatchBatchImpl;
29  import fr.ifremer.adagio.core.dao.data.batch.SortingBatch;
30  import fr.ifremer.adagio.core.dao.data.batch.SortingBatchImpl;
31  import fr.ifremer.adagio.core.dao.data.measure.QuantificationMeasurement;
32  import fr.ifremer.adagio.core.dao.data.operation.FishingOperationImpl;
33  import fr.ifremer.adagio.core.dao.referential.QualityFlagCode;
34  import fr.ifremer.adagio.core.dao.referential.QualityFlagImpl;
35  import fr.ifremer.tutti.TuttiConfiguration;
36  import fr.ifremer.tutti.persistence.entities.data.CatchBatch;
37  import fr.ifremer.tutti.persistence.entities.data.CatchBatchBean;
38  import fr.ifremer.tutti.persistence.service.util.BatchPersistenceHelper;
39  import fr.ifremer.tutti.persistence.service.util.tree.BatchTreeHelper;
40  import fr.ifremer.tutti.persistence.service.util.MeasurementPersistenceHelper;
41  import fr.ifremer.tutti.persistence.service.util.SynchronizationStatusHelper;
42  import fr.ifremer.tutti.type.WeightUnit;
43  import fr.ifremer.tutti.util.Numbers;
44  import org.apache.commons.collections4.CollectionUtils;
45  import org.apache.commons.logging.Log;
46  import org.apache.commons.logging.LogFactory;
47  import org.hibernate.FlushMode;
48  import org.hibernate.type.IntegerType;
49  import org.springframework.dao.DataIntegrityViolationException;
50  import org.springframework.dao.DataRetrievalFailureException;
51  import org.springframework.stereotype.Service;
52  
53  import javax.annotation.Resource;
54  import java.math.BigDecimal;
55  import java.util.Collection;
56  import java.util.HashMap;
57  import java.util.HashSet;
58  import java.util.Map;
59  import java.util.Set;
60  import java.util.TreeMap;
61  import org.hibernate.Query;
62  
63  @Service("batchPersistenceService")
64  public class CatchBatchPersistenceServiceImpl
65          extends AbstractPersistenceService implements CatchBatchPersistenceService {
66  
67      /** Logger. */
68      private static final Log log =
69              LogFactory.getLog(CatchBatchPersistenceServiceImpl.class);
70  
71      @Resource(name = "attachmentPersistenceService")
72      protected AttachmentPersistenceService attachmentPersistenceService;
73  
74      @Resource(name = "batchPersistenceHelper")
75      protected BatchPersistenceHelper batchHelper;
76  
77      @Resource(name = "batchTreeHelper")
78      protected BatchTreeHelper batchTreeHelper;
79  
80      @Resource(name = "measurementPersistenceHelper")
81      protected MeasurementPersistenceHelper measurementPersistenceHelper;
82  
83      @Resource(name = "synchronizationStatusHelper")
84      protected SynchronizationStatusHelper synchronizationStatusHelper;
85  
86      //------------------------------------------------------------------------//
87      //-- CatchBatch methods                                                 --//
88      //------------------------------------------------------------------------//
89  
90      @Override
91      public boolean isFishingOperationWithCatchBatch(Integer operationId) {
92          Preconditions.checkNotNull(operationId);
93          return batchHelper.isCatchBatchExistsForFishingOperation(operationId);
94      }
95  
96      @Override
97      public CatchBatch getCatchBatchFromFishingOperation(Integer fishingOperationId) {
98          Preconditions.checkNotNull(fishingOperationId);
99  
100         // whenever want to repair anything from Tutti
101         fr.ifremer.adagio.core.dao.data.batch.CatchBatch source =
102                 batchHelper.getRootCatchBatchByFishingOperationId(fishingOperationId, true);
103 
104         if (log.isDebugEnabled()) {
105             log.debug("Loaded CatchBatch: " + source.getId());
106         }
107 
108         boolean showBatchLog = TuttiConfiguration.getInstance().isShowBatchLog();
109 
110         if (showBatchLog) {
111 
112             batchTreeHelper.displayCatchBatch(source);
113 
114         }
115 
116         CatchBatch result = new CatchBatchBean();
117 
118         entityToBean(source, result);
119 
120         return result;
121     }
122 
123     @Override
124     public CatchBatch createCatchBatch(CatchBatch bean) {
125         Preconditions.checkNotNull(bean);
126         Preconditions.checkArgument(bean.getId() == null);
127         Preconditions.checkNotNull(bean.getFishingOperation());
128         Preconditions.checkNotNull(bean.getFishingOperation().getId());
129 
130         fr.ifremer.adagio.core.dao.data.batch.CatchBatch catchBatch = fr.ifremer.adagio.core.dao.data.batch.CatchBatch.Factory.newInstance();
131         beanToEntity(bean, catchBatch);
132         bean = batchHelper.createCatchBatch(bean, catchBatch);
133 
134         // Link to fishing operation
135         getCurrentSession().flush();
136         Integer fishingOperationId = bean.getFishingOperation().getIdAsInt();
137         int rowUpdated = queryUpdate("updateFishingOperationCatchBatch",
138                                      "fishingOperationId", IntegerType.INSTANCE, fishingOperationId,
139                                      "catchBatchId", IntegerType.INSTANCE, catchBatch.getId());
140         if (rowUpdated == 0) {
141             throw new DataIntegrityViolationException("Could not attach catch batch to the given operation : operation was not found.");
142         }
143 
144         // bean is dirty
145         synchronizationStatusHelper.setDirty(bean);
146         return bean;
147     }
148 
149     @Override
150     public CatchBatch saveCatchBatch(CatchBatch bean) {
151 
152         Preconditions.checkNotNull(bean);
153         Preconditions.checkNotNull(bean.getId());
154         Preconditions.checkNotNull(bean.getFishingOperation());
155         Preconditions.checkNotNull(bean.getFishingOperation().getId());
156 
157         getCurrentSession().enableFetchProfile("batch-with-childs");
158         getCurrentSession().setFlushMode(FlushMode.COMMIT);
159         fr.ifremer.adagio.core.dao.data.batch.CatchBatch catchBatch = load(CatchBatchImpl.class, bean.getIdAsInt());
160         if (catchBatch == null) {
161             throw new DataRetrievalFailureException("Could not retrieve catch batch with id=" + bean.getId());
162         }
163 
164         beanToEntity(bean, catchBatch);
165         batchHelper.update(catchBatch);
166         getCurrentSession().flush();
167 
168         // bean is dirty
169         synchronizationStatusHelper.setDirty(bean);
170         return bean;
171     }
172 
173     @Override
174     public void deleteCatchBatch(Integer fishingOperationId) {
175         Preconditions.checkNotNull(fishingOperationId);
176         Integer catchBatchId = batchHelper.getCatchBatchIdByFishingOperationId(fishingOperationId);
177 
178         if (catchBatchId == null) {
179             throw new DataRetrievalFailureException("Could not retrieve catch batch for fishingOperation id=" + fishingOperationId);
180         }
181 
182         batchHelper.deleteCatchBatch(fishingOperationId, catchBatchId);
183     }
184 
185     @Override
186     public void recomputeCatchBatchSampleRatios(Integer fishingOperationId) {
187 
188         Preconditions.checkNotNull(fishingOperationId);
189         Integer catchBatchId = batchHelper.getCatchBatchIdByFishingOperationId(fishingOperationId);
190 
191         if (catchBatchId == null) {
192             throw new DataRetrievalFailureException("Could not retrieve catch batch for fishingOperation id=" + fishingOperationId);
193         }
194 
195         fr.ifremer.adagio.core.dao.data.batch.CatchBatch catchBatch = batchTreeHelper.loadCatchBatch(catchBatchId);
196 
197         // To store computed indirect weights by batch
198         // If a batch has a weight before sampling then nothing is computed
199         Map<Integer, SortingBatch> indirectWeightByBatch = new TreeMap<>();
200 
201         // To store quantification measurement ids which need to update to pass
202         // is_reference_quantification to false
203         // such measurements are only on batch nodes (leaf always keep the value to true)
204         Set<QuantificationMeasurement> quantificationMeasurements = new HashSet<>();
205 
206         Set<Integer> indirectWeightByBatchSkip = new HashSet<>();
207 
208         for (Batch rootBatch : catchBatch.getChildBatchs()) {
209 
210             computeIndirectWeight(rootBatch,
211                                   indirectWeightByBatch,
212                                   indirectWeightByBatchSkip,
213                                   quantificationMeasurements);
214 
215         }
216 
217         if (!indirectWeightByBatch.isEmpty()) {
218 
219             // update batchs sample ratio
220             for (SortingBatch batch : indirectWeightByBatch.values()) {
221 
222                 Float weight = batch.getWeight();
223                 Float indirectWeight = batch.getIndirectWeight();
224                 batch.setIndirectWeight(null);
225 
226                 if (indirectWeight == null) {
227 
228                     // will reuse then the weight
229                     indirectWeight = weight;
230                 }
231 
232                 if (log.isInfoEnabled()) {
233                     log.info(String.format("setWeightAndSampleRatio :: %d (%s // %s)", batch.getId(), weight, indirectWeight));
234                 }
235 
236                 SortingBatch sortingBatch = load(SortingBatchImpl.class, batch.getId());
237                 batchTreeHelper.setSortingSamplingRatio(sortingBatch, indirectWeight, weight);
238 
239             }
240 
241         }
242         if (!quantificationMeasurements.isEmpty()) {
243 
244             // remove measurements
245             if (log.isInfoEnabled()) {
246                 log.info("updateQuantificationMeasurementsForBatchNodes :: " + quantificationMeasurements);
247             }
248 
249             for (QuantificationMeasurement quantificationMeasurement : quantificationMeasurements) {
250 
251                 if (log.isInfoEnabled()) {
252                     log.info(String.format("Remove quantification measurement %d on batch %d (batch is not a leaf)", quantificationMeasurement.getId(), quantificationMeasurement.getBatch().getId()));
253                 }
254                 Batch batch = quantificationMeasurement.getBatch();
255                 SortingBatch sortingBatch = load(SortingBatchImpl.class, batch.getId());
256                 measurementPersistenceHelper.removeWeightMeasurementQuantificationMeasurement(sortingBatch, quantificationMeasurement);
257             }
258 
259         }
260 
261     }
262 
263     //------------------------------------------------------------------------//
264     //-- Internal methods                                                   --//
265     //------------------------------------------------------------------------//
266 
267     protected void entityToBean(fr.ifremer.adagio.core.dao.data.batch.CatchBatch source, CatchBatch target) {
268 
269         target.setId(source.getId());
270         target.setCatchTotalWeight(source.getWeight());
271         target.setSynchronizationStatus(source.getSynchronizationStatus());
272 
273         // -- Vrac
274         SortingBatch vracBatch = batchTreeHelper.getVracBatch(source);
275 
276         if (vracBatch != null) {
277 
278             target.setCatchTotalSortedCarousselWeight(vracBatch.getWeight());
279             target.setCatchTotalSortedTremisWeight(vracBatch.getWeightBeforeSampling());
280 
281             // -- Vrac > Species
282             SortingBatch vracSpeciesBatch = batchTreeHelper.getSpeciesVracRootBatch(vracBatch);
283 
284             if (vracSpeciesBatch != null) {
285 
286                 target.setSpeciesTotalSortedWeight(vracSpeciesBatch.getWeight());
287 
288                 // -- Vrac > Species > Inert
289                 SortingBatch inertBatch = batchTreeHelper.getSpeciesVracInertRootBatch(vracSpeciesBatch);
290 
291                 if (inertBatch != null) {
292                     target.setSpeciesTotalInertWeight(inertBatch.getWeight());
293                 }
294 
295                 // -- Vrac > Species > Alive not itemized
296                 SortingBatch livingNotItemizedBatch = batchTreeHelper.getSpeciesVracAliveNotItemizedRootBatch(vracSpeciesBatch);
297 
298                 if (livingNotItemizedBatch != null) {
299                     target.setSpeciesTotalLivingNotItemizedWeight(livingNotItemizedBatch.getWeight());
300                 }
301             }
302 
303             // -- Vrac > Benthos
304             SortingBatch vracBenthosBatch = batchTreeHelper.getBenthosVracRootBatch(vracBatch);
305 
306             if (vracBenthosBatch != null) {
307                 target.setBenthosTotalSortedWeight(vracBenthosBatch.getWeight());
308 
309                 // -- Vrac > Benthos > Inert
310                 SortingBatch inertBatch = batchTreeHelper.getBenthosVracInertRootBatch(vracBenthosBatch);
311 
312                 if (inertBatch != null) {
313                     target.setBenthosTotalInertWeight(inertBatch.getWeight());
314                 }
315 
316                 // -- Vrac > Benthos > Alive no itemized
317                 SortingBatch livingNotItemizedBatch = batchTreeHelper.getBenthosVracAliveNotItemizedRootBatch(vracBenthosBatch);
318 
319                 if (livingNotItemizedBatch != null) {
320                     target.setBenthosTotalLivingNotItemizedWeight(livingNotItemizedBatch.getWeight());
321                 }
322             }
323         }
324 
325         // -- Hors Vrac
326         SortingBatch horsVracBatch = batchTreeHelper.getHorsVracBatch(source);
327 
328         if (horsVracBatch != null) {
329 
330             // -- Hors Vrac > Species
331             batchTreeHelper.getSpeciesHorsVracRootBatch(horsVracBatch);
332 
333             // -- Hors Vrac > Benthos
334             batchTreeHelper.getBenthosHorsVracRootBatch(horsVracBatch);
335 
336             // -- Hors Vrac > MarineLitter
337             SortingBatch marineLitterBatch = batchTreeHelper.getMarineLitterRootBatch(horsVracBatch);
338 
339             if (marineLitterBatch != null) {
340                 target.setMarineLitterTotalWeight(marineLitterBatch.getWeight());
341             }
342         }
343 
344         // -- Unsorted
345         SortingBatch unsortedBatch = batchTreeHelper.getRejectedBatch(source);
346 
347         if (unsortedBatch != null) {
348             target.setCatchTotalRejectedWeight(unsortedBatch.getWeight());
349         }
350     }
351 
352     protected void beanToEntity(CatchBatch source,
353                                 fr.ifremer.adagio.core.dao.data.batch.CatchBatch target) {
354         Preconditions.checkNotNull(source.getFishingOperation());
355         Preconditions.checkNotNull(source.getFishingOperation().getId());
356 
357         // First initialization (when created)
358         Integer fishingOperationId = source.getFishingOperation().getIdAsInt();
359         target.setFishingOperation(load(FishingOperationImpl.class, fishingOperationId));
360 
361         // Quality flag
362         target.setQualityFlag(load(QualityFlagImpl.class, QualityFlagCode.NOTQUALIFIED.getValue()));
363 
364         // Rank order
365         target.setRankOrder((short) 1);
366 
367         // Synchronization status
368         synchronizationStatusHelper.setDirty(target);
369 
370         // Total Weight
371         if (source.getCatchTotalWeight() == null) {
372 
373             QuantificationMeasurement quantificationMeasurement = measurementPersistenceHelper.getWeightMeasurementQuantificationMeasurement(target);
374             if (quantificationMeasurement != null) {
375 
376                 // remove it
377                 measurementPersistenceHelper.removeWeightMeasurementQuantificationMeasurement(target, quantificationMeasurement);
378             }
379         } else {
380 
381             measurementPersistenceHelper.setWeightMeasurementQuantificationMeasurement(
382                     target,
383                     source.getCatchTotalWeight());
384         }
385 
386         SortingBatch vracBatch = batchTreeHelper.getVracBatch(target);
387 
388         SortingBatch horsVracBatch = batchTreeHelper.getHorsVracBatch(target);
389 
390         SortingBatch horsVracSpeciesRootBatch = null;
391         SortingBatch horsVracBenthosRootBatch = null;
392         SortingBatch horsVracMarineLitterRootBatch = null;
393 
394         if (horsVracBatch != null) {
395 
396             horsVracSpeciesRootBatch = batchTreeHelper.getSpeciesHorsVracRootBatch(horsVracBatch);
397             horsVracBenthosRootBatch = batchTreeHelper.getBenthosHorsVracRootBatch(horsVracBatch);
398             horsVracMarineLitterRootBatch = batchTreeHelper.getMarineLitterRootBatch(horsVracBatch);
399         }
400 
401         SortingBatch speciesVracBatch = null;
402         SortingBatch benthosVracBatch = null;
403 
404         SortingBatch speciesVracAliveNotItemizeRootBatch = null;
405         SortingBatch speciesVracInertRootBatch = null;
406         SortingBatch speciesVracAliveItemizeRootBatch = null;
407         SortingBatch benthosVracAliveNotItemizeRootBatch = null;
408         SortingBatch benthosVracInertRootBatch = null;
409         SortingBatch benthosVracAliveItemizeRootBatch = null;
410 
411         if (vracBatch != null) {
412             speciesVracBatch = batchTreeHelper.getSpeciesVracRootBatch(vracBatch);
413 
414             if (speciesVracBatch != null) {
415                 speciesVracAliveNotItemizeRootBatch = batchTreeHelper.getSpeciesVracAliveNotItemizedRootBatch(speciesVracBatch);
416                 speciesVracInertRootBatch = batchTreeHelper.getSpeciesVracInertRootBatch(speciesVracBatch);
417                 speciesVracAliveItemizeRootBatch = batchTreeHelper.getSpeciesVracAliveItemizedRootBatch(speciesVracBatch);
418             }
419 
420             benthosVracBatch = batchTreeHelper.getBenthosVracRootBatch(vracBatch);
421             if (benthosVracBatch != null) {
422                 benthosVracAliveNotItemizeRootBatch = batchTreeHelper.getBenthosVracAliveNotItemizedRootBatch(benthosVracBatch);
423                 benthosVracInertRootBatch = batchTreeHelper.getBenthosVracInertRootBatch(benthosVracBatch);
424                 benthosVracAliveItemizeRootBatch = batchTreeHelper.getBenthosVracAliveItemizedRootBatch(benthosVracBatch);
425             }
426         }
427 
428         boolean needVracSpeciesAliveNotItemized = speciesVracAliveNotItemizeRootBatch != null ||
429                                                   source.getSpeciesTotalLivingNotItemizedWeight() != null;
430         boolean needVracSpeciesInert = speciesVracInertRootBatch != null ||
431                                        source.getSpeciesTotalInertWeight() != null;
432         boolean needVracSpeciesAliveItemized = speciesVracAliveItemizeRootBatch != null;
433 
434         boolean needVracSpecies = speciesVracBatch != null ||
435                                   source.getSpeciesTotalSortedWeight() != null ||
436                                   needVracSpeciesAliveNotItemized ||
437                                   needVracSpeciesInert ||
438                                   needVracSpeciesAliveItemized;
439 
440         boolean needVracBenthosAliveNotItemized = benthosVracAliveNotItemizeRootBatch != null ||
441                                                   source.getBenthosTotalLivingNotItemizedWeight() != null;
442         boolean needVracBenthosInert = benthosVracInertRootBatch != null ||
443                                        source.getBenthosTotalInertWeight() != null;
444         boolean needVracBenthosAliveItemized = benthosVracAliveItemizeRootBatch != null;
445 
446         boolean needVracBenthos = benthosVracBatch != null ||
447                                   source.getBenthosTotalSortedWeight() != null ||
448                                   needVracBenthosAliveNotItemized ||
449                                   needVracBenthosInert ||
450                                   needVracBenthosAliveItemized;
451 
452         boolean needVrac = vracBatch != null ||
453                            source.getCatchTotalSortedCarousselWeight() != null ||
454                            source.getCatchTotalSortedTremisWeight() != null ||
455                            needVracSpecies ||
456                            needVracBenthos;
457 
458         boolean needHorsVracSpecies = horsVracSpeciesRootBatch != null;
459         boolean needHorsVracBenthos = horsVracBenthosRootBatch != null;
460         boolean needHorsVracMarineLitter = horsVracMarineLitterRootBatch != null ||
461                                            source.getMarineLitterTotalWeight() != null;
462 
463         boolean needHorsVrac = needHorsVracSpecies ||
464                                needHorsVracBenthos ||
465                                needHorsVracMarineLitter;
466 
467         boolean needUnsorted = batchTreeHelper.getRejectedBatch(target) != null ||
468                                source.getCatchTotalRejectedWeight() != null;
469 
470         if (needVrac) {
471             // -- Vrac
472             vracBatch = batchTreeHelper.getOrCreateVracBatch(
473                     target,
474                     source.getCatchTotalSortedCarousselWeight(),
475                     source.getCatchTotalSortedTremisWeight());
476 
477             if (needVracSpecies) {
478                 // -- Vrac > Species
479                 speciesVracBatch = batchTreeHelper.getOrCreateSpeciesVracRootBatch(
480                         target,
481                         vracBatch,
482                         source.getSpeciesTotalSortedWeight());
483 
484                 if (needVracSpeciesAliveNotItemized) {
485                     // -- Vrac > Species > Alive not itemized
486                     batchTreeHelper.getOrCreateSpeciesVracAliveNotItemizedRootBatch(
487                             target,
488                             speciesVracBatch,
489                             source.getSpeciesTotalLivingNotItemizedWeight());
490                 }
491 
492                 if (needVracSpeciesInert) {
493                     // -- Vrac > Species > Inert (not alive)
494                     batchTreeHelper.getOrCreateSpeciesVracInertRootBatch(
495                             target,
496                             speciesVracBatch,
497                             source.getSpeciesTotalInertWeight());
498                 }
499 
500                 if (needVracSpeciesAliveItemized) {
501                     // -- Vrac > Species > Alive itemized
502                     batchTreeHelper.getOrCreateSpeciesVracAliveItemizedRootBatch(
503                             target,
504                             speciesVracBatch);
505                 }
506             }
507 
508             if (needVracBenthos) {
509                 // -- Vrac > Benthos
510                 benthosVracBatch = batchTreeHelper.getOrCreateBenthosVracRootBatch(
511                         target,
512                         vracBatch,
513                         source.getBenthosTotalSortedWeight());
514 
515                 if (needVracBenthosAliveNotItemized) {
516                     // -- Vrac > Benthos > Alive not itemized
517                     batchTreeHelper.getOrCreateBenthosVracAliveNotItemizedRootBatch(
518                             target,
519                             benthosVracBatch,
520                             source.getBenthosTotalLivingNotItemizedWeight());
521                 }
522 
523                 if (needVracBenthosInert) {
524                     // -- Vrac > Benthos > Inert (not alive)
525                     batchTreeHelper.getOrCreateBenthosVracInertRootBatch(
526                             target,
527                             benthosVracBatch,
528                             source.getBenthosTotalInertWeight());
529                 }
530 
531                 if (needVracBenthosAliveItemized) {
532                     // -- Vrac > Benthos > Alive itemized
533                     batchTreeHelper.getOrCreateBenthosVracAliveItemizedRootBatch(
534                             target,
535                             benthosVracBatch);
536                 }
537             }
538 
539         }
540 
541         if (needHorsVrac) {
542             // -- Hors Vrac
543             horsVracBatch = batchTreeHelper.getOrCreateHorsVracBatch(target);
544 
545             if (needHorsVracSpecies) {
546                 // -- Hors Vrac > Species
547                 batchTreeHelper.getOrCreateSpeciesHorsVracRootBatch(
548                         target,
549                         horsVracBatch);
550             }
551 
552             if (needHorsVracBenthos) {
553                 // -- Hors Vrac > Benthos
554                 batchTreeHelper.getOrCreateBenthosHorsVracRootBatch(
555                         target,
556                         horsVracBatch);
557             }
558 
559             if (needHorsVracMarineLitter) {
560                 // -- Hors Vrac > MarineLitter
561                 batchTreeHelper.getOrCreateMarineLitterRootBatch(
562                         target,
563                         horsVracBatch,
564                         source.getMarineLitterTotalWeight());
565             }
566         }
567 
568         if (needUnsorted) {
569             // -- Unsorted (=rejected)
570             batchTreeHelper.getOrCreateRejectedBatch(
571                     target, source.getCatchTotalRejectedWeight());
572         }
573     }
574 
575     protected void computeIndirectWeight(Batch batch,
576                                          Map<Integer, SortingBatch> indirectWeightByBatch,
577                                          Set<Integer> indirectWeightByBatchSkip,
578                                          Set<QuantificationMeasurement> quantificationMeasurements) {
579 
580         Integer batchId = batch.getId();
581 
582         if (indirectWeightByBatch.containsKey(batchId) ||
583             indirectWeightByBatchSkip.contains(batchId)) {
584 
585             // already computed
586             return;
587 
588         }
589 
590         Collection<Batch> childBatchs = batch.getChildBatchs();
591         boolean batchIsLeaf = CollectionUtils.isEmpty(childBatchs);
592 
593         if (batchIsLeaf) {
594 
595             // on a leaf, nothing else to do
596             if (log.isDebugEnabled()) {
597                 log.debug("[BATCH :: " + batchId + "] - Do not compute on a leaf ");
598             }
599             return;
600 
601         }
602 
603         QuantificationMeasurement measurement = measurementPersistenceHelper.getWeightMeasurementQuantificationMeasurement(batch);
604         if (measurement != null) {
605 
606             // need to remove the quantification measurement
607             quantificationMeasurements.add(measurement);
608 
609             if (log.isDebugEnabled()) {
610                 log.debug("[BATCH :: " + batchId + "] - Need to remove the quantification measurement (not a leaf) :: " + measurement.getId());
611             }
612 
613         }
614 
615         // compute indirect weights of childs before all
616 
617         for (Batch childBatch : childBatchs) {
618 
619             computeIndirectWeight(childBatch, indirectWeightByBatch, indirectWeightByBatchSkip, quantificationMeasurements);
620 
621         }
622 
623         if (batch.getWeightBeforeSampling() != null) {
624 
625             // no need to compute indirect weight, mark batch
626             indirectWeightByBatchSkip.add(batchId);
627 
628             if (log.isDebugEnabled()) {
629                 log.debug("[BATCH :: " + batchId + "] - No need of indirect weight (there is a weight before sampling) ");
630             }
631             return;
632 
633         }
634 
635         // At last, compute the indirect weight
636         Float indirectWeight = computeIndirectWeight(batch);
637         batch.setIndirectWeight(indirectWeight);
638 
639         if (batch.getWeight() != null) {
640 
641             // Can only update the sample ratio if there is a weight on the batch
642             indirectWeightByBatch.put(batchId, (SortingBatch) batch);
643 
644         }
645 
646         if (log.isDebugEnabled()) {
647             log.debug("[BATCH :: " + batchId + "] - " + "Computed indirect weight " + indirectWeight);
648         }
649 
650     }
651 
652     protected Float computeIndirectWeight(Batch batch) {
653 
654         if (log.isDebugEnabled()) {
655             log.debug("[BATCH :: " + batch.getId() + "] compute indirect weight");
656         }
657 
658         BigDecimal result = new BigDecimal(0);
659 
660         for (Batch childBatch : batch.getChildBatchs()) {
661 
662             Float weight = Numbers.getValueOrComputedValue(childBatch.getWeightBeforeSampling(),
663                                                            childBatch.getWeight());
664 
665             if (weight == null) {
666 
667                 //  at last use the indirectWeight
668                 weight = childBatch.getIndirectWeight();
669 
670             }
671 
672             if (weight == null) {
673 
674                 if (log.isDebugEnabled()) {
675                     log.debug("[BATCH :: " + batch.getId() + "] Found a child batch " + childBatch.getId() + " has no weight, skip computing indirect weight for batch :: ...");
676                 }
677 
678                 return null;
679 
680             }
681             result = result.add(new BigDecimal(String.valueOf(weight)));
682 
683         }
684 
685         return WeightUnit.KG.round(result.floatValue());
686 
687     }
688 
689     //------------------------------------------------------------------------//
690     //-- Other methods                                                      --//
691     //------------------------------------------------------------------------//
692 
693     @Override
694     public Map getPrevOperationNameAndBatchId(int operationId, int taxonId) {
695         // TODO poussin 20160729 put hql in query file (xml) and use getNamedQuery instead of createQuery
696         String sql = "SELECT o.id as operationId, b.id as batchId"
697                 + " FROM OPERATION o JOIN batch b ON o.catch_batch_fk=b.root_batch_fk"
698                 + " WHERE o.is_fishing_operation = 1"
699                 + "   AND o.fishing_trip_fk = (SELECT fishing_trip_fk FROM operation WHERE id = :operationId)"
700                 + "   AND o.fishing_end_date_time < (select fishing_end_date_time from operation where id = :operationId)"
701                 + "   AND b.reference_taxon_fk = :taxonId"
702                 + " ORDER BY o.fishing_start_date_time DESC, b.id;";
703 
704         Query q = getCurrentSession().createSQLQuery(sql);
705         q.setInteger("operationId", operationId);
706         q.setInteger("taxonId", taxonId);
707         q.setMaxResults(1);
708 
709         Object[] select = (Object[])q.uniqueResult();
710         Map result = null;
711         if (select != null && select.length == 2) {
712             result = new HashMap();
713             result.put("operationId", select[0]);
714             result.put("batchId", select[1]);
715         }
716 
717         return result;
718     }
719     
720     @Override
721     public Map getNextOperationNameAndBatchId(int operationId, int taxonId) {
722         // TODO poussin 20160729 put hql in query file (xml) and use getNamedQuery instead of createQuery
723         String sql = "SELECT o.id as operationId, b.id as batchId"
724                 + " FROM OPERATION o JOIN batch b ON o.catch_batch_fk=b.root_batch_fk"
725                 + " WHERE o.is_fishing_operation = 1"
726                 + "   AND o.fishing_trip_fk = (SELECT fishing_trip_fk FROM operation WHERE id = :operationId)"
727                 + "   AND o.fishing_end_date_time > (select fishing_end_date_time from operation where id = :operationId)"
728                 + "   AND b.reference_taxon_fk = :taxonId"
729                 + " ORDER BY o.fishing_start_date_time ASC, b.id;";
730 
731         Query q = getCurrentSession().createSQLQuery(sql);
732         q.setInteger("operationId", operationId);
733         q.setInteger("taxonId", taxonId);
734         q.setMaxResults(1);
735 
736         Object[] select = (Object[])q.uniqueResult();
737         Map result = null;
738         if (select != null && select.length == 2) {
739             result = new HashMap();
740             result.put("operationId", select[0]);
741             result.put("batchId", select[1]);
742         }
743 
744         return result;
745     }
746 }