View Javadoc
1   package fr.ifremer.tutti.service.pupitri;
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.collect.ImmutableSet;
26  import fr.ifremer.tutti.persistence.entities.referential.Species;
27  import org.apache.commons.lang3.builder.ToStringBuilder;
28  
29  import java.io.Serializable;
30  import java.util.HashSet;
31  import java.util.Set;
32  import java.util.TreeMap;
33  
34  /**
35   * Pour aggreger toutes les lignes lors d'un import pupitri ayant la même tuple (espece - sorted).
36   *
37   * @author Kevin Morin - kmorin@codelutin.com
38   * @since 1.2
39   */
40  public class PupitriSpeciesContext implements Serializable {
41  
42      private static final long serialVersionUID = 1L;
43  
44      private static final String MELAG_META_SPECIES = "MELA-NGE";
45  
46      private static final String MELAG_2_META_SPECIES = "MELANGE";
47  
48      /**
49       * All MELAG species.
50       *
51       * @since 3.7
52       */
53      private static final Set<String> MELAG_SPECIES = ImmutableSet.of(MELAG_META_SPECIES, MELAG_2_META_SPECIES);
54  
55      private static final Set<Signs> DEFAULT_SIGNS = ImmutableSet.of(Signs.DEFAULT);
56  
57      private static final Set<Signs> UNSORTED_SIGNS = ImmutableSet.of(Signs.UNSORTED);
58  
59      private static final Set<Signs> SEX_SIGNS = ImmutableSet.of(Signs.DEFAULT, Signs.MALE, Signs.FEMALE);
60  
61      private static final Set<Signs> SIZE_SIGNS = ImmutableSet.of(Signs.SMALL, Signs.MEDIUM, Signs.BIG);
62  
63      /**
64       * Espece du lot.
65       */
66      protected final Species species;
67  
68      /**
69       * Is the species is a sorted (VRAC) or unsorted (HORS-VRAC)?
70       */
71      protected final boolean sorted;
72  
73      /**
74       * If the species was involved in the melag, fill this flag.
75       *
76       * If species has also a {@link Signs#BIG} weight, then the melga weight is imported as a {@link Signs#SMALL} batch.
77       * Otherwise using the {@link Signs#DEFAULT} sign.
78       *
79       * We will look after this sign while crzating species batch to import.
80       */
81      protected Signs melagElevatedSign;
82  
83      /**
84       * Tous les signes utilisés par cette espèce/sorted lors de l'import.
85       *
86       * @since 3.11
87       */
88      protected final TreeMap<Signs, PupitriSignContext> signs;
89  
90      /**
91       * Pour créer les lots fils manquants (see http://forge.codelutin.com/issues/6116)
92       * @since 4.3
93       */
94      protected final boolean createMissingSigns;
95  
96      public PupitriSpeciesContext(Species species, boolean createMissingSigns, boolean sorted) {
97          this.species = species;
98          this.sorted = sorted;
99          this.signs = new TreeMap<>();
100         this.createMissingSigns = createMissingSigns;
101     }
102 
103     public Species getSpecies() {
104         return species;
105     }
106 
107     public boolean isSorted() {
108         return sorted;
109     }
110 
111     public boolean isAddMelagComment(Signs sign) {
112         return melagElevatedSign != null && melagElevatedSign.equals(sign);
113     }
114 
115     public boolean isForMelag() {
116         return signs.containsKey(Signs.MELAG);
117     }
118 
119     public boolean isMelagMetaSpecies() {
120 
121         return MELAG_SPECIES.contains(species.getSurveyCode());
122 
123     }
124 
125     public boolean containsSign(Signs signs) {
126         return this.signs.containsKey(signs);
127     }
128 
129     public Set<Signs> getSigns() {
130         return ImmutableSet.copyOf(signs.keySet());
131     }
132 
133     public float getWeight(Signs signs) {
134         PupitriSignContext signContext = getSignContext(signs);
135         return signContext.getWeight();
136 
137     }
138 
139     public float getTotalWeight() {
140 
141         float totalWeight = 0f;
142         for (PupitriSignContext signContext : signs.values()) {
143             float weight = signContext.getWeight();
144             totalWeight += weight;
145         }
146 
147         return totalWeight;
148 
149     }
150 
151     public void addToSignContext(Signs sign, BoxType boxType, Float weight) {
152 
153         PupitriSignContext signContext = getOrCreateSignContext(sign);
154         signContext.addWeight(weight);
155         switch (boxType) {
156             case SMALL:
157                 signContext.incrementNbSmallBox();
158                 break;
159             case BIG:
160                 signContext.incrementNbBigBox();
161                 break;
162         }
163 
164         // cf #6116
165         if (createMissingSigns) {
166             switch (sign) {
167                 case MALE:
168                     getOrCreateSignContext(Signs.FEMALE);
169                     getOrCreateSignContext(Signs.DEFAULT);
170                     break;
171                 case FEMALE:
172                     getOrCreateSignContext(Signs.MALE);
173                     getOrCreateSignContext(Signs.DEFAULT);
174                     break;
175 
176                 case SMALL:
177                     getOrCreateSignContext(Signs.BIG);
178                     break;
179                 case BIG:
180                     getOrCreateSignContext(Signs.SMALL);
181                     break;
182             }
183         }
184     }
185 
186     public void setMelagElevatedWeight(Signs melagElevatedSign, Float weight) {
187 
188         PupitriSignContext melagContext = getSignContext(Signs.MELAG);
189         PupitriSignContext pupitriSignContext = getOrCreateSignContext(melagElevatedSign);
190         pupitriSignContext.addWeight(weight);
191         //FIXME Check this???
192         pupitriSignContext.addNbBoxs(melagContext);
193 
194         signs.remove(Signs.MELAG);
195         this.melagElevatedSign = melagElevatedSign;
196 
197     }
198 
199     public void moveMelagToDefaultSign() {
200 
201         PupitriSignContext melagContext = getSignContext(Signs.MELAG);
202 
203         PupitriSignContext defaultSignContext = getOrCreateSignContext(Signs.DEFAULT);
204         defaultSignContext.addWeight(melagContext.getWeight());
205         //FIXME Check this???
206         defaultSignContext.addNbBoxs(melagContext);
207         signs.remove(Signs.MELAG);
208 
209     }
210 
211     /**
212      * Check that the given species catch can be split.
213      * For the moment accept for a same catch :
214      * <ul>
215      * <li>Signs.DEFAULT, Signs.UNSORTED, Signs.MALE, Signs.FEMALE</li>
216      * <li>Signs.SMALL, Signs.MEDIUM, Signs.BIG</li>
217      * </ul>
218      * See http://forge.codelutin.com/issues/3898
219      *
220      * @return {@code true} if species catch is safe, {@code false} otherwise.
221      * @since 3.0-rc-2
222      */
223     public boolean isSplitSpecies() {
224 
225         Set<Signs> allSigns = new HashSet<>(this.signs.keySet());
226 
227         boolean result;
228 
229         if (DEFAULT_SIGNS.equals(allSigns)) {
230 
231             // only a default sign, no split
232             result = false;
233         } else if (UNSORTED_SIGNS.equals(allSigns)) {
234 
235             // only a unsorted sign, no split
236             result = false;
237         } else {
238 
239             // remove all sex signs
240             boolean contains = allSigns.removeAll(SEX_SIGNS);
241             if (contains) {
242 
243                 // check there only sex signs
244                 result = allSigns.isEmpty();
245             } else {
246 
247                 // remove all size signs
248                 contains = allSigns.removeAll(SIZE_SIGNS);
249                 if (contains) {
250 
251                     // check there only size signs
252                     result = allSigns.isEmpty();
253                 } else {
254 
255                     // in all other cases, not a safe
256                     result = false;
257                 }
258             }
259         }
260         return result;
261     }
262 
263     @Override
264     public int hashCode() {
265         int speciesHashCode = species != null ? species.hashCode() : 0;
266         int sortedHashCode = sorted ? 0x55555555 : 0x2AAAAAAA;
267         return speciesHashCode ^ sortedHashCode;
268     }
269 
270     @Override
271     public boolean equals(Object obj) {
272         if (obj == null) {
273             return false;
274         }
275         if (getClass() != obj.getClass()) {
276             return false;
277         }
278         final PupitriSpeciesContext other = (PupitriSpeciesContext) obj;
279         if (this.species != other.species && (this.species == null || !this.species.equals(other.species))) {
280             return false;
281         }
282         if (this.sorted != other.sorted) {
283             return false;
284         }
285         return true;
286     }
287 
288     @Override
289     public String toString() {
290         return new ToStringBuilder(this)
291                 .append("species", species.getSurveyCode())
292                 .append("sorted", sorted)
293                 .append("signs", signs)
294                 .toString();
295     }
296 
297     PupitriSignContext getSignContext(Signs sign) {
298         return signs.get(sign);
299     }
300 
301     private PupitriSignContext getOrCreateSignContext(Signs sign) {
302 
303         PupitriSignContext signContext = getSignContext(sign);
304         if (signContext == null) {
305             signContext = new PupitriSignContext(sign);
306             signs.put(sign, signContext);
307         }
308         return signContext;
309     }
310 
311 }