1 module hunt.time.format.LocalizedPrinterParser;
2 
3 import hunt.time.chrono.Chronology;
4 import hunt.time.chrono.ChronoLocalDate;
5 import hunt.time.format.DateTimeFormatter;
6 import hunt.time.format.DateTimeFormatterBuilder;
7 import hunt.time.format.DateTimeParseContext;
8 import hunt.time.format.DateTimePrinterParser;
9 import hunt.time.format.DateTimePrintContext;
10 import hunt.time.format.FormatStyle;
11 import hunt.time.temporal.TemporalField;
12 import hunt.time.util.Common;
13 // import hunt.time.util.Locale;
14 import hunt.util.StringBuilder;
15 
16 import hunt.collection.HashMap;
17 import hunt.collection.Map;
18 import hunt.Exceptions;
19 import hunt.util.Locale;
20 
21 import std.concurrency : initOnce;
22 
23 //-----------------------------------------------------------------------
24 /**
25 * Prints or parses a localized pattern.
26 */
27 final class LocalizedPrinterParser : DateTimePrinterParser
28 {
29     /** Cache of formatters. */
30     static Map!(string, DateTimeFormatter) FORMATTER_CACHE() {
31         __gshared Map!(string, DateTimeFormatter) inst;
32         return initOnce!(inst)(
33                 new HashMap!(string, DateTimeFormatter)(16, 0.75f /* , 2 */ ));
34     }
35 
36     private FormatStyle dateStyle;
37     private FormatStyle timeStyle;
38 
39     /**
40      * Constructor.
41      *
42      * @param dateStyle  the date style to use, may be null
43      * @param timeStyle  the time style to use, may be null
44      */
45     this(FormatStyle dateStyle, FormatStyle timeStyle)
46     {
47         // validated by caller
48         this.dateStyle = dateStyle;
49         this.timeStyle = timeStyle;
50     }
51 
52     override bool format(DateTimePrintContext context, StringBuilder buf)
53     {
54         Chronology chrono = Chronology.from(context.getTemporal());
55         return formatter(context.getLocale(), chrono).toPrinterParser(false)
56             .format(context, buf);
57     }
58 
59     override int parse(DateTimeParseContext context, string text, int position)
60     {
61         Chronology chrono = context.getEffectiveChronology();
62         return formatter(context.getLocale(), chrono).toPrinterParser(false)
63             .parse(context, text, position);
64     }
65 
66     /**
67      * Gets the formatter to use.
68      * !(p)
69      * The formatter will be the most appropriate to use for the date and time style _in the locale.
70      * For example, some locales will use the month name while others will use the number.
71      *
72      * @param locale  the locale to use, not null
73      * @param chrono  the chronology to use, not null
74      * @return the formatter, not null
75      * @throws IllegalArgumentException if the formatter cannot be found
76      */
77     private DateTimeFormatter formatter(Locale locale, Chronology chrono)
78     {
79         string key = chrono.getId() ~ '|' ~ locale.toString() ~ '|' ~ dateStyle.name() ~ timeStyle.name();
80         DateTimeFormatter formatter = FORMATTER_CACHE.get(key);
81         if (formatter is null) {
82             string pattern = getLocalizedDateTimePattern(dateStyle,
83                     timeStyle, chrono, locale);
84             formatter = new DateTimeFormatterBuilder().appendPattern(pattern)
85                 .toFormatter(locale);
86             DateTimeFormatter old = FORMATTER_CACHE.putIfAbsent(key, formatter);
87             if (old !is null) {
88                 formatter = old;
89             }
90         }
91         return formatter;
92         // implementationMissing(false);
93         // return null;
94     }
95 
96     
97     /**
98      * Gets the formatting pattern for date and time styles for a locale and chronology.
99      * The locale and chronology are used to lookup the locale specific format
100      * for the requested dateStyle and/or timeStyle.
101      * !(p)
102      * If the locale contains the "rg" (region override)
103      * <a href="../../util/Locale.html#def_locale_extension">Unicode extensions</a>,
104      * the formatting pattern is overridden with the one appropriate for the region.
105      *
106      * @param dateStyle  the FormatStyle for the date, null for time-only pattern
107      * @param timeStyle  the FormatStyle for the time, null for date-only pattern
108      * @param chrono  the Chronology, non-null
109      * @param locale  the locale, non-null
110      * @return the locale and Chronology specific formatting pattern
111      * @throws IllegalArgumentException if both dateStyle and timeStyle are null
112      */
113     static string getLocalizedDateTimePattern(FormatStyle dateStyle,
114             FormatStyle timeStyle, Chronology chrono, Locale locale) {
115         // assert(locale, "locale");
116         // assert(chrono, "chrono");
117         // if (dateStyle is null && timeStyle is null) {
118         //     throw new IllegalArgumentException("Either dateStyle or timeStyle must be non-null");
119         // }
120         // LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(JavaTimeDateTimePatternProvider.class, locale);
121         // JavaTimeDateTimePatternProvider provider = adapter.getJavaTimeDateTimePatternProvider();
122         // string pattern = provider.getJavaTimeDateTimePattern(convertStyle(timeStyle),
123         //                  convertStyle(dateStyle), chrono.getCalendarType(),
124         //                  CalendarDataUtility.findRegionOverride(locale));
125         // return pattern;
126         implementationMissing(false);
127         return null;
128     }
129 
130     override string toString()
131     {
132         return "Localized(" ~ (dateStyle !is null ? dateStyle.name()
133                 : "") ~ "," ~ (timeStyle !is null ? timeStyle.name() : "") ~ ")";
134     }
135 }