View Javadoc

1   /*
2    * Created on 17.06.2004
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;		//internal switch is set when data is changed
34  	//private boolean isTransient= false;		//transient objects will not store dates
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));  //there seems to be a bug in java.util.Calendar
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{	//SA
131 				days[n]= Calendar.SATURDAY;
132 			}
133 		}
134 		
135 		do{
136 			//int numdays= days.length;
137 			for (int n=days.length-1;n>=0;n--){
138 				int d= days[n];
139 				cal.set(Calendar.DAY_OF_WEEK, d);
140 				//System.out.println(d+" "+cal.get(Calendar.DAY_OF_WEEK)+": "+cal.getTime()+"<>"+start);
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 				//cal.set(Calendar.WEEK_OF_MONTH, by);
173 				//cal.set(Calendar.DAY_OF_WEEK, weekday);
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 		//System.out.println(rule);
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