View Javadoc
1   /*
2    * Prometheus: Application Framework
3    * Copyright 2012-2026. Tony Washer
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6    * use this file except in compliance with the License.  You may obtain a copy
7    * of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
14   * License for the specific language governing permissions and limitations under
15   * the License.
16   */
17  package io.github.tonywasher.joceanus.prometheus.service.sheet;
18  
19  import io.github.tonywasher.joceanus.oceanus.date.OceanusDate;
20  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusDecimal;
21  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusDecimalConstants;
22  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusMoney;
23  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusPrice;
24  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusRate;
25  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusRatio;
26  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusUnits;
27  
28  /**
29   * Excel/Oasis format string builder class.
30   */
31  public final class PrometheusSheetFormats {
32      /**
33       * Money accounting format width.
34       */
35      static final int ACCOUNTING_WIDTH = 10;
36  
37      /**
38       * Date width.
39       */
40      public static final int WIDTH_DATE = 11;
41  
42      /**
43       * Integer width.
44       */
45      public static final int WIDTH_INT = 8;
46  
47      /**
48       * Boolean width.
49       */
50      public static final int WIDTH_BOOL = 8;
51  
52      /**
53       * Money width.
54       */
55      public static final int WIDTH_MONEY = 13;
56  
57      /**
58       * Units width.
59       */
60      public static final int WIDTH_UNITS = 13;
61  
62      /**
63       * Rate width.
64       */
65      public static final int WIDTH_RATE = 13;
66  
67      /**
68       * Dilution width.
69       */
70      public static final int WIDTH_DILUTION = 13;
71  
72      /**
73       * Ratio width.
74       */
75      public static final int WIDTH_RATIO = 13;
76  
77      /**
78       * Price width.
79       */
80      public static final int WIDTH_PRICE = 15;
81  
82      /**
83       * String width.
84       */
85      public static final int WIDTH_STRING = 30;
86  
87      /**
88       * Font Height.
89       */
90      public static final int FONT_HEIGHT = 10;
91  
92      /**
93       * Value Font.
94       */
95      public static final String FONT_VALUE = "Arial";
96  
97      /**
98       * Numeric Font.
99       */
100     public static final String FONT_NUMERIC = "Courier";
101 
102     /**
103      * The digit placeholder.
104      */
105     private static final char CHAR_DIGIT = '#';
106 
107     /**
108      * The separator placeholder.
109      */
110     private static final char CHAR_SEP = ';';
111 
112     /**
113      * The Quote String.
114      */
115     private static final String STR_QUOTE = "\"";
116 
117     /**
118      * The Red indicating.
119      */
120     private static final String STR_RED = "[RED]";
121 
122     /**
123      * The Zero string.
124      */
125     private static final String STR_ZERO = "0";
126 
127     /**
128      * The Null string.
129      */
130     private static final String STR_NULL = "";
131 
132     /**
133      * Oasis date format.
134      */
135     static final String OASIS_DATE = "yyyy-MM-dd";
136 
137     /**
138      * Internal date format.
139      */
140     private static final String FORMAT_DATE = "dd-MMM-yy";
141 
142     /**
143      * Internal boolean format.
144      */
145     private static final String FORMAT_BOOLEAN = "\"TRUE\";;\"FALSE\"";
146 
147     /**
148      * Format current prefix.
149      */
150     private static final String FORMAT_CURR = "Curr";
151 
152     /**
153      * Prevent instantiation.
154      */
155     private PrometheusSheetFormats() {
156     }
157 
158     /**
159      * Obtain format for integer.
160      *
161      * @return the format
162      */
163     private static String getIntegerFormat() {
164         //* Return the format */
165         return String.valueOf(OceanusDecimalConstants.CHAR_ZERO)
166                 /* Return the format */;
167     }
168 
169     /**
170      * Obtain format for standard decimal.
171      *
172      * @param pValue the example decimal
173      * @return the format
174      */
175     private static String getStandardFormat(final OceanusDecimal pValue) {
176         /* Create String builder */
177         final StringBuilder myBuilder = new StringBuilder();
178 
179         /* Start with zero */
180         myBuilder.append(OceanusDecimalConstants.CHAR_ZERO);
181 
182         /* Determine scale */
183         final int myScale = pValue.scale();
184         if (myScale > 0) {
185             /* Append the decimal point */
186             myBuilder.append(OceanusDecimalConstants.STR_DEC);
187 
188             /* Append the decimal places */
189             myBuilder.repeat(String.valueOf(OceanusDecimalConstants.CHAR_ZERO), myScale);
190         }
191 
192         /* Return the format */
193         return myBuilder.toString();
194     }
195 
196     /**
197      * Obtain format for rate.
198      *
199      * @param pValue the example rate
200      * @return the format
201      */
202     private static String getRateFormat(final OceanusRate pValue) {
203         /* Create String builder */
204         final StringBuilder myBuilder = new StringBuilder();
205 
206         /* Start with zero */
207         myBuilder.append(OceanusDecimalConstants.CHAR_ZERO);
208 
209         /* Determine scale */
210         final int myScale = pValue.scale()
211                 - OceanusDecimalConstants.ADJUST_PERCENT;
212         if (myScale > 0) {
213             /* Append the decimal point */
214             myBuilder.append(OceanusDecimalConstants.STR_DEC);
215 
216             /* Append the decimal places */
217             myBuilder.repeat(String.valueOf(OceanusDecimalConstants.CHAR_ZERO), myScale);
218         }
219 
220         /* Append the percent */
221         myBuilder.append('%');
222 
223         /* Return the format */
224         return myBuilder.toString();
225     }
226 
227     /**
228      * Obtain format for extended decimal.
229      *
230      * @param pValue the example decimal
231      * @return the format
232      */
233     private static String getExtendedFormat(final OceanusDecimal pValue) {
234         /* Create String builder */
235         final StringBuilder myBuilder = new StringBuilder();
236 
237         /* Start with standard decimal */
238         myBuilder.append(getStandardFormat(pValue));
239 
240         /* Insert initial values */
241         myBuilder.insert(0, CHAR_DIGIT);
242         myBuilder.insert(0, CHAR_DIGIT);
243         myBuilder.insert(0, OceanusDecimalConstants.CHAR_GROUP);
244         myBuilder.insert(0, CHAR_DIGIT);
245 
246         /* Return the format */
247         return myBuilder.toString();
248     }
249 
250     /**
251      * Obtain format for currency.
252      *
253      * @param pValue the example currency
254      * @return the format
255      */
256     private static String getCurrencyFormat(final OceanusMoney pValue) {
257         /* Create String builder */
258         final StringBuilder myBuilder = new StringBuilder();
259 
260         /* Start with extended decimal */
261         final String myFormat = getExtendedFormat(pValue);
262 
263         /* Obtain currency code */
264         String myCurrency = pValue.getCurrency().getSymbol();
265         myCurrency = STR_QUOTE + myCurrency + STR_QUOTE;
266 
267         /* Insert initial values */
268         myBuilder.append(myCurrency);
269         myBuilder.append(myFormat);
270         myBuilder.append(CHAR_SEP);
271         myBuilder.append(STR_RED);
272         myBuilder.append(OceanusDecimalConstants.CHAR_MINUS);
273         myBuilder.append(myCurrency);
274         myBuilder.append(myFormat);
275 
276         /* Return the format */
277         return myBuilder.toString();
278     }
279 
280     /**
281      * Obtain format for currency, with zero usage.
282      *
283      * @param pValue the example currency
284      * @return the format
285      */
286     private static String getAccountingFormat(final OceanusMoney pValue) {
287         /* Create String builder */
288         final StringBuilder myBuilder = new StringBuilder();
289 
290         /* Start with currency format */
291         final String myFormat = getCurrencyFormat(pValue);
292 
293         /* Obtain currency code */
294         String myCurrency = pValue.getCurrency().getSymbol();
295         myCurrency = STR_QUOTE + myCurrency + STR_QUOTE;
296 
297         /* Insert initial values */
298         myBuilder.append(myFormat);
299         myBuilder.append(CHAR_SEP);
300         myBuilder.append(myCurrency);
301         myBuilder.append(OceanusDecimalConstants.CHAR_BLANK);
302         myBuilder.append(OceanusDecimalConstants.CHAR_MINUS);
303 
304         /* Return the format */
305         return myBuilder.toString();
306     }
307 
308     /**
309      * Obtain data format string for a cell type.
310      *
311      * @param pType the cell style type
312      * @return the format string
313      */
314     public static String getDataFormatString(final PrometheusSheetCellStyleType pType) {
315         return getDataFormatString(getDefaultValue(pType));
316     }
317 
318     /**
319      * Obtain default value for a cell type.
320      *
321      * @param pType the cell style type
322      * @return the format string
323      */
324     public static Object getDefaultValue(final PrometheusSheetCellStyleType pType) {
325         return switch (pType) {
326             case STRING -> STR_NULL;
327             case DATE -> new OceanusDate();
328             case BOOLEAN -> Boolean.TRUE;
329             case INTEGER -> 0;
330             case MONEY -> OceanusMoney.getWholeUnits(0);
331             case PRICE -> OceanusPrice.getWholeUnits(0);
332             case RATE -> OceanusRate.getWholePercentage(0);
333             case UNITS -> OceanusUnits.getWholeUnits(0);
334             case RATIO -> OceanusRatio.getWholeUnits(0);
335             default -> null;
336         };
337     }
338 
339     /**
340      * Obtain data format string for a cell value.
341      *
342      * @param pValue the cell value
343      * @return the format string
344      */
345     public static String getDataFormatString(final Object pValue) {
346         if (pValue instanceof OceanusDate) {
347             return FORMAT_DATE;
348         }
349         if (pValue instanceof Boolean) {
350             return FORMAT_BOOLEAN;
351         }
352         if (pValue instanceof Integer
353                 || pValue instanceof Long) {
354             return getIntegerFormat();
355         }
356         if (pValue instanceof OceanusMoney m) {
357             return getAccountingFormat(m);
358         }
359         if (pValue instanceof OceanusRate r) {
360             return getRateFormat(r);
361         }
362         if (pValue instanceof OceanusUnits u) {
363             return getExtendedFormat(u);
364         }
365         if (pValue instanceof OceanusDecimal d) {
366             return getStandardFormat(d);
367         }
368         return null;
369     }
370 
371     /**
372      * Obtain alternate data format string for a cell value.
373      *
374      * @param pValue the cell value
375      * @return the format string
376      */
377     public static String getAlternateFormatString(final Object pValue) {
378         if (pValue instanceof OceanusMoney m) {
379             return getCurrencyFormat(m);
380         }
381         return null;
382     }
383 
384     /**
385      * Obtain style name.
386      *
387      * @param pStyle the style type
388      * @return the name of the style
389      */
390     private static String getStyleName(final String pStyle) {
391         return "sn"
392                 + pStyle;
393     }
394 
395     /**
396      * Obtain data format string for a cell type.
397      *
398      * @param pType the cell style type
399      * @return the format string
400      */
401     public static String getFormatName(final PrometheusSheetCellStyleType pType) {
402         return pType == PrometheusSheetCellStyleType.HEADER
403                 ? getAlternateFormatName(STR_NULL)
404                 : getFormatName(getDefaultValue(pType));
405     }
406 
407     /**
408      * Obtain format name for a cell.
409      *
410      * @param pValue the cell value
411      * @return the format string
412      */
413     public static String getFormatName(final Object pValue) {
414         if (pValue instanceof String) {
415             return getStyleName(String.class.getSimpleName());
416         }
417         if (pValue instanceof Boolean) {
418             return getStyleName(Boolean.class.getSimpleName());
419         }
420         if (pValue instanceof OceanusDate) {
421             return getStyleName(OceanusDate.class.getSimpleName());
422         }
423         if (pValue instanceof Integer
424                 || pValue instanceof Long) {
425             return getStyleName(Integer.class.getSimpleName());
426         }
427         if (pValue instanceof OceanusPrice p) {
428             final String myCurr = p.getCurrency().getCurrencyCode();
429             return getStyleName(OceanusPrice.class.getSimpleName()
430                     + myCurr);
431         }
432         if (pValue instanceof OceanusMoney m) {
433             final String myCurr = m.getCurrency().getCurrencyCode();
434             return getStyleName(OceanusMoney.class.getSimpleName()
435                     + myCurr);
436         }
437         if (pValue instanceof OceanusRate) {
438             return getStyleName(OceanusRate.class.getSimpleName());
439         }
440         if (pValue instanceof OceanusUnits) {
441             return getStyleName(OceanusUnits.class.getSimpleName());
442         }
443         if (pValue instanceof OceanusRatio) {
444             return getStyleName(OceanusRatio.class.getSimpleName());
445         }
446         return null;
447     }
448 
449     /**
450      * Obtain currency format name for a cell.
451      *
452      * @param pValue the cell value
453      * @return the format string
454      */
455     public static String getAlternateFormatName(final Object pValue) {
456         if (pValue instanceof String) {
457             return getStyleName(PrometheusSheetCellStyleType.HEADER.toString());
458         }
459         if (pValue instanceof OceanusPrice p) {
460             final String myCurr = p.getCurrency().getCurrencyCode();
461             return getStyleName(OceanusPrice.class.getSimpleName()
462                     + FORMAT_CURR
463                     + myCurr);
464         }
465         if (pValue instanceof OceanusMoney m) {
466             final String myCurr = m.getCurrency().getCurrencyCode();
467             return getStyleName(OceanusMoney.class.getSimpleName()
468                     + FORMAT_CURR
469                     + myCurr);
470         }
471         return null;
472     }
473 
474     /**
475      * Determine whether cell type has data format.
476      *
477      * @param pType the cell type
478      * @return true/false
479      */
480     public static boolean hasDataFormat(final PrometheusSheetCellStyleType pType) {
481         return switch (pType) {
482             case DATE, BOOLEAN, INTEGER, MONEY, PRICE, RATE, UNITS, RATIO -> true;
483             default -> false;
484         };
485     }
486 
487     /**
488      * Obtain data format for a value.
489      *
490      * @param pValue the cell value
491      * @return the cell style type
492      */
493     public static PrometheusSheetCellStyleType getCellStyleType(final Object pValue) {
494         if (pValue instanceof String) {
495             return PrometheusSheetCellStyleType.STRING;
496         }
497         if (pValue instanceof OceanusDate) {
498             return PrometheusSheetCellStyleType.DATE;
499         }
500         if (pValue instanceof Boolean) {
501             return PrometheusSheetCellStyleType.BOOLEAN;
502         }
503         if (pValue instanceof Integer
504                 || pValue instanceof Long) {
505             return PrometheusSheetCellStyleType.INTEGER;
506         }
507         if (pValue instanceof OceanusPrice) {
508             return PrometheusSheetCellStyleType.PRICE;
509         }
510         if (pValue instanceof OceanusMoney) {
511             return PrometheusSheetCellStyleType.MONEY;
512         }
513         if (pValue instanceof OceanusRate) {
514             return PrometheusSheetCellStyleType.RATE;
515         }
516         if (pValue instanceof OceanusUnits) {
517             return PrometheusSheetCellStyleType.UNITS;
518         }
519         if (pValue instanceof OceanusRatio) {
520             return PrometheusSheetCellStyleType.RATIO;
521         }
522         return null;
523     }
524 }