001package org.nuxeo.ecm.platform.suggestbox.utils;
002
003import java.util.Calendar;
004import java.util.regex.Matcher;
005import java.util.regex.Pattern;
006
007import org.joda.time.Chronology;
008import org.joda.time.DateTime;
009import org.joda.time.IllegalFieldValueException;
010import org.joda.time.chrono.GregorianChronology;
011
012public class DateMatcher {
013
014    private static final Pattern YEAR_ONLY_MATCHER = Pattern.compile("^\\d{4}$");
015
016    private static final Pattern MONTH_DIGIT_ONLY_MATCHER = Pattern.compile("^\\d{2}$");
017
018    private static final Pattern YEAR_MONTHS_MATCHER = Pattern.compile("^\\d{4}[_ -:]\\d{2}$");
019
020    private static final Pattern MONTHS_YEAR_MATCHER = Pattern.compile("^\\d{2}[_ -:]\\d{4}$");
021
022    private static final Pattern MONTHS_DAY_YEAR_MATCHER = Pattern.compile("^\\d{2}[_ -:]\\d{2,}[_ -:]\\d{4}$");
023
024    private static final Pattern YEAR_MONTHS_DAY_MATCHER = Pattern.compile("^\\d{4}[_ -:]\\d{2,}[_ -:]\\d{2}$");
025
026    private boolean withYears = false;
027
028    private boolean withMonth = false;
029
030    private boolean withDay = false;
031
032    private final Calendar dateSuggestion;
033
034    private DateMatcher(boolean withYears, boolean withMonth, boolean withDay, Calendar dateSuggestion) {
035        this.withYears = withYears;
036        this.withMonth = withMonth;
037        this.withDay = withDay;
038        this.dateSuggestion = dateSuggestion;
039    }
040
041    public boolean isWithYears() {
042        return withYears;
043    }
044
045    public void setWithYears(boolean withYears) {
046        this.withYears = withYears;
047    }
048
049    public boolean isWithMonth() {
050        return withMonth;
051    }
052
053    public void setWithMonth(boolean withMonth) {
054        this.withMonth = withMonth;
055    }
056
057    public boolean isWitDay() {
058        return withDay;
059    }
060
061    public void setWitDay(boolean witDay) {
062        withDay = witDay;
063    }
064
065    public Calendar getDateSuggestion() {
066        return dateSuggestion;
067    }
068
069    public boolean hasMatch() {
070        return getDateSuggestion() != null;
071    }
072
073    public static Matcher parsingDate(Pattern pattern, String input) {
074        return pattern.matcher(input.trim());
075    }
076
077    public static DateMatcher fromInput(String input) {
078        try {
079            return doFromInput(input);
080        } catch (NumberFormatException e) {
081            return new DateMatcher(false, false, false, null);
082        }
083    }
084
085    public static DateMatcher doFromInput(String input) {
086        Matcher matcher = parsingDate(YEAR_ONLY_MATCHER, input);
087
088        if (matcher.find()) {
089            return new DateMatcher(true, false, false, dateToInstance(Integer.parseInt(matcher.group()), 1, 1));
090        }
091        matcher = parsingDate(MONTH_DIGIT_ONLY_MATCHER, input);
092        if (matcher.find()) {
093            int month = Integer.parseInt(matcher.group());
094            if (month > 12 || month < 1) {
095                return new DateMatcher(false, true, false, null);
096            }
097            return new DateMatcher(false, true, false, dateToInstance(Calendar.getInstance().get(Calendar.YEAR), month,
098                    1));
099        }
100        matcher = parsingDate(YEAR_MONTHS_MATCHER, input);
101        if (matcher.find()) {
102            int month = Integer.parseInt(matcher.group().substring(5));
103            if (month > 12 || month < 1) {
104                return new DateMatcher(true, true, false, null);
105            }
106            int year = Integer.parseInt(matcher.group().substring(0, 4));
107
108            return new DateMatcher(true, true, false, dateToInstance(year, month, 1));
109        }
110        matcher = parsingDate(MONTHS_YEAR_MATCHER, input);
111        if (matcher.find()) {
112            int month = Integer.parseInt(matcher.group().substring(0, 2));
113            if (month > 12 || month < 1) {
114                return new DateMatcher(true, true, false, null);
115            }
116            int year = Integer.parseInt(matcher.group().substring(3));
117
118            return new DateMatcher(true, true, false, dateToInstance(year, month, 1));
119
120        }
121        matcher = parsingDate(MONTHS_DAY_YEAR_MATCHER, input);
122        if (matcher.find()) {
123            int first = Integer.parseInt(matcher.group().substring(0, 2));
124            int second = Integer.parseInt(matcher.group().substring(3, 5));
125            int year = Integer.parseInt(matcher.group().substring(6));
126            int control = first + second;
127            if (control < 2 || control > 12 + 31 || first < 1 || second < 1) {
128                return new DateMatcher(true, true, true, null);
129            } else if (control < 12 + 12 + 1) {
130                return new DateMatcher(true, true, true, dateToInstance(year, first, second));
131            }
132            int month = first;
133            int day = second;
134            if (first > second) {
135                month = second;
136                day = first;
137            }
138            Calendar dateToInstance = dateToInstance(year, month, day);
139            return new DateMatcher(true, true, true, dateToInstance);
140        }
141        matcher = parsingDate(YEAR_MONTHS_DAY_MATCHER, input);
142        if (matcher.find()) {
143            int year = Integer.parseInt(matcher.group().substring(0, 4));
144            int first = Integer.parseInt(matcher.group().substring(5, 7));
145            int second = Integer.parseInt(matcher.group().substring(8));
146            int control = first + second;
147            if (control < 2 || control > 12 + 31 || first < 1 || second < 1) {
148                return new DateMatcher(true, true, true, null);
149            } else if (control < 12 + 12 + 1) {
150                return new DateMatcher(true, true, true, dateToInstance(year, first, second));
151            }
152            int month = first;
153            int day = second;
154            if (first > second) {
155                month = second;
156                day = first;
157            }
158            Calendar dateToInstance = dateToInstance(year, month, day);
159            return new DateMatcher(true, true, true, dateToInstance);
160        }
161
162        return new DateMatcher(false, false, false, null);
163    }
164
165    protected static Calendar dateToInstance(int year, int month, int day) {
166        try {
167            Chronology chrono = GregorianChronology.getInstance();
168            DateTime dt = new DateTime(year, month, day, 12, 0, 0, 0, chrono);
169            return dt.toGregorianCalendar();
170        } catch (IllegalArgumentException e) {
171            return null;
172        }
173    }
174
175}