1/*
2 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26import java.util.ArrayList;
27import java.util.HashMap;
28import java.util.List;
29import java.util.Map;
30
31/**
32 * RuleDay class represents the value of the "ON" field.  The day of
33 * week values start from 1 following the {@link java.util.Calendar}
34 * convention.
35 *
36 * @since 1.4
37 */
38class RuleDay {
39    private static final Map<String,DayOfWeek> abbreviations = new HashMap<String,DayOfWeek>(7);
40    static {
41        for (DayOfWeek day : DayOfWeek.values()) {
42            abbreviations.put(day.getAbbr(), day);
43        }
44    }
45
46    private String dayName = null;
47    private DayOfWeek dow;
48    private boolean lastOne = false;
49    private int soonerOrLater = 0;
50    private int thanDayOfMonth; // day of month (e.g., 8 for "Sun>=8")
51
52    RuleDay() {
53    }
54
55    RuleDay(int day) {
56        thanDayOfMonth = day;
57    }
58
59    int getDay() {
60        return thanDayOfMonth;
61    }
62
63    /**
64     * @return the day of week value (1-based)
65     */
66    int getDayOfWeekNum() {
67        return dow.value();
68    }
69
70    /**
71     * @return true if this rule day represents the last day of
72     * week. (e.g., lastSun).
73     */
74    boolean isLast() {
75        return lastOne;
76    }
77
78    /**
79     * @return true if this rule day represents the day of week on or
80     * later than (after) the {@link #getDay}. (e.g., Sun>=1)
81     */
82    boolean isLater() {
83        return soonerOrLater > 0;
84    }
85
86    /**
87     * @return true if this rule day represents the day of week on or
88     * earlier than (before) the {@link #getDay}. (e.g., Sun<=15)
89     */
90    boolean isEarlier() {
91        return soonerOrLater < 0;
92    }
93
94    /**
95     * @return true if this rule day represents an exact day.
96     */
97    boolean isExact() {
98        return soonerOrLater == 0;
99    }
100
101    /**
102     * Parses the "ON" field and constructs a RuleDay.
103     * @param day an "ON" field string (e.g., "Sun>=1")
104     * @return a RuleDay representing the given "ON" field
105     */
106    static RuleDay parse(String day) {
107        RuleDay d = new RuleDay();
108        if (day.startsWith("last")) {
109            d.lastOne = true;
110            d.dayName = day.substring(4);
111            d.dow = getDOW(d.dayName);
112        } else {
113            int index;
114            if ((index = day.indexOf(">=")) != -1) {
115                d.dayName = day.substring(0, index);
116                d.dow = getDOW(d.dayName);
117                d.soonerOrLater = 1; // greater or equal
118                d.thanDayOfMonth = Integer.parseInt(day.substring(index+2));
119            } else if ((index = day.indexOf("<=")) != -1) {
120                d.dayName = day.substring(0, index);
121                d.dow = getDOW(d.dayName);
122                d.soonerOrLater = -1; // less or equal
123                d.thanDayOfMonth = Integer.parseInt(day.substring(index+2));
124            } else {
125                // it should be an integer value.
126                d.thanDayOfMonth = Integer.parseInt(day);
127            }
128        }
129        return d;
130    }
131
132    /**
133     * Converts this RuleDay to the SimpleTimeZone day rule.
134     * @return the converted SimpleTimeZone day rule
135     */
136    int getDayForSimpleTimeZone() {
137        if (isLast()) {
138            return -1;
139        }
140        return isEarlier() ? -getDay() : getDay();
141    }
142
143    /**
144     * Converts this RuleDay to the SimpleTimeZone day-of-week rule.
145     * @return the SimpleTimeZone day-of-week rule value
146     */
147    int getDayOfWeekForSimpleTimeZoneInt() {
148        if (isEarlier() || isLater()) {
149            return -getDayOfWeekNum();
150        }
151        return isLast() ? getDayOfWeekNum() : 0;
152    }
153
154    /**
155     * @return the string representation of the {@link
156     * #getDayOfWeekForSimpleTimeZoneInt} value
157     */
158    String getDayOfWeekForSimpleTimeZone() {
159        int d = getDayOfWeekForSimpleTimeZoneInt();
160        if (d == 0) {
161            return "0";
162        }
163        String sign = "";
164        if (d < 0) {
165            sign = "-";
166            d = -d;
167        }
168        return sign + toString(d);
169    }
170
171    private static DayOfWeek getDOW(String abbr) {
172        return abbreviations.get(abbr);
173    }
174
175    /**
176     * Converts the specified day of week value to the day-of-week
177     * name defined in {@link java.util.Calenda}.
178     * @param dow 1-based day of week value
179     * @return the Calendar day of week name with "Calendar." prefix.
180     * @throws IllegalArgumentException if the specified dow value is out of range.
181     */
182    static String toString(int dow) {
183        if (dow >= DayOfWeek.SUNDAY.value() && dow <= DayOfWeek.SATURDAY.value()) {
184            return "Calendar." + DayOfWeek.values()[dow - 1];
185        }
186        throw new IllegalArgumentException("wrong Day_of_Week number: " + dow);
187    }
188}
189