View Javadoc
1   package fr.ifremer.tutti.persistence.entities.protocol;
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  import com.esotericsoftware.yamlbeans.YamlConfig;
26  import com.esotericsoftware.yamlbeans.YamlReader;
27  import com.esotericsoftware.yamlbeans.YamlWriter;
28  import com.google.common.base.Joiner;
29  import com.google.common.base.Preconditions;
30  import com.google.common.collect.Collections2;
31  import com.google.common.collect.Maps;
32  import com.google.common.collect.Multimap;
33  import com.google.common.io.Files;
34  import fr.ifremer.adagio.core.dao.referential.pmfm.PmfmId;
35  import fr.ifremer.tutti.persistence.TuttiPersistence;
36  import fr.ifremer.tutti.persistence.entities.data.SampleCategoryModel;
37  import fr.ifremer.tutti.persistence.entities.protocol.v1.SpeciesProtocol1;
38  import fr.ifremer.tutti.persistence.entities.protocol.v1.SpeciesProtocolBean1;
39  import fr.ifremer.tutti.persistence.entities.protocol.v1.TuttiProtocol1;
40  import fr.ifremer.tutti.persistence.entities.protocol.v1.TuttiProtocolBean1;
41  import fr.ifremer.tutti.persistence.entities.protocol.v2.TuttiProtocol2;
42  import fr.ifremer.tutti.persistence.entities.protocol.v2.TuttiProtocolBean2;
43  import fr.ifremer.tutti.persistence.entities.protocol.v3.SpeciesProtocol3;
44  import fr.ifremer.tutti.persistence.entities.protocol.v3.SpeciesProtocolBean3;
45  import fr.ifremer.tutti.persistence.entities.protocol.v3.TuttiProtocol3;
46  import fr.ifremer.tutti.persistence.entities.protocol.v3.TuttiProtocolBean3;
47  import fr.ifremer.tutti.persistence.entities.referential.Caracteristic;
48  import fr.ifremer.tutti.persistence.entities.referential.Species;
49  import fr.ifremer.tutti.persistence.entities.referential.Speciess;
50  import org.apache.commons.collections4.CollectionUtils;
51  import org.apache.commons.io.IOUtils;
52  import org.apache.commons.logging.Log;
53  import org.apache.commons.logging.LogFactory;
54  import org.nuiton.decorator.Decorator;
55  import org.nuiton.jaxx.application.ApplicationTechnicalException;
56  import org.nuiton.util.beans.Binder;
57  import org.nuiton.util.beans.BinderFactory;
58  
59  import java.io.BufferedWriter;
60  import java.io.File;
61  import java.io.Reader;
62  import java.nio.charset.StandardCharsets;
63  import java.util.ArrayList;
64  import java.util.Collection;
65  import java.util.Collections;
66  import java.util.Iterator;
67  import java.util.List;
68  import java.util.Map;
69  import java.util.Objects;
70  import java.util.Set;
71  import java.util.TreeMap;
72  
73  import static org.nuiton.i18n.I18n.t;
74  
75  /**
76   * Helper class around {@link TuttiProtocol}.
77   *
78   * @author Tony Chemit - chemit@codelutin.com
79   * @since 1.0
80   */
81  public class TuttiProtocols extends AbstractTuttiProtocols {
82  
83      /** Logger. */
84      private static final Log log = LogFactory.getLog(TuttiProtocols.class);
85  
86      public static final Integer CURRENT_PROTOCOL_VERSION = 4;
87  
88      public static void toFile(TuttiProtocol protocol, File file) {
89  
90          String id = protocol.getId();
91  
92          BufferedWriter fileWriter = null;
93          try {
94              fileWriter = Files.newWriter(file, StandardCharsets.UTF_8);
95              YamlWriter writer = new YamlWriter(fileWriter, createConfig());
96              writer.write(protocol);
97              writer.close();
98              fileWriter.close();
99          } catch (Exception e) {
100             throw new ApplicationTechnicalException(t("tutti.persistence.protocol.fromFile.error", id, file), e);//"Could not transform protocol " + to file
101         } finally {
102             IOUtils.closeQuietly(fileWriter);
103         }
104     }
105 
106     public static TuttiProtocol fromFile(File file) {
107         TuttiProtocol result;
108         Reader fileReader = null;
109         try {
110             fileReader = Files.newReader(file, StandardCharsets.UTF_8);
111             YamlReader reader = new YamlReader(fileReader, createConfig());
112             result = reader.read(typeOfTuttiProtocol());
113             fileReader.close();
114 
115             if (!CURRENT_PROTOCOL_VERSION.equals(result.getVersion())) {
116                 result = migrateProtocol(file);
117             }
118 
119         } catch (Exception e) {
120             if (log.isErrorEnabled()) {
121                 log.error("Error loading protocol, try to migrate", e);
122             }
123             result = migrateProtocol(file);
124 
125         } finally {
126             IOUtils.closeQuietly(fileReader);
127         }
128 
129         Integer sampleCategoryIdToRemove = PmfmId.SORTED_UNSORTED.getValue();
130         // transform String to Integer...
131         if (!result.isBenthosEmpty()) {
132             for (SpeciesProtocol speciesProtocol : result.getBenthos()) {
133                 List mandatorySampleCategoryId = speciesProtocol.getMandatorySampleCategoryId();
134                 List<Integer> mandatorySampleCategoryIdInteger = new ArrayList<>();
135                 for (Object o : mandatorySampleCategoryId) {
136                     mandatorySampleCategoryIdInteger.add(Integer.valueOf(o.toString()));
137                 }
138                 mandatorySampleCategoryIdInteger.remove(sampleCategoryIdToRemove);
139                 speciesProtocol.setMandatorySampleCategoryId(mandatorySampleCategoryIdInteger);
140 
141             }
142         }
143         if (!result.isSpeciesEmpty()) {
144             for (SpeciesProtocol speciesProtocol : result.getSpecies()) {
145                 List mandatorySampleCategoryId = speciesProtocol.getMandatorySampleCategoryId();
146                 List<Integer> mandatorySampleCategoryIdInteger = new ArrayList<>();
147                 for (Object o : mandatorySampleCategoryId) {
148                     mandatorySampleCategoryIdInteger.add(Integer.valueOf(o.toString()));
149                 }
150                 mandatorySampleCategoryIdInteger.remove(sampleCategoryIdToRemove);
151                 speciesProtocol.setMandatorySampleCategoryId(mandatorySampleCategoryIdInteger);
152 
153             }
154         }
155 
156         return result;
157     }
158 
159     public static void translateReferenceTaxonIds(TuttiProtocol result, Map<Integer, Integer> idTranslationMap) {
160 
161         List<SpeciesProtocol> species = result.getSpecies();
162         translateReferenceTaxonIds(species, idTranslationMap);
163 
164         List<SpeciesProtocol> benthos = result.getBenthos();
165         translateReferenceTaxonIds(benthos, idTranslationMap);
166 
167     }
168 
169     protected static void translateReferenceTaxonIds(List<SpeciesProtocol> species, Map<Integer, Integer> idTranslationMap) {
170 
171         for (SpeciesProtocol speciesProtocol : species) {
172             Integer speciesReferenceTaxonId = speciesProtocol.getSpeciesReferenceTaxonId();
173             if (idTranslationMap.containsKey(speciesReferenceTaxonId)) {
174 
175                 Integer newSpeciesReferenceTaxonId = idTranslationMap.get(speciesReferenceTaxonId);
176                 speciesProtocol.setSpeciesReferenceTaxonId(newSpeciesReferenceTaxonId);
177 
178                 if (log.isInfoEnabled()) {
179                     log.info("Translate reference taxon from " + speciesReferenceTaxonId + " to " + newSpeciesReferenceTaxonId);
180                 }
181 
182             }
183         }
184     }
185 
186     protected static TuttiProtocol migrateProtocol(File file) {
187         try {
188             //try to load a v3
189             TuttiProtocol3 tuttiProtocol3 = fromFileV3(file);
190 
191             return fromTuttiProtocol3(tuttiProtocol3);
192 
193         } catch (Exception ee) {
194             if (log.isErrorEnabled()) {
195                 log.error("Error on loading a v3", ee);
196             }
197             try {
198                 //try to load a v2
199                 TuttiProtocol2 tuttiProtocol2 = fromFileV2(file);
200 
201                 TuttiProtocol3 tuttiProtocol3 = fromTuttiProtocol2(tuttiProtocol2);
202 
203                 return fromTuttiProtocol3(tuttiProtocol3);
204 
205             } catch (Exception ee2) {
206                 if (log.isErrorEnabled()) {
207                     log.error("Error on loading a v2", ee2);
208                 }
209                 // try to load a v1
210                 TuttiProtocol1 tuttiProtocol1 = fromFileV1(file);
211 
212                 TuttiProtocol2 tuttiProtocol2 = fromTuttiProtocol1(tuttiProtocol1);
213 
214                 TuttiProtocol3 tuttiProtocol3 = fromTuttiProtocol2(tuttiProtocol2);
215 
216                 return fromTuttiProtocol3(tuttiProtocol3);
217             }
218         }
219     }
220 
221     public static TuttiProtocol1 fromFileV1(File file) {
222 
223         Reader fileReader = null;
224         try {
225             fileReader = Files.newReader(file, StandardCharsets.UTF_8);
226             YamlReader reader = new YamlReader(fileReader, createConfigV1());
227             TuttiProtocol1 result = reader.read(TuttiProtocolBean1.class);
228             fileReader.close();
229             return result;
230         } catch (Exception e) {
231             throw new ApplicationTechnicalException(t("tutti.persistence.protocol.fromFile.error", file), e);
232         } finally {
233             IOUtils.closeQuietly(fileReader);
234         }
235     }
236 
237     public static TuttiProtocol2 fromFileV2(File file) {
238 
239         Reader fileReader = null;
240         try {
241             fileReader = Files.newReader(file, StandardCharsets.UTF_8);
242             YamlReader reader = new YamlReader(fileReader, createConfigV2());
243             TuttiProtocol2 result = reader.read(TuttiProtocolBean2.class);
244             fileReader.close();
245             return result;
246         } catch (Exception e) {
247             throw new ApplicationTechnicalException(t("tutti.persistence.protocol.fromFile.error", file), e);
248         } finally {
249             IOUtils.closeQuietly(fileReader);
250         }
251     }
252 
253     public static TuttiProtocol3 fromFileV3(File file) {
254 
255         Reader fileReader = null;
256         try {
257             fileReader = Files.newReader(file, StandardCharsets.UTF_8);
258             YamlReader reader = new YamlReader(fileReader, createConfigV3());
259             TuttiProtocol3 result = reader.read(TuttiProtocolBean3.class);
260             fileReader.close();
261             return result;
262         } catch (Exception e) {
263             throw new ApplicationTechnicalException(t("tutti.persistence.protocol.fromFile.error", file), e);
264         } finally {
265             IOUtils.closeQuietly(fileReader);
266         }
267     }
268 
269     public static void checkSampleCategories(SampleCategoryModel sampleCategoryModel,
270                                              TuttiProtocol protocol,
271                                              Set<Integer> badCategories) {
272 
273         if (CollectionUtils.isNotEmpty(protocol.getSpecies())) {
274             for (SpeciesProtocol entry : protocol.getSpecies()) {
275                 List<Integer> mandatorySampleCategoryId = entry.getMandatorySampleCategoryId();
276                 for (Integer categoryId : mandatorySampleCategoryId) {
277                     if (!sampleCategoryModel.containsCategoryId(categoryId)) {
278                         badCategories.add(categoryId);
279                     }
280                 }
281             }
282         }
283         if (CollectionUtils.isNotEmpty(protocol.getBenthos())) {
284             for (SpeciesProtocol entry : protocol.getBenthos()) {
285                 List<Integer> mandatorySampleCategoryId = entry.getMandatorySampleCategoryId();
286                 for (Integer categoryId : mandatorySampleCategoryId) {
287                     if (!sampleCategoryModel.containsCategoryId(categoryId)) {
288                         badCategories.add(categoryId);
289                     }
290                 }
291             }
292         }
293     }
294 
295     public static void removeBadCategories(SampleCategoryModel sampleCategoryModel, TuttiProtocol protocol) {
296         List<Integer> samplingOrder = sampleCategoryModel.getSamplingOrder();
297         if (!protocol.isSpeciesEmpty()) {
298 
299             for (SpeciesProtocol entry : protocol.getSpecies()) {
300                 entry.getMandatorySampleCategoryId().retainAll(samplingOrder);
301             }
302         }
303 
304         if (!protocol.isBenthosEmpty()) {
305 
306             for (SpeciesProtocol entry : protocol.getBenthos()) {
307                 entry.getMandatorySampleCategoryId().retainAll(samplingOrder);
308             }
309         }
310     }
311 
312     public static String getBadCategoriesMessage(Set<Integer> badCategories,
313                                                  Decorator<Caracteristic> decorator,
314                                                  TuttiPersistence persistenceService) {
315         List<String> badCategoriesStr = new ArrayList<>();
316 
317         for (Integer id : badCategories) {
318             String caracteristicStr;
319             try {
320                 Caracteristic caracteristic = persistenceService.getCaracteristic(id);
321                 caracteristicStr = decorator.toString(caracteristic);
322             } catch (NullPointerException e) {
323                 if (log.isWarnEnabled()) {
324                     log.warn("Could not find caracteristic with id: " + id);
325                 }
326                 caracteristicStr = t("tutti.persistence.error.caracteristic.notFound");
327             }
328             badCategoriesStr.add("<li>" + id + " : " + caracteristicStr + "</li>");
329         }
330         return t("tutti.persistence.error.protocol.categories.not.compatible", Joiner.on("").join(badCategoriesStr));
331     }
332 
333     protected static TuttiProtocol2 fromTuttiProtocol1(TuttiProtocol1 tuttiProtocol1) {
334         TuttiProtocol2 result = new TuttiProtocolBean2();
335         Binder<TuttiProtocol1, TuttiProtocol2> binder = BinderFactory.newBinder(TuttiProtocol1.class, TuttiProtocol2.class);
336         binder.copy(tuttiProtocol1, result);
337         if (!tuttiProtocol1.isSpeciesEmpty()) {
338             result.setSpecies(new ArrayList<>());
339             Binder<SpeciesProtocol1, SpeciesProtocol> binderSpecies = BinderFactory.newBinder(SpeciesProtocol1.class, SpeciesProtocol.class);
340             for (SpeciesProtocol1 speciesProtocol1 : tuttiProtocol1.getSpecies()) {
341                 SpeciesProtocol row = SpeciesProtocols.newSpeciesProtocol();
342                 row.setMandatorySampleCategoryId(new ArrayList<>());
343                 binderSpecies.copy(speciesProtocol1, row);
344                 if (speciesProtocol1.isAgeEnabled()) {
345                     row.addMandatorySampleCategoryId(PmfmId.AGE.getValue());
346                 }
347                 if (speciesProtocol1.isSizeEnabled()) {
348                     row.addMandatorySampleCategoryId(PmfmId.SIZE_CATEGORY.getValue());
349                 }
350                 if (speciesProtocol1.isMaturityEnabled()) {
351                     row.addMandatorySampleCategoryId(PmfmId.MATURITY.getValue());
352                 }
353                 if (speciesProtocol1.isSexEnabled()) {
354                     row.addMandatorySampleCategoryId(PmfmId.SEX.getValue());
355                 }
356                 result.addSpecies(row);
357             }
358         }
359         if (!tuttiProtocol1.isBenthosEmpty()) {
360             result.setBenthos(new ArrayList<>());
361             Binder<SpeciesProtocol1, SpeciesProtocol> binderSpecies = BinderFactory.newBinder(SpeciesProtocol1.class, SpeciesProtocol.class);
362             for (SpeciesProtocol1 speciesProtocol1 : tuttiProtocol1.getBenthos()) {
363                 SpeciesProtocol row = SpeciesProtocols.newSpeciesProtocol();
364                 row.setMandatorySampleCategoryId(new ArrayList<>());
365                 binderSpecies.copy(speciesProtocol1, row);
366                 if (speciesProtocol1.isAgeEnabled()) {
367                     row.addMandatorySampleCategoryId(PmfmId.AGE.getValue());
368                 }
369                 if (speciesProtocol1.isSizeEnabled()) {
370                     row.addMandatorySampleCategoryId(PmfmId.SIZE_CATEGORY.getValue());
371                 }
372                 if (speciesProtocol1.isMaturityEnabled()) {
373                     row.addMandatorySampleCategoryId(PmfmId.MATURITY.getValue());
374                 }
375                 if (speciesProtocol1.isSexEnabled()) {
376                     row.addMandatorySampleCategoryId(PmfmId.SEX.getValue());
377                 }
378                 result.addBenthos(row);
379             }
380         }
381         return result;
382     }
383 
384     protected static TuttiProtocol3 fromTuttiProtocol2(TuttiProtocol2 tuttiProtocol2) {
385         TuttiProtocol3 result = new TuttiProtocolBean3();
386         Binder<TuttiProtocol2, TuttiProtocol3> binder = BinderFactory.newBinder(TuttiProtocol2.class, TuttiProtocol3.class);
387         binder.copy(tuttiProtocol2, result);
388 
389         List<CaracteristicMappingRow> caracteristicMappingRows = new ArrayList<>();
390         for (String id : tuttiProtocol2.getGearUseFeaturePmfmId()) {
391             CaracteristicMappingRow row = new CaracteristicMappingRowBean();
392             row.setPmfmId(id);
393             row.setTab(CaracteristicType.GEAR_USE_FEATURE.name());
394             caracteristicMappingRows.add(row);
395         }
396         for (String id : tuttiProtocol2.getVesselUseFeaturePmfmId()) {
397             CaracteristicMappingRow row = new CaracteristicMappingRowBean();
398             row.setPmfmId(id);
399             row.setTab(CaracteristicType.VESSEL_USE_FEATURE.name());
400             caracteristicMappingRows.add(row);
401         }
402         result.setCaracteristicMapping(caracteristicMappingRows);
403 
404         //TODO finish
405 
406         return result;
407     }
408 
409     protected static TuttiProtocol fromTuttiProtocol3(TuttiProtocol3 tuttiProtocol3) {
410         TuttiProtocol result = newTuttiProtocol();
411         Binder<TuttiProtocol3, TuttiProtocol> binder = BinderFactory.newBinder(TuttiProtocol3.class, TuttiProtocol.class);
412         binder.copy(tuttiProtocol3, result);
413 
414         if (!tuttiProtocol3.isSpeciesEmpty()) {
415             result.setSpecies(new ArrayList<>());
416             Binder<SpeciesProtocol3, SpeciesProtocol> binderSpecies = BinderFactory.newBinder(SpeciesProtocol3.class, SpeciesProtocol.class);
417             for (SpeciesProtocol3 speciesProtocol3 : tuttiProtocol3.getSpecies()) {
418                 SpeciesProtocol row = SpeciesProtocols.newSpeciesProtocol();
419                 row.setMandatorySampleCategoryId(new ArrayList<>());
420                 binderSpecies.copy(speciesProtocol3, row);
421                 result.addSpecies(row);
422             }
423         }
424         if (!tuttiProtocol3.isBenthosEmpty()) {
425             result.setBenthos(new ArrayList<>());
426             Binder<SpeciesProtocol3, SpeciesProtocol> binderSpecies = BinderFactory.newBinder(SpeciesProtocol3.class, SpeciesProtocol.class);
427             for (SpeciesProtocol3 speciesProtocol3 : tuttiProtocol3.getBenthos()) {
428                 SpeciesProtocol row = SpeciesProtocols.newSpeciesProtocol();
429                 row.setMandatorySampleCategoryId(new ArrayList<>());
430                 binderSpecies.copy(speciesProtocol3, row);
431                 result.addBenthos(row);
432             }
433         }
434 
435         return result;
436     }
437 
438     protected static YamlConfig createConfig() {
439         YamlConfig result = new YamlConfig();
440         result.setClassTag(SpeciesProtocol.class.getSimpleName(),
441                            SpeciesProtocols.typeOfSpeciesProtocol());
442         result.setClassTag(CalcifiedPiecesSamplingDefinition.class.getSimpleName(),
443                            CalcifiedPiecesSamplingDefinitions.typeOfCalcifiedPiecesSamplingDefinition());
444         result.setClassTag(CaracteristicMappingRow.class.getSimpleName(),
445                            CaracteristicMappingRows.typeOfCaracteristicMappingRow());
446         result.setClassTag(Zone.class.getSimpleName(), Zones.typeOfZone());
447         result.setClassTag(Strata.class.getSimpleName(), Stratas.typeOfStrata());
448         result.setClassTag(SubStrata.class.getSimpleName(), SubStratas.typeOfSubStrata());
449         result.setClassTag(MaturityCaracteristic.class.getSimpleName(), MaturityCaracteristics.typeOfMaturityCaracteristic());
450         result.writeConfig.setAlwaysWriteClassname(false);
451         result.writeConfig.setWriteRootTags(false);
452         return result;
453     }
454 
455     protected static YamlConfig createConfigV1() {
456         YamlConfig result = new YamlConfig();
457         result.setClassTag(SpeciesProtocol.class.getSimpleName(),
458                            SpeciesProtocolBean1.class);
459         result.writeConfig.setAlwaysWriteClassname(false);
460         result.writeConfig.setWriteRootTags(false);
461         return result;
462     }
463 
464     protected static YamlConfig createConfigV2() {
465         YamlConfig result = new YamlConfig();
466         result.setClassTag(SpeciesProtocol.class.getSimpleName(),
467                            SpeciesProtocols.typeOfSpeciesProtocol());
468         result.writeConfig.setAlwaysWriteClassname(false);
469         result.writeConfig.setWriteRootTags(false);
470         return result;
471     }
472 
473     protected static YamlConfig createConfigV3() {
474         YamlConfig result = new YamlConfig();
475         result.setClassTag(SpeciesProtocol.class.getSimpleName(), SpeciesProtocolBean3.class);
476         result.setClassTag(CaracteristicMappingRow.class.getSimpleName(),
477                            CaracteristicMappingRows.typeOfCaracteristicMappingRow());
478         result.setClassTag(Zone.class.getSimpleName(), Zones.typeOfZone());
479         result.setClassTag(Strata.class.getSimpleName(), Stratas.typeOfStrata());
480         result.setClassTag(SubStrata.class.getSimpleName(), SubStratas.typeOfSubStrata());
481         result.setClassTag(CalcifiedPiecesSamplingDefinition.class.getSimpleName(),
482                            CalcifiedPiecesSamplingDefinitions.typeOfCalcifiedPiecesSamplingDefinition());
483         result.writeConfig.setAlwaysWriteClassname(false);
484         result.writeConfig.setWriteRootTags(false);
485         return result;
486     }
487 
488     public static SpeciesProtocol getSpeciesOrBenthosProtocol(TuttiProtocol protocol, Integer speciesReferenceTaxonId) {
489         SpeciesProtocol speciesProtocol = getSpeciesProtocol(protocol, speciesReferenceTaxonId);
490         if (speciesProtocol == null) {
491             speciesProtocol = getBenthosProtocol(protocol, speciesReferenceTaxonId);
492         }
493         return speciesProtocol;
494     }
495 
496     public static boolean removeSpeciesOrBenthosProtocol(TuttiProtocol protocol, Integer speciesReferenceTaxonId) {
497 
498         boolean wasRemoved = false;
499 
500         SpeciesProtocol speciesProtocol = getSpeciesProtocol(protocol, speciesReferenceTaxonId);
501         if (speciesProtocol != null) {
502 
503             if (log.isInfoEnabled()) {
504                 log.info("Remove referenceTaxonId " + speciesReferenceTaxonId + " from species protocol " + speciesProtocol.getSpeciesSurveyCode());
505             }
506             protocol.getSpecies().remove(speciesProtocol);
507             wasRemoved = true;
508 
509         } else {
510 
511             SpeciesProtocol benthosProtocol = getBenthosProtocol(protocol, speciesReferenceTaxonId);
512 
513             if (benthosProtocol != null) {
514 
515                 if (log.isInfoEnabled()) {
516                     log.info("Remove referenceTaxonId " + speciesReferenceTaxonId + " from benthos protocol " + benthosProtocol.getSpeciesSurveyCode());
517                 }
518                 protocol.getBenthos().remove(benthosProtocol);
519                 wasRemoved = true;
520 
521             }
522 
523         }
524 
525         return wasRemoved;
526 
527     }
528 
529     /**
530      * Return the species Protocol corresponding to the species of the given protocol.
531      *
532      * @param protocol                protocol to scan
533      * @param speciesReferenceTaxonId species referenceTaxonId filter
534      * @return the species protocol for the given species
535      * @since 2.5
536      */
537     public static SpeciesProtocol getSpeciesProtocol(TuttiProtocol protocol, Integer speciesReferenceTaxonId) {
538         return getSpeciesProtocol(speciesReferenceTaxonId, protocol.getSpecies());
539     }
540 
541     /**
542      * Return the benthos Protocol corresponding to the species of the given protocol.
543      *
544      * @param protocol                protocol to scan
545      * @param speciesReferenceTaxonId species referenceTaxonId filter
546      * @return the benthos protocol for the given species
547      * @since 3.9
548      */
549     public static SpeciesProtocol getBenthosProtocol(TuttiProtocol protocol, Integer speciesReferenceTaxonId) {
550         return getSpeciesProtocol(speciesReferenceTaxonId, protocol.getBenthos());
551     }
552 
553     /**
554      * Return the speciesProtocol row corresponding to the species of the species protocols.
555      *
556      * @param speciesProtocols species protocols to scan
557      * @param species          species filter
558      * @return the species protocol for the given species
559      */
560     public static SpeciesProtocol getSpeciesProtocol(Species species,
561                                                      List<SpeciesProtocol> speciesProtocols) {
562 
563         return getSpeciesProtocol(species.getReferenceTaxonId(), speciesProtocols);
564 
565     }
566 
567     /**
568      * Return the speciesProtocol row corresponding to the species of the species protocols.
569      *
570      * @param speciesProtocols        species protocols to scan
571      * @param speciesReferenceTaxonId speciesReferenceTaxonId filter
572      * @return the species protocol for the given species
573      */
574     public static SpeciesProtocol getSpeciesProtocol(Integer speciesReferenceTaxonId,
575                                                      List<SpeciesProtocol> speciesProtocols) {
576         for (SpeciesProtocol speciesProtocol : speciesProtocols) {
577             if (speciesReferenceTaxonId.equals(speciesProtocol.getSpeciesReferenceTaxonId())) {
578                 return speciesProtocol;
579             }
580         }
581         return null;
582     }
583 
584     public static CaracteristicMappingRow caracteristicMappingRow(String pmfmId, CaracteristicType tab) {
585         CaracteristicMappingRow caracteristicMappingRow = new CaracteristicMappingRowBean();
586         caracteristicMappingRow.setPmfmId(pmfmId);
587         caracteristicMappingRow.setTab(tab.name());
588         return caracteristicMappingRow;
589     }
590 
591     public static List<String> gearUseFeaturePmfmIds(TuttiProtocol protocol) {
592         return pmfmIdsForCaracteristicType(protocol, CaracteristicType.GEAR_USE_FEATURE);
593     }
594 
595     public static List<String> vesselUseFeaturePmfmIds(TuttiProtocol protocol) {
596         return pmfmIdsForCaracteristicType(protocol, CaracteristicType.VESSEL_USE_FEATURE);
597     }
598 
599     public static List<String> pmfmIdsForCaracteristicType(TuttiProtocol protocol, final CaracteristicType type) {
600         Preconditions.checkNotNull(protocol);
601         Preconditions.checkNotNull(type);
602 
603         List<CaracteristicMappingRow> caracteristicMapping = protocol.getCaracteristicMapping();
604         Collection<CaracteristicMappingRow> gearUseFeatureCaracteristics =
605                 Collections2.filter(caracteristicMapping, new CaracteristicMappingRows.TabPredicate(type));
606 
607         Collection<String> pmfmIds = Collections2.transform(gearUseFeatureCaracteristics, CaracteristicMappingRows.GET_PMFM_ID);
608         return new ArrayList<>(pmfmIds);
609     }
610 
611     public static String getFirstAvailableName(String name, List<String> allProtocolNames) {
612 
613         String baseName = name + "-";
614         int index = 0;
615         do {
616 
617             name = baseName + (index++);
618 
619         } while (allProtocolNames.contains(name));
620 
621         return name;
622 
623     }
624 
625     public static Map<Integer, SpeciesProtocol> toSpeciesProtocolMap(TuttiProtocol protocol) {
626         final Map<Integer, SpeciesProtocol> result = Maps.newHashMap();
627         for (SpeciesProtocol sp : protocol.getSpecies()) {
628             result.put(sp.getSpeciesReferenceTaxonId(), sp);
629         }
630         return result;
631     }
632 
633     public static Map<Integer, SpeciesProtocol> toBenthosProtocolMap(TuttiProtocol protocol) {
634         final Map<Integer, SpeciesProtocol> result = Maps.newHashMap();
635         for (SpeciesProtocol sp : protocol.getBenthos()) {
636             result.put(sp.getSpeciesReferenceTaxonId(), sp);
637         }
638         return result;
639     }
640 
641     public static Map<Integer, String> detectMissingSpecies(TuttiProtocol protocol, List<Species> species) {
642 
643         return TuttiProtocols.detectMissingSpecies(species, toSpeciesProtocolMap(protocol));
644 
645     }
646 
647     public static Map<Integer, String> detectMissingBenthos(TuttiProtocol protocol, List<Species> species) {
648 
649         return TuttiProtocols.detectMissingSpecies(species, toBenthosProtocolMap(protocol));
650 
651     }
652 
653     public static void removeBadSpecies(TuttiProtocol protocol, Map<Integer, String> speciesProtocolNotFound) {
654 
655         if (!speciesProtocolNotFound.isEmpty()) {
656 
657             Iterator<SpeciesProtocol> iterator = protocol.getSpecies().iterator();
658             while (iterator.hasNext()) {
659                 SpeciesProtocol speciesProtocol = iterator.next();
660                 Integer taxonId = speciesProtocol.getSpeciesReferenceTaxonId();
661                 boolean containsSpecies = speciesProtocolNotFound.containsKey(taxonId);
662                 if (containsSpecies) {
663                     if (log.isWarnEnabled()) {
664                         log.warn("Could not find protocol species " + taxonId + " (" + speciesProtocol.getSpeciesSurveyCode() + ") in referential.");
665                     }
666                     iterator.remove();
667                 }
668             }
669 
670         }
671 
672     }
673 
674     public static void removeBadBenthos(TuttiProtocol protocol, Map<Integer, String> benthosProtocolNotFound) {
675 
676         if (!benthosProtocolNotFound.isEmpty()) {
677 
678             Iterator<SpeciesProtocol> iterator = protocol.getBenthos().iterator();
679             while (iterator.hasNext()) {
680                 SpeciesProtocol speciesProtocol = iterator.next();
681                 Integer taxonId = speciesProtocol.getSpeciesReferenceTaxonId();
682                 boolean containsSpecies = benthosProtocolNotFound.containsKey(taxonId);
683                 if (containsSpecies) {
684                     if (log.isWarnEnabled()) {
685                         log.warn("Could not find protocol benthos " + taxonId + " (" + speciesProtocol.getSpeciesSurveyCode() + ") in referential.");
686                     }
687                     iterator.remove();
688                 }
689             }
690 
691         }
692 
693     }
694 
695     protected static Map<Integer, String> detectMissingSpecies(List<Species> species, Map<Integer, SpeciesProtocol> speciesProtocolMap) {
696 
697         Multimap<String, Species> speciesByRefTaxonId = Speciess.splitByReferenceTaxonId(species);
698         Map<Integer, String> badSpecies = new TreeMap<>();
699         for (SpeciesProtocol speciesProtocol : speciesProtocolMap.values()) {
700             Integer referenceTaxonId = speciesProtocol.getSpeciesReferenceTaxonId();
701             if (referenceTaxonId != null && !speciesByRefTaxonId.containsKey(String.valueOf(referenceTaxonId))) {
702                 badSpecies.put(referenceTaxonId, speciesProtocol.getSpeciesSurveyCode());
703             }
704         }
705         return Collections.unmodifiableMap(badSpecies);
706 
707     }
708 
709     public static String getBadSpeciesMessage(Map<Integer, String> speciesProtocolNotFound) {
710 
711         List<String> badCategoriesStr = new ArrayList<>();
712         for (Map.Entry<Integer, String> id : speciesProtocolNotFound.entrySet()) {
713             badCategoriesStr.add("<li>" + id.getKey() + " : " + (id.getValue() == null ? "" : id.getValue()) + "</li>");
714         }
715         return t("tutti.persistence.error.protocol.species.not.found", Joiner.on("").join(badCategoriesStr));
716 
717     }
718 
719     public static String getBadBenthosMessage(Map<Integer, String> benthosProtocolNotFound) {
720 
721         List<String> badCategoriesStr = new ArrayList<>();
722         for (Map.Entry<Integer, String> id : benthosProtocolNotFound.entrySet()) {
723             badCategoriesStr.add("<li>" + id.getKey() + " : " + (id.getValue() == null ? "" : id.getValue()) + "</li>");
724         }
725         return t("tutti.persistence.error.protocol.benthos.not.found", Joiner.on("").join(badCategoriesStr));
726 
727     }
728 
729     public static boolean matchProgramId(TuttiProtocol protocol, String programId) {
730         Preconditions.checkNotNull(protocol, "Protocol can't be null.");
731         return Objects.equals(programId, protocol.getProgramId());
732     }
733 
734 }