1 module hunt.time.format.WeekBasedFieldPrinterParser;
2 
3 import hunt.time.format.DateTimeParseContext;
4 import hunt.time.format.DateTimePrinterParser;
5 import hunt.time.format.DateTimePrintContext;
6 import hunt.time.format.NumberPrinterParser;
7 import hunt.time.format.ReducedPrinterParser;
8 import hunt.time.format.SignStyle;
9 import hunt.time.temporal.TemporalField;
10 import hunt.time.temporal.WeekFields;
11 
12 import hunt.util.StringBuilder;
13 
14 import hunt.Exceptions;
15 import hunt.util.Locale;
16 
17 //-----------------------------------------------------------------------
18 /**
19 * Prints or parses a localized pattern from a localized field.
20 * The specific formatter and parameters is not selected until
21 * the field is to be printed or parsed.
22 * The locale is needed to select the proper WeekFields from which
23 * the field for day-of-week, week-of-month, or week-of-year is selected.
24 * Hence the inherited field NumberPrinterParser.field is unused.
25 */
26 static final class WeekBasedFieldPrinterParser : NumberPrinterParser
27 {
28     private char chr;
29     private int count;
30 
31     /**
32  * Constructor.
33  *
34  * @param chr the pattern format letter that added this PrinterParser.
35  * @param count the repeat count of the format letter
36  * @param minWidth  the minimum field width, from 1 to 19
37  * @param maxWidth  the maximum field width, from minWidth to 19
38  */
39     this(char chr, int count, int minWidth, int maxWidth)
40     {
41         this(chr, count, minWidth, maxWidth, 0);
42     }
43 
44     /**
45  * Constructor.
46  *
47  * @param chr the pattern format letter that added this PrinterParser.
48  * @param count the repeat count of the format letter
49  * @param minWidth  the minimum field width, from 1 to 19
50  * @param maxWidth  the maximum field width, from minWidth to 19
51  * @param subsequentWidth  the width of subsequent non-negative numbers, 0 or greater,
52  * -1 if fixed width due to active adjacent parsing
53  */
54     this(char chr, int count, int minWidth, int maxWidth, int subsequentWidth)
55     {
56         super(null, minWidth, maxWidth, SignStyle.NOT_NEGATIVE, subsequentWidth);
57         this.chr = chr;
58         this.count = count;
59     }
60 
61     /**
62  * Returns a new instance with fixed width flag set.
63  *
64  * @return a new updated printer-parser, not null
65  */
66     override WeekBasedFieldPrinterParser withFixedWidth()
67     {
68         if (subsequentWidth == -1)
69         {
70             return this;
71         }
72         return new WeekBasedFieldPrinterParser(chr, count, minWidth, maxWidth, -1);
73     }
74 
75     /**
76  * Returns a new instance with an updated subsequent width.
77  *
78  * @param subsequentWidth  the width of subsequent non-negative numbers, 0 or greater
79  * @return a new updated printer-parser, not null
80  */
81     override WeekBasedFieldPrinterParser withSubsequentWidth(int subsequentWidth)
82     {
83         return new WeekBasedFieldPrinterParser(chr, count, minWidth,
84                 maxWidth, this.subsequentWidth + subsequentWidth);
85     }
86 
87     override public bool format(DateTimePrintContext context, StringBuilder buf)
88     {
89         return printerParser(context.getLocale()).format(context, buf);
90     }
91 
92     override public int parse(DateTimeParseContext context, string text, int position)
93     {
94         return printerParser(context.getLocale()).parse(context, text, position);
95     }
96 
97     /**
98  * Gets the printerParser to use based on the field and the locale.
99  *
100  * @param locale  the locale to use, not null
101  * @return the formatter, not null
102  * @throws IllegalArgumentException if the formatter cannot be found
103  */
104     private DateTimePrinterParser printerParser(Locale locale)
105     {
106         WeekFields weekDef = WeekFields.of(locale);
107         TemporalField field = null;
108         switch (chr)
109         {
110         case 'Y':
111             field = weekDef.weekBasedYear();
112             if (count == 2)
113             {
114                 return new ReducedPrinterParser(field, 2, 2, 0,
115                         ReducedPrinterParser.BASE_DATE, this.subsequentWidth);
116             }
117             else
118             {
119                 return new NumberPrinterParser(field, count, 19, (count < 4)
120                         ? SignStyle.NORMAL : SignStyle.EXCEEDS_PAD, this.subsequentWidth);
121             }
122         case 'e':
123         case 'c':
124             field = weekDef.dayOfWeek();
125             break;
126         case 'w':
127             field = weekDef.weekOfWeekBasedYear();
128             break;
129         case 'W':
130             field = weekDef.weekOfMonth();
131             break;
132         default:
133             throw new IllegalStateException("unreachable");
134         }
135         return new NumberPrinterParser(field, minWidth, maxWidth,
136                 SignStyle.NOT_NEGATIVE, this.subsequentWidth);
137     }
138 
139     override public string toString()
140     {
141         StringBuilder sb = new StringBuilder(30);
142         sb.append("Localized(");
143         if (chr == 'Y')
144         {
145             if (count == 1)
146             {
147                 sb.append("WeekBasedYear");
148             }
149             else if (count == 2)
150             {
151                 sb.append("ReducedValue(WeekBasedYear,2,2,2000-01-01)");
152             }
153             else
154             {
155                 sb.append("WeekBasedYear,").append(count).append(",")
156                     .append(19).append(",").append((count < 4)
157                             ? SignStyle.NORMAL.name() : SignStyle.EXCEEDS_PAD.name());
158             }
159         }
160         else
161         {
162             switch (chr)
163             {
164             case 'c':
165             case 'e':
166                 sb.append("DayOfWeek");
167                 break;
168             case 'w':
169                 sb.append("WeekOfWeekBasedYear");
170                 break;
171             case 'W':
172                 sb.append("WeekOfMonth");
173                 break;
174             default:
175                 break;
176             }
177             sb.append(",");
178             sb.append(count);
179         }
180         sb.append(")");
181         return sb.toString();
182     }
183 }