1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.util;
18
19import java.util.Calendar;
20
21/**
22 * Helps answer common questions that come up when displaying a month in a
23 * 6 row calendar grid format.
24 *
25 * Not thread safe.
26 */
27public class MonthDisplayHelper {
28
29    // display pref
30    private final int mWeekStartDay;
31
32    // holds current month, year, helps compute display
33    private Calendar mCalendar;
34
35    // cached computed stuff that helps with display
36    private int mNumDaysInMonth;
37    private int mNumDaysInPrevMonth;
38    private int mOffset;
39
40
41    /**
42     * @param year The year.
43     * @param month The month.
44     * @param weekStartDay What day of the week the week should start.
45     */
46    public MonthDisplayHelper(int year, int month, int weekStartDay) {
47
48        if (weekStartDay < Calendar.SUNDAY || weekStartDay > Calendar.SATURDAY) {
49            throw new IllegalArgumentException();
50        }
51        mWeekStartDay = weekStartDay;
52
53        mCalendar = Calendar.getInstance();
54        mCalendar.set(Calendar.YEAR, year);
55        mCalendar.set(Calendar.MONTH, month);
56        mCalendar.set(Calendar.DAY_OF_MONTH, 1);
57        mCalendar.set(Calendar.HOUR_OF_DAY, 0);
58        mCalendar.set(Calendar.MINUTE, 0);
59        mCalendar.set(Calendar.SECOND, 0);
60        mCalendar.getTimeInMillis();
61
62        recalculate();
63    }
64
65
66    public MonthDisplayHelper(int year, int month) {
67        this(year, month, Calendar.SUNDAY);
68    }
69
70
71    public int getYear() {
72        return mCalendar.get(Calendar.YEAR);
73    }
74
75    public int getMonth() {
76        return mCalendar.get(Calendar.MONTH);
77    }
78
79
80    public int getWeekStartDay() {
81        return mWeekStartDay;
82    }
83
84    /**
85     * @return The first day of the month using a constants such as
86     *   {@link java.util.Calendar#SUNDAY}.
87     */
88    public int getFirstDayOfMonth() {
89        return mCalendar.get(Calendar.DAY_OF_WEEK);
90    }
91
92    /**
93     * @return The number of days in the month.
94     */
95    public int getNumberOfDaysInMonth() {
96        return mNumDaysInMonth;
97    }
98
99
100    /**
101     * @return The offset from displaying everything starting on the very first
102     *   box.  For example, if the calendar is set to display the first day of
103     *   the week as Sunday, and the month starts on a Wednesday, the offset is 3.
104     */
105    public int getOffset() {
106        return mOffset;
107    }
108
109
110    /**
111     * @param row Which row (0-5).
112     * @return the digits of the month to display in one
113     * of the 6 rows of a calendar month display.
114     */
115    public int[] getDigitsForRow(int row) {
116        if (row < 0 || row > 5) {
117            throw new IllegalArgumentException("row " + row
118                    + " out of range (0-5)");
119        }
120
121        int [] result = new int[7];
122        for (int column = 0; column < 7; column++) {
123            result[column] = getDayAt(row, column);
124        }
125
126        return result;
127    }
128
129    /**
130     * @param row The row, 0-5, starting from the top.
131     * @param column The column, 0-6, starting from the left.
132     * @return The day at a particular row, column
133     */
134    public int getDayAt(int row, int column) {
135
136        if (row == 0 && column < mOffset) {
137            return mNumDaysInPrevMonth + column - mOffset + 1;
138        }
139
140        int day = 7 * row + column - mOffset + 1;
141
142        return (day > mNumDaysInMonth) ?
143                day - mNumDaysInMonth : day;
144    }
145
146    /**
147     * @return Which row day is in.
148     */
149    public int getRowOf(int day) {
150        return (day + mOffset - 1) / 7;
151    }
152
153    /**
154     * @return Which column day is in.
155     */
156    public int getColumnOf(int day) {
157        return (day + mOffset - 1) % 7;
158    }
159
160    /**
161     * Decrement the month.
162     */
163    public void previousMonth() {
164        mCalendar.add(Calendar.MONTH, -1);
165        recalculate();
166    }
167
168    /**
169     * Increment the month.
170     */
171    public void nextMonth() {
172        mCalendar.add(Calendar.MONTH, 1);
173        recalculate();
174    }
175
176    /**
177     * @return Whether the row and column fall within the month.
178     */
179    public boolean isWithinCurrentMonth(int row, int column) {
180
181        if (row < 0 || column < 0 || row > 5 || column > 6) {
182            return false;
183        }
184
185        if (row == 0 && column < mOffset) {
186            return false;
187        }
188
189        int day = 7 * row + column - mOffset + 1;
190        if (day > mNumDaysInMonth) {
191            return false;
192        }
193        return true;
194    }
195
196
197    // helper method that recalculates cached values based on current month / year
198    private void recalculate() {
199
200        mNumDaysInMonth = mCalendar.getActualMaximum(Calendar.DAY_OF_MONTH);
201
202        mCalendar.add(Calendar.MONTH, -1);
203        mNumDaysInPrevMonth = mCalendar.getActualMaximum(Calendar.DAY_OF_MONTH);
204        mCalendar.add(Calendar.MONTH, 1);
205
206        int firstDayOfMonth = getFirstDayOfMonth();
207        int offset = firstDayOfMonth - mWeekStartDay;
208        if (offset < 0) {
209            offset += 7;
210        }
211        mOffset = offset;
212    }
213}
214