1
2
3
4
5 package net.stff.ical.beans;
6
7 import java.util.Calendar;
8 import java.util.Collection;
9 import java.util.Date;
10 import java.util.HashSet;
11 import java.util.Iterator;
12 import java.util.Set;
13
14 /***
15 * @author buntekuh
16 *
17 *
18 */
19 public class Recurrence {
20
21 public static final int DAILY= 1;
22 public static final int WEEKLY= 2;
23 public static final int MONTHLY= 3;
24 public static final int YEARLY= 4;
25 public static final String[] WEEKDAYS= {"SU", "MO", "TU", "WE", "TH", "FR", "SA"};
26 private Date until;
27 private int frequency;
28 private int interval= 1;
29 private String byLabel;
30 private String byValue;
31 private Set exDate;
32 private HashSet dates;
33 private boolean recompute= true;
34
35
36 public Recurrence(){
37 exDate= new HashSet();
38 }
39
40 public Recurrence(String rule){
41 exDate= new HashSet();
42 setRule(rule);
43 }
44
45 public String toString(){
46 return getRule();
47 }
48
49 public void recompute(VEvent event){
50 recompute= true;
51 getRecurrentDates(event);
52 }
53
54 public Collection getRecurrentDates(VEvent event){
55
56 if (!recompute) return dates;
57
58 HashSet newDates= new HashSet();
59 if (until == null) return newDates;
60 if (until.before(event.getDtstart())) return newDates;
61 Calendar cal= IEvent.getStartOfDay(event.getDtstart());
62 cal.setLenient(true);
63
64 try{
65 switch (frequency){
66 case DAILY:
67 setDailyDates(cal, newDates);
68 break;
69 case WEEKLY:
70 setWeeklyDates(cal, newDates);
71 break;
72 case MONTHLY:
73 setMonthlyDates(cal, newDates);
74 break;
75 case YEARLY:
76 setYearlyDates(cal, newDates);
77 break;
78 default:
79 return null;
80 }
81 }
82 catch(Exception e){
83 return null;
84 }
85
86 recompute= false;
87 dates= newDates;
88 return newDates;
89
90 }
91
92 private void setDailyDates(Calendar cal, HashSet newDates) throws Exception{
93
94 do{
95 if (!isExDate(cal.getTime())){
96 newDates.add(cal.getTime());
97 }
98 cal.add(Calendar.DAY_OF_MONTH, interval);
99 }
100 while (cal.getTime().before(until));
101
102 }
103
104 private void setWeeklyDates(Calendar cal, HashSet newDates) throws Exception{
105 cal.set(Calendar.DAY_OF_WEEK, cal.get(Calendar.DAY_OF_WEEK));
106 Date start= cal.getTime();
107 String byV[]= byValue.split(",");
108 int[] days= new int[byV.length];
109
110 for (int n= 0;n<byV.length;n++){
111 String day= byV[n];
112 if (day.equals("SU")){
113 days[n]= Calendar.SUNDAY;
114 }
115 else if (day.equals("MO")){
116 days[n]= Calendar.MONDAY;
117 }
118 else if (day.equals("TU")){
119 days[n]= Calendar.TUESDAY;
120 }
121 else if (day.equals("WE")){
122 days[n]= Calendar.WEDNESDAY;
123 }
124 else if (day.equals("TH")){
125 days[n]= Calendar.THURSDAY;
126 }
127 else if (day.equals("FR")){
128 days[n]= Calendar.FRIDAY;
129 }
130 else{
131 days[n]= Calendar.SATURDAY;
132 }
133 }
134
135 do{
136
137 for (int n=days.length-1;n>=0;n--){
138 int d= days[n];
139 cal.set(Calendar.DAY_OF_WEEK, d);
140
141 if ((!isExDate(cal.getTime()) && (cal.getTime().after(start)) && (cal.getTime().before(until)))){
142 newDates.add(cal.getTime());
143 }
144 }
145 cal.add(Calendar.WEEK_OF_YEAR, interval);
146 } while (cal.getTime().before(until));
147
148 }
149
150 private void setMonthlyDates(Calendar cal, HashSet newDates) throws Exception{
151
152 int by= -1;
153 int weekday= -1;
154 boolean byDay= ((byLabel != null) && (byLabel.equals("BYDAY")));
155 if (byDay){
156 try{
157 by= Integer.parseInt(byValue.substring(0, byValue.length() -2));
158 weekday= cal.get(Calendar.DAY_OF_WEEK_IN_MONTH);
159 }
160 catch (Exception e){
161 byDay= false;
162 }
163 }
164
165 do{
166 if (!isExDate(cal.getTime())){
167 newDates.add(cal.getTime());
168 }
169 if (byDay){
170 cal.add(Calendar.MONTH, interval);
171 cal.set(Calendar.DAY_OF_WEEK_IN_MONTH, weekday);
172
173
174 }
175 else{
176 cal.add(Calendar.MONTH, interval);
177 }
178
179 }
180 while (cal.getTime().before(until));
181
182 }
183
184 private void setYearlyDates(Calendar cal, HashSet newDates) throws Exception{
185
186 do{
187 if (!isExDate(cal.getTime())){
188 newDates.add(cal.getTime());
189 }
190 cal.add(Calendar.YEAR, interval);
191 }
192 while (cal.getTime().before(until));
193
194 }
195
196 /***
197 * @return Returns the byLabel.
198 */
199 public String getByLabel() {
200 return byLabel;
201 }
202 /***
203 * @param byLabel The byLabel to set.
204 */
205 public void setByLabel(String byLabel) {
206 recompute= true;
207 this.byLabel = byLabel;
208 }
209 /***
210 * @return Returns the byValue.
211 */
212 public String getByValue() {
213 return byValue;
214 }
215 /***
216 * @param byValue The byValue to set.
217 */
218 public void setByValue(String byValue) {
219 recompute= true;
220 this.byValue = byValue;
221 }
222 /***
223 * @return Returns the exDate.
224 */
225 public Set getExDates() {
226 return exDate;
227 }
228
229 public String getExDatesAsString(){
230 StringBuffer buff= new StringBuffer();
231
232 if (exDate == null) return null;
233 Iterator i= exDate.iterator();
234 while(i.hasNext()){
235 Date ex= (Date)i.next();
236 buff.append("EXDATE:");
237 buff.append(VEvent.dateToString(ex));
238 buff.append("\r\n");
239 }
240 return buff.toString();
241 }
242 /***
243 * @param exDate The exDate to set.
244 */
245 public void setExDates(Set exDates) {
246 exDate= new HashSet();
247 recompute= true;
248 Iterator i= exDates.iterator();
249 while (i.hasNext()){
250 Date d= (Date)i.next();
251 exDate.add(d);
252 }
253 }
254
255 public void addExdate(Date d){
256 recompute= true;
257 exDate.add(d);
258 }
259 public void removeExdate(Date d){
260 recompute= true;
261 exDate.remove(d);
262 }
263
264 /***
265 * @return Returns the frequency.
266 */
267 public int getFrequency() {
268 return frequency;
269 }
270 public String getFrequencyAsString() {
271 if (frequency == DAILY) return "DAILY";
272 if (frequency == WEEKLY) return "WEEKLY";
273 if (frequency == MONTHLY) return "MONTHLY";
274 if (frequency == YEARLY) return "YEARLY";
275 return "NOTATALL";
276 }
277 /***
278 * @param frequency The frequency to set.
279 */
280 public void setFrequency(int frequency) {
281 recompute= true;
282 this.frequency = frequency;
283 }
284 public void setFrequencyAsString(String frequency) {
285 recompute= true;
286 if (frequency.equals("DAILY")) this.frequency = Recurrence.DAILY;
287 else if (frequency.equals("WEEKLY")) this.frequency = Recurrence.WEEKLY;
288 else if (frequency.equals("MONTHLY")) this.frequency = Recurrence.MONTHLY;
289 else if (frequency.equals("YEARLY")) this.frequency = Recurrence.YEARLY;
290 }
291 /***
292 * @return Returns the interval.
293 */
294 public int getInterval() {
295 return interval;
296 }
297 /***
298 * @param interval The interval to set.
299 */
300 public void setInterval(int interval) {
301 recompute= true;
302 this.interval = interval;
303 }
304 /***
305 * @return Returns the repeatUntil.
306 */
307 public Date getUntil() {
308 return until;
309 }
310 /***
311 * @param repeatUntil The repeatUntil to set.
312 */
313 public void setUntil(Date until) {
314 recompute= true;
315 this.until = until;
316 }
317 public void setUntilDate(String date) {
318 try{
319 String[] d= date.split(VEvent.REGEX);
320 if (d.length == 3){
321 Calendar c= Calendar.getInstance();
322 c.set(Integer.parseInt(d[2]), Integer.parseInt(d[1])-1, Integer.parseInt(d[0]));
323 until= c.getTime();
324 }
325 }
326 catch(NumberFormatException e){
327 System.out.println("Variable "+date+" must represent an Integer instead.");
328 e.printStackTrace();
329 }
330 }
331 public String getUntilDate() {
332 try{
333 return VEvent.dateToString(until);
334 }
335 catch (Exception e){
336 return null;
337 }
338 }
339 /***
340 * @return Returns the rule.
341 */
342 public String getRule() {
343 StringBuffer buffer= new StringBuffer();
344
345 switch (frequency){
346 case DAILY:
347 buffer.append("FREQ=DAILY");
348 break;
349 case WEEKLY:
350 buffer.append("FREQ=WEEKLY");
351 break;
352 case MONTHLY:
353 buffer.append("FREQ=MONTHLY");
354 break;
355 case YEARLY:
356 buffer.append("FREQ=YEARLY");
357 break;
358 default:
359 return null;
360 }
361 buffer.append(";UNTIL=");
362 buffer.append(VEvent.dateToString(until));
363 buffer.append(";INTERVAL=");
364 buffer.append(interval);
365 if ((byLabel != null) && (!byLabel.equals(""))){
366 buffer.append(";");
367 buffer.append(byLabel);
368 buffer.append("=");
369 buffer.append(byValue);
370 }
371 return buffer.toString();
372 }
373
374 /***
375 * @param rule The rule to set.
376 */
377 public void setRule(String rule) {
378
379 recompute= true;
380 String rules[]= rule.split(";");
381 for(int n=0;n<rules.length;n++){
382 String[] lv= rules[n].split("=");
383 String l= lv[0];
384 if (l.equals("FREQ")){
385 if (lv[1].equals("DAILY")) setFrequency(DAILY);
386 else if (lv[1].equals("WEEKLY")) setFrequency(WEEKLY);
387 else if (lv[1].equals("MONTHLY")) setFrequency(MONTHLY);
388 else if (lv[1].equals("YEARLY")) setFrequency(YEARLY);
389 }
390 else if (l.equals("UNTIL")){
391 setUntil(VEvent.parseDate(lv[1]));
392 }
393 else if (l.equals("INTERVAL")){
394 setInterval(Integer.parseInt(lv[1]));
395 }
396 else if (l.startsWith("BY")){
397 setByLabel(l);
398 setByValue(lv[1]);
399 }
400 }
401 }
402
403 public boolean isExDate(Date d){
404 Calendar c= IEvent.getStartOfDay(d);
405 return exDate.contains(c.getTime());
406 }
407 }
408
409
410
411
412
413