001/*
002 * (C) Copyright 2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Olivier Grisel
018 */
019package org.nuxeo.ecm.platform.suggestbox.utils;
020
021import java.time.DateTimeException;
022import java.time.ZoneOffset;
023import java.time.ZonedDateTime;
024import java.util.Calendar;
025import java.util.GregorianCalendar;
026import java.util.regex.Matcher;
027import java.util.regex.Pattern;
028
029import org.nuxeo.ecm.platform.suggestbox.service.suggesters.DocumentSearchByDateSuggester;
030
031/**
032 * @deprecated since 11.1 only used from deprecated {@link DocumentSearchByDateSuggester}
033 */
034@Deprecated
035public class DateMatcher {
036
037    private static final Pattern YEAR_ONLY_MATCHER = Pattern.compile("^\\d{4}$");
038
039    private static final Pattern MONTH_DIGIT_ONLY_MATCHER = Pattern.compile("^\\d{2}$");
040
041    private static final Pattern YEAR_MONTHS_MATCHER = Pattern.compile("^\\d{4}[_ -:]\\d{2}$");
042
043    private static final Pattern MONTHS_YEAR_MATCHER = Pattern.compile("^\\d{2}[_ -:]\\d{4}$");
044
045    private static final Pattern MONTHS_DAY_YEAR_MATCHER = Pattern.compile("^\\d{2}[_ -:]\\d{2,}[_ -:]\\d{4}$");
046
047    private static final Pattern YEAR_MONTHS_DAY_MATCHER = Pattern.compile("^\\d{4}[_ -:]\\d{2,}[_ -:]\\d{2}$");
048
049    private boolean withYears = false;
050
051    private boolean withMonth = false;
052
053    private boolean withDay = false;
054
055    private final Calendar dateSuggestion;
056
057    private DateMatcher(boolean withYears, boolean withMonth, boolean withDay, Calendar dateSuggestion) {
058        this.withYears = withYears;
059        this.withMonth = withMonth;
060        this.withDay = withDay;
061        this.dateSuggestion = dateSuggestion;
062    }
063
064    public boolean isWithYears() {
065        return withYears;
066    }
067
068    public void setWithYears(boolean withYears) {
069        this.withYears = withYears;
070    }
071
072    public boolean isWithMonth() {
073        return withMonth;
074    }
075
076    public void setWithMonth(boolean withMonth) {
077        this.withMonth = withMonth;
078    }
079
080    public boolean isWitDay() {
081        return withDay;
082    }
083
084    public void setWitDay(boolean witDay) {
085        withDay = witDay;
086    }
087
088    public Calendar getDateSuggestion() {
089        return dateSuggestion;
090    }
091
092    public boolean hasMatch() {
093        return getDateSuggestion() != null;
094    }
095
096    public static Matcher parsingDate(Pattern pattern, String input) {
097        return pattern.matcher(input.trim());
098    }
099
100    public static DateMatcher fromInput(String input) {
101        try {
102            return doFromInput(input);
103        } catch (NumberFormatException e) {
104            return new DateMatcher(false, false, false, null);
105        }
106    }
107
108    public static DateMatcher doFromInput(String input) {
109        Matcher matcher = parsingDate(YEAR_ONLY_MATCHER, input);
110
111        if (matcher.find()) {
112            return new DateMatcher(true, false, false, dateToInstance(Integer.parseInt(matcher.group()), 1, 1));
113        }
114        matcher = parsingDate(MONTH_DIGIT_ONLY_MATCHER, input);
115        if (matcher.find()) {
116            int month = Integer.parseInt(matcher.group());
117            if (month > 12 || month < 1) {
118                return new DateMatcher(false, true, false, null);
119            }
120            return new DateMatcher(false, true, false,
121                    dateToInstance(Calendar.getInstance().get(Calendar.YEAR), month, 1));
122        }
123        matcher = parsingDate(YEAR_MONTHS_MATCHER, input);
124        if (matcher.find()) {
125            int month = Integer.parseInt(matcher.group().substring(5));
126            if (month > 12 || month < 1) {
127                return new DateMatcher(true, true, false, null);
128            }
129            int year = Integer.parseInt(matcher.group().substring(0, 4));
130
131            return new DateMatcher(true, true, false, dateToInstance(year, month, 1));
132        }
133        matcher = parsingDate(MONTHS_YEAR_MATCHER, input);
134        if (matcher.find()) {
135            int month = Integer.parseInt(matcher.group().substring(0, 2));
136            if (month > 12 || month < 1) {
137                return new DateMatcher(true, true, false, null);
138            }
139            int year = Integer.parseInt(matcher.group().substring(3));
140
141            return new DateMatcher(true, true, false, dateToInstance(year, month, 1));
142
143        }
144        matcher = parsingDate(MONTHS_DAY_YEAR_MATCHER, input);
145        if (matcher.find()) {
146            int first = Integer.parseInt(matcher.group().substring(0, 2));
147            int second = Integer.parseInt(matcher.group().substring(3, 5));
148            int year = Integer.parseInt(matcher.group().substring(6));
149            int control = first + second;
150            if (control < 2 || control > 12 + 31 || first < 1 || second < 1) {
151                return new DateMatcher(true, true, true, null);
152            } else if (control < 12 + 12 + 1) {
153                return new DateMatcher(true, true, true, dateToInstance(year, first, second));
154            }
155            int month = first;
156            int day = second;
157            if (first > second) {
158                month = second;
159                day = first;
160            }
161            Calendar dateToInstance = dateToInstance(year, month, day);
162            return new DateMatcher(true, true, true, dateToInstance);
163        }
164        matcher = parsingDate(YEAR_MONTHS_DAY_MATCHER, input);
165        if (matcher.find()) {
166            int year = Integer.parseInt(matcher.group().substring(0, 4));
167            int first = Integer.parseInt(matcher.group().substring(5, 7));
168            int second = Integer.parseInt(matcher.group().substring(8));
169            int control = first + second;
170            if (control < 2 || control > 12 + 31 || first < 1 || second < 1) {
171                return new DateMatcher(true, true, true, null);
172            } else if (control < 12 + 12 + 1) {
173                return new DateMatcher(true, true, true, dateToInstance(year, first, second));
174            }
175            int month = first;
176            int day = second;
177            if (first > second) {
178                month = second;
179                day = first;
180            }
181            Calendar dateToInstance = dateToInstance(year, month, day);
182            return new DateMatcher(true, true, true, dateToInstance);
183        }
184
185        return new DateMatcher(false, false, false, null);
186    }
187
188    protected static Calendar dateToInstance(int year, int month, int day) {
189        try {
190            return GregorianCalendar.from(ZonedDateTime.of(year, month, day, 12, 0, 0, 0, ZoneOffset.UTC));
191        } catch (IllegalArgumentException | DateTimeException e) {
192            return null;
193        }
194    }
195
196}