1 package com.github.mygreen.cellformatter;
2
3 import java.util.ArrayList;
4 import java.util.Calendar;
5 import java.util.List;
6 import java.util.regex.Pattern;
7
8 import org.slf4j.Logger;
9 import org.slf4j.LoggerFactory;
10
11 import com.github.mygreen.cellformatter.lang.ArgUtils;
12 import com.github.mygreen.cellformatter.lang.Utils;
13 import com.github.mygreen.cellformatter.term.AsteriskTerm;
14 import com.github.mygreen.cellformatter.term.DateTerm;
15 import com.github.mygreen.cellformatter.term.EscapedCharTerm;
16 import com.github.mygreen.cellformatter.term.LocaelSymbolTerm;
17 import com.github.mygreen.cellformatter.term.OtherTerm;
18 import com.github.mygreen.cellformatter.term.Term;
19 import com.github.mygreen.cellformatter.term.UnderscoreTerm;
20 import com.github.mygreen.cellformatter.term.WordTerm;
21 import com.github.mygreen.cellformatter.tokenizer.Token;
22 import com.github.mygreen.cellformatter.tokenizer.TokenStore;
23
24
25
26
27
28
29
30 public class ConditionDateFormatterFactory extends ConditionFormatterFactory<ConditionDateFormatter> {
31
32 private static Logger logger = LoggerFactory.getLogger(ConditionDateFormatterFactory.class);
33
34
35
36
37 private static final String[] DATE_DECISTION_CHARS = {
38 "yy", "yyyy",
39 "m", "mm", "mmm", "mmmm", "mmmmm",
40 "d", "dd", "ddd", "dddd",
41 "g", "gg", "ggg",
42 "ee",
43 "aaa", "aaaa",
44 "r", "rr",
45 "h", "hh",
46 "s", "ss",
47 "am/pm", "a/p",
48 "q", "qq",
49 "nn", "nnn",
50 "ww",
51 };
52
53
54
55
56 private static final String[] DATE_TERM_CHARS = {
57 "yy", "yyyy",
58 "m", "mm", "mmm", "mmmm", "mmmmm",
59 "d", "dd", "ddd", "dddd",
60 "g", "gg", "ggg",
61 "e", "ee",
62 "aaa", "aaaa",
63 "r", "rr",
64 "h", "hh",
65 "s", "ss",
66 "am/pm", "a/p",
67 "q", "qq",
68 "nn",
69 "ww",
70 };
71
72
73
74
75
76 private static final List<String> SORTED_DATE_CHARS = Utils.reverse(DATE_TERM_CHARS);
77
78
79
80
81 private static final Pattern PATTERN_ELAPSED_TIME = Pattern.compile("\\[([h]+|[m]+|[s]+)\\]", Pattern.CASE_INSENSITIVE);
82
83
84
85
86
87
88 public boolean isDatePattern(final TokenStore store) {
89
90 if(store.containsInFactor("General")) {
91 return false;
92 }
93
94 if(store.containsAnyInFactorIgnoreCase(DATE_DECISTION_CHARS)) {
95 return true;
96 }
97
98
99 for(Token token : store.getTokens()) {
100 if(!(token instanceof Token.Condition)) {
101 continue;
102 }
103
104 final Token.Condition condition = token.asCondition();
105 final String value = condition.getValue();
106 if(PATTERN_ELAPSED_TIME.matcher(value).matches()) {
107 return true;
108 }
109
110 }
111
112 return false;
113 }
114
115
116
117
118
119
120
121 @Override
122 public ConditionDateFormatter create(final TokenStore store) {
123 ArgUtils.notNull(store, "store");
124
125 final ConditionDateFormatterormatter.html#ConditionDateFormatter">ConditionDateFormatter formatter = new ConditionDateFormatter(store.getConcatenatedToken());
126
127 for(Token token : store.getTokens()) {
128
129 if(token instanceof Token.Condition) {
130
131 final Token.Condition conditionToken = token.asCondition();
132 final String condition = conditionToken.getCondition();
133
134 if(PATTERN_ELAPSED_TIME.matcher(token.getValue()).matches()) {
135
136 if(Utils.startsWithIgnoreCase(condition, "h")) {
137 formatter.addTerm(DateTerm.elapsedHour(condition));
138
139 } else if(Utils.startsWithIgnoreCase(condition, "m")) {
140 formatter.addTerm(DateTerm.elapsedMinute(condition));
141
142 } else if(Utils.startsWithIgnoreCase(condition, "s")) {
143 formatter.addTerm(DateTerm.elapsedSecond(condition));
144
145 }
146 continue;
147 }
148
149 formatter.addCondition(condition);
150
151 if(isConditionOperator(conditionToken)) {
152 setupConditionOperator(formatter, conditionToken);
153
154 } else if(isConditionLocale(conditionToken)) {
155 setupConditionLocale(formatter, conditionToken);
156
157 } else if(isConditionLocaleSymbol(conditionToken)) {
158 final LocaleSymbol localeSymbol = setupConditionLocaleSymbol(formatter, conditionToken);
159 formatter.addTerm(new LocaelSymbolTerm<Calendar>(localeSymbol));
160
161 } else if(isConditionDbNum(conditionToken)) {
162 setupConditionDbNum(formatter, conditionToken);
163
164 } else if(isConditionColor(conditionToken)) {
165 setupConditionColor(formatter, conditionToken);
166
167 }
168
169 } else if(token instanceof Token.Word) {
170 formatter.addTerm(new WordTerm<Calendar>(token.asWord()));
171
172 } else if(token instanceof Token.EscapedChar) {
173 formatter.addTerm(new EscapedCharTerm<Calendar>(token.asEscapedChar()));
174
175 } else if(token instanceof Token.Underscore) {
176 formatter.addTerm(new UnderscoreTerm<Calendar>(token.asUnderscore()));
177
178 } else if(token instanceof Token.Asterisk) {
179 formatter.addTerm(new AsteriskTerm<Calendar>(token.asAsterisk()));
180
181 } else if(token instanceof Token.Factor) {
182
183 final List<Token> list = convertFactor(token.asFactor());
184 for(Token item : list) {
185
186 if(item instanceof Token.Formatter) {
187 final String formatterItem = item.asFormatter().getValue();
188
189 if(Utils.equalsAnyIgnoreCase(formatterItem, new String[]{"am/pm", "a/p"})) {
190 formatter.addTerm(DateTerm.amPm(formatterItem));
191
192 } else if(Utils.startsWithIgnoreCase(formatterItem, "w")) {
193 formatter.addTerm(DateTerm.weekNumber(formatterItem));
194
195 } else if(Utils.startsWithIgnoreCase(formatterItem, "y")) {
196 formatter.addTerm(DateTerm.year(formatterItem));
197
198 } else if(Utils.startsWithIgnoreCase(formatterItem, "g")) {
199 formatter.addTerm(DateTerm.eraName(formatterItem));
200
201 } else if(Utils.startsWithIgnoreCase(formatterItem, "e")) {
202 formatter.addTerm(DateTerm.eraYear(formatterItem));
203
204 } else if(Utils.startsWithIgnoreCase(formatterItem, "r")) {
205 formatter.addTerm(DateTerm.eraNameYear(formatterItem));
206
207 } else if(Utils.startsWithIgnoreCase(formatterItem, "m")) {
208
209 formatter.addTerm(DateTerm.month(formatterItem));
210
211 } else if(Utils.startsWithIgnoreCase(formatterItem, "d")) {
212 formatter.addTerm(DateTerm.day(formatterItem));
213
214 } else if(Utils.startsWithIgnoreCase(formatterItem, "a")) {
215 formatter.addTerm(DateTerm.weekName(formatterItem));
216
217 } else if(Utils.startsWithIgnoreCase(formatterItem, "n")) {
218 formatter.addTerm(DateTerm.weekNameForOO(formatterItem));
219
220 } else if(Utils.startsWithIgnoreCase(formatterItem, "h")) {
221 final boolean halfHour = store.containsAnyInFactorIgnoreCase(new String[]{"am/pm", "a/p"});
222 formatter.addTerm(DateTerm.hour(formatterItem, halfHour));
223
224 } else if(Utils.startsWithIgnoreCase(formatterItem, "s")) {
225 formatter.addTerm(DateTerm.second(formatterItem));
226
227 } else if(Utils.startsWithIgnoreCase(formatterItem, "q")) {
228 formatter.addTerm(DateTerm.quater(formatterItem));
229
230 } else {
231
232 if(logger.isWarnEnabled()) {
233 logger.warn("unknown date format terms '{}'.", formatterItem);
234 }
235 formatter.addTerm(new OtherTerm<Calendar>(item));
236 }
237
238 } else {
239 formatter.addTerm(new OtherTerm<Calendar>(item));
240 }
241
242 }
243 } else {
244 formatter.addTerm(new OtherTerm<Calendar>(token));
245 }
246 }
247
248
249 convertMinuteTerm(formatter);
250
251 return formatter;
252
253 }
254
255
256
257
258
259
260 private List<Token> convertFactor(final Token.Factor factor) {
261
262 final String item = factor.getValue();
263 final int itemLength = item.length();
264
265 final List<Token> list = new ArrayList<>();
266
267 int idx = 0;
268 StringBuilder noTermChar = new StringBuilder();
269 while(idx < itemLength) {
270
271 String matchChars = null;
272 for(String chars : SORTED_DATE_CHARS) {
273 if(Utils.startsWithIgnoreCase(item, chars, idx)) {
274 matchChars = item.substring(idx, idx + chars.length());
275 break;
276 }
277 }
278
279 if(matchChars == null) {
280
281 noTermChar.append(item.charAt(idx));
282 idx++;
283 } else {
284 if(noTermChar.length() > 0) {
285
286 list.add(Token.factor(noTermChar.toString()));
287 noTermChar = new StringBuilder();
288 }
289
290 list.add(Token.formatter(matchChars));
291 idx += matchChars.length();
292
293 }
294 }
295
296 if(noTermChar.length() > 0) {
297 list.add(Token.factor(noTermChar.toString()));
298 }
299
300 return list;
301 }
302
303
304
305
306
307
308 private void convertMinuteTerm(final ConditionDateFormatter formatter) {
309
310 final int termSize = formatter.getTerms().size();
311 for(int i=0; i < termSize; i++) {
312 final Term<Calendar> term = formatter.getTerms().get(i);
313 if(!(term instanceof DateTerm.MonthTerm)) {
314 continue;
315 }
316
317 if(isMinuteTerm(i, formatter.getTerms())) {
318
319 final DateTerm.MonthTerm monthTerm = (DateTerm.MonthTerm) term;
320 formatter.getTerms().set(i, DateTerm.minute(monthTerm.getFormat()));
321 }
322
323 }
324
325 }
326
327
328
329
330
331
332
333
334
335
336 private boolean isMinuteTerm(final int currentTermIdx, final List<Term<Calendar>> terms) {
337
338 final int termSize = terms.size();
339
340
341 if(currentTermIdx -1 > 0) {
342 DateTerm beforeTerm = null;
343 for(int i=currentTermIdx-1; i >= 0; i--) {
344 final Term<Calendar> term = terms.get(i);
345 if(term instanceof DateTerm) {
346 beforeTerm = (DateTerm) term;
347 break;
348 }
349
350 }
351
352 if(beforeTerm != null) {
353 if(beforeTerm instanceof DateTerm.HourTerm || beforeTerm instanceof DateTerm.ElapsedHourTerm) {
354 return true;
355 }
356 }
357
358 }
359
360
361 if(currentTermIdx +1 < termSize) {
362 DateTerm afterTerm = null;
363 for(int i=currentTermIdx+1; i < termSize; i++) {
364 final Term<Calendar> term = terms.get(i);
365 if(term instanceof DateTerm) {
366 afterTerm = (DateTerm) term;
367 break;
368 }
369 }
370
371 if(afterTerm != null) {
372 if(afterTerm instanceof DateTerm.SecondTerm || afterTerm instanceof DateTerm.ElapsedSecondTerm) {
373 return true;
374 }
375 }
376 }
377
378 return false;
379 }
380
381 }