View Javadoc
1   /*
2    * Licensed under the GPL License. You may not use this file except in compliance with the License.
3    * You may obtain a copy of the License at
4    *
5    *   https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
6    *
7    * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
8    * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
9    * PURPOSE.
10   */
11  package psiprobe.jsp;
12  
13  import jakarta.servlet.jsp.JspException;
14  import jakarta.servlet.jsp.tagext.BodyContent;
15  import jakarta.servlet.jsp.tagext.BodyTagSupport;
16  
17  import java.io.IOException;
18  import java.text.MessageFormat;
19  
20  /**
21   * The Class VisualScoreTag.
22   */
23  public class VisualScoreTag extends BodyTagSupport {
24  
25    /** The Constant serialVersionUID. */
26    private static final long serialVersionUID = -5653846466205838602L;
27  
28  
29    /** The Constant WHITE_LEFT_BORDER. */
30    private static final String WHITE_LEFT_BORDER = "a0";
31  
32    /** The Constant RED_LEFT_BORDER. */
33    private static final String RED_LEFT_BORDER = "a1";
34  
35    /** The Constant BLUE_LEFT_BORDER. */
36    private static final String BLUE_LEFT_BORDER = "a2";
37  
38    /** The Constant WHITE_RIGHT_BORDER. */
39    private static final String WHITE_RIGHT_BORDER = "b0";
40  
41    /** The Constant RED_RIGHT_BORDER. */
42    private static final String RED_RIGHT_BORDER = "b1";
43  
44    /** The Constant BLUE_RIGHT_BORDER. */
45    private static final String BLUE_RIGHT_BORDER = "b2";
46  
47    /** Red value. */
48    private double value = 0;
49  
50    /** Blue value. */
51    private double value2 = 0;
52  
53    /** The min value. */
54    private double minValue = 0;
55  
56    /** The max value. */
57    private double maxValue = 100;
58  
59    /**
60     * Number of parts in one block.<br>
61     * It always must be 5 to match the 5 different gifs available at
62     * /src/main/webapp/css/classic/gifs
63     */
64    private int partialBlocks = 1;
65  
66    /**
67     * Total number of blocks.<br>
68     * fullBlocks + 2 img elements will be added to the page.<br>
69     * The plus 2 is due the left and right border.
70     */
71    private int fullBlocks = 5;
72  
73    /** The show empty blocks. */
74    private boolean showEmptyBlocks;
75  
76    /** The show a. */
77    private boolean showA;
78  
79    /** The show b. */
80    private boolean showB;
81  
82    @Override
83    public int doAfterBody() throws JspException {
84      try (BodyContent bc = getBodyContent()) {
85        String body = bc.getString().trim();
86  
87        String buf = calculateSuffix(body);
88  
89        bc.getEnclosingWriter().print(buf);
90      } catch (IOException e) {
91        throw new JspException("Exception while writing to client", e);
92      }
93  
94      return SKIP_BODY;
95    }
96  
97    /**
98     * Calculate suffix.
99     *
100    * @param body the body
101    *
102    * @return the string buffer
103    */
104   String calculateSuffix(String body) {
105     if (value < minValue) {
106       value = minValue;
107     }
108     if (value > maxValue) {
109       value = maxValue;
110     }
111     if (value + value2 < minValue || value2 < 0) {
112       value2 = 0;
113     }
114     if (value + value2 > maxValue) {
115       value2 = maxValue - value;
116     }
117 
118     double unitSize = (maxValue - minValue) / (fullBlocks * partialBlocks);
119     double blockWidth = unitSize * partialBlocks;
120 
121     int redWhole = (int) Math.floor(value / blockWidth);
122     int redPart = (int) Math.floor((value - redWhole * blockWidth) / unitSize);
123     int bluePart1 =
124         redPart > 0 ? Math.min((int) Math.floor(value2 / unitSize), partialBlocks - redPart) : 0;
125     int blueWhole = (int) Math.max(0, Math.ceil(value2 / blockWidth) - (redPart > 0 ? 1 : 0));
126     int bluePart2 =
127         (int) Math.floor((value2 - blueWhole * blockWidth - bluePart1 * unitSize) / unitSize);
128 
129     StringBuilder buf = new StringBuilder();
130 
131     // Beginning
132     if (showA) {
133       String format = WHITE_LEFT_BORDER;
134       if (redWhole > 0 || redPart > 0) {
135         format = RED_LEFT_BORDER;
136       } else if (bluePart1 == 0 && (blueWhole > 0 || bluePart2 > 0)) {
137 
138         format = BLUE_LEFT_BORDER;
139       }
140       buf.append(MessageFormat.format(body, format));
141     }
142 
143     // Full red blocks
144     String fullRedBody = MessageFormat.format(body, partialBlocks + "+0");
145     for (int i = 0; i < redWhole; i++) {
146       buf.append(fullRedBody);
147     }
148 
149     // Mixed red/blue block (mid-block transition)
150     if (redPart > 0) {
151       String partialBody = MessageFormat.format(body, redPart + "+" + bluePart1);
152       buf.append(partialBody);
153     }
154 
155     // Full blue blocks
156     String fullBlueBody = MessageFormat.format(body, "0+" + partialBlocks);
157     for (int i = 0; i < blueWhole; i++) {
158       buf.append(fullBlueBody);
159     }
160 
161     // Partial blue block
162     if (bluePart2 > 0) {
163       String partialBody = MessageFormat.format(body, "0+" + bluePart2);
164       buf.append(partialBody);
165     }
166 
167     // Empty blocks
168     int emptyBlocks = showEmptyBlocks
169         ? fullBlocks - (redWhole + blueWhole + (redPart > 0 ? 1 : 0) + (bluePart2 > 0 ? 1 : 0))
170         : 0;
171     if (emptyBlocks > 0) {
172       String emptyBody = MessageFormat.format(body, "0+0");
173       for (int i = 0; i < emptyBlocks; i++) {
174         buf.append(emptyBody);
175       }
176     }
177 
178     // End
179     if (showB) {
180       String format = WHITE_RIGHT_BORDER;
181       if (redWhole == fullBlocks) {
182         format = RED_RIGHT_BORDER;
183       } else if (redWhole + (redPart + bluePart1 == partialBlocks ? 1 : 0)
184           + blueWhole == fullBlocks) {
185         format = BLUE_RIGHT_BORDER;
186       }
187       buf.append(MessageFormat.format(body, format));
188     }
189 
190     return buf.toString();
191   }
192 
193   /**
194    * Gets the value.
195    *
196    * @return the value
197    */
198   public double getValue() {
199     return value;
200   }
201 
202   /**
203    * Sets the value.
204    *
205    * @param value the new value
206    */
207   public void setValue(double value) {
208     this.value = value;
209   }
210 
211   /**
212    * Gets the value2.
213    *
214    * @return the value2
215    */
216   public double getValue2() {
217     return value2;
218   }
219 
220   /**
221    * Sets the value2.
222    *
223    * @param value2 the new value2
224    */
225   public void setValue2(double value2) {
226     this.value2 = value2;
227   }
228 
229   /**
230    * Gets the min value.
231    *
232    * @return the min value
233    */
234   public double getMinValue() {
235     return minValue;
236   }
237 
238   /**
239    * Sets the min value.
240    *
241    * @param minValue the new min value
242    */
243   public void setMinValue(double minValue) {
244     this.minValue = minValue;
245   }
246 
247   /**
248    * Gets the max value.
249    *
250    * @return the max value
251    */
252   public double getMaxValue() {
253     return maxValue;
254   }
255 
256   /**
257    * Sets the max value.
258    *
259    * @param maxValue the new max value
260    */
261   public void setMaxValue(double maxValue) {
262     this.maxValue = maxValue;
263   }
264 
265   /**
266    * Gets the partial blocks.
267    *
268    * @return the partial blocks
269    */
270   public int getPartialBlocks() {
271     return partialBlocks;
272   }
273 
274   /**
275    * Sets the partial blocks.
276    *
277    * @param partialBlocks the new partial blocks
278    */
279   public void setPartialBlocks(int partialBlocks) {
280     this.partialBlocks = partialBlocks;
281   }
282 
283   /**
284    * Gets the full blocks.
285    *
286    * @return the full blocks
287    */
288   public int getFullBlocks() {
289     return fullBlocks;
290   }
291 
292   /**
293    * Sets the full blocks.
294    *
295    * @param fullBlocks the new full blocks
296    */
297   public void setFullBlocks(int fullBlocks) {
298     this.fullBlocks = fullBlocks;
299   }
300 
301   /**
302    * Checks if is show empty blocks.
303    *
304    * @return true, if is show empty blocks
305    */
306   public boolean isShowEmptyBlocks() {
307     return showEmptyBlocks;
308   }
309 
310   /**
311    * Sets the show empty blocks.
312    *
313    * @param showEmptyBlocks the new show empty blocks
314    */
315   public void setShowEmptyBlocks(boolean showEmptyBlocks) {
316     this.showEmptyBlocks = showEmptyBlocks;
317   }
318 
319   /**
320    * Checks if is show a.
321    *
322    * @return true, if is show a
323    */
324   public boolean isShowA() {
325     return showA;
326   }
327 
328   /**
329    * Sets the show a.
330    *
331    * @param showA the new show a
332    */
333   public void setShowA(boolean showA) {
334     this.showA = showA;
335   }
336 
337   /**
338    * Checks if is show b.
339    *
340    * @return true, if is show b
341    */
342   public boolean isShowB() {
343     return showB;
344   }
345 
346   /**
347    * Sets the show b.
348    *
349    * @param showB the new show b
350    */
351   public void setShowB(boolean showB) {
352     this.showB = showB;
353   }
354 
355 }