KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jical > ICalendar


1 /*
2  *
3  * Created on August 1, 2002, 9:01 PM
4  *
5  * Stores an icalendar as a java object.
6  * Included in the ICalendar is a collection of iCalendarVEvents
7  *
8  * Rules for these objects:
9  * All dates to be recorded as GMT time. ie if this is EST (Sydney) we record
10  * based on that time -11h
11  * The advantage of this is that it becomes easy to compare dates and to convert
12  * to FBURL if required...
13  *
14  * Event objects that are re-curring are expanded there and then out for
15  * a year or whatever the Max Extension parameter states.
16  *
17  *
18  * Can parse an ICalendar file and create the ICalendar Java Object from
19  * that ICalendar file.
20  *
21  * Currently, this is a partial implementation.
22  *
23  * 1) Altered method to sort FBURLS so that they are in date/time sequence, not as found.
24  *>>> Up To Here.
25  * 2) Altering logic to include a blow out of events as a vector under the name
26  * icalExpandedEventCollection. This is the true list of events for this calendar
27  * expanded for as far as the parameter dictates.
28  * 3) Represent XML version of ICalendar expanded events. The outside world has no interest
29  * in the repetition, only that the event occurs.
30  *
31  */

32
33 package org.jical;
34
35 /**
36  *
37  * @author sfg
38  * RFC 2445
39  *
40  */

41
42 import java.text.SimpleDateFormat JavaDoc;
43 import java.util.ArrayList JavaDoc;
44 import java.util.Calendar JavaDoc;
45 import java.util.Collection JavaDoc;
46 import java.util.Date JavaDoc;
47 import java.util.GregorianCalendar JavaDoc;
48 import java.util.Iterator JavaDoc;
49 import java.util.Set JavaDoc;
50 import java.util.TimeZone JavaDoc;
51 import java.util.TreeSet JavaDoc;
52 import java.util.logging.Logger JavaDoc;
53
54 public class ICalendar {
55
56     private String JavaDoc calScale;
57     private String JavaDoc prodId;
58     private String JavaDoc iCalVersion;
59     private TimeZone JavaDoc defaultTimeZone;
60     public Collection JavaDoc icaltimeZoneCollection;
61     
62     // The most important one, the list of vevents.
63
public Collection JavaDoc icalEventCollection;
64     
65     private static SimpleDateFormat JavaDoc hoursMinutes = new SimpleDateFormat JavaDoc("HHmm");
66     private static SimpleDateFormat JavaDoc formatter = new SimpleDateFormat JavaDoc("yyyyMMdd'T'HHmmss'Z'");
67     private static SimpleDateFormat JavaDoc dateFormatter = new SimpleDateFormat JavaDoc("yyyyMMddHHmmss");
68     private static SimpleDateFormat JavaDoc dateOnlyFormat = new SimpleDateFormat JavaDoc("yyyyMMdd");
69     private static SimpleDateFormat JavaDoc dayOfWeek = new SimpleDateFormat JavaDoc("EEEEEEEE");
70     private static SimpleDateFormat JavaDoc monthOfYear = new SimpleDateFormat JavaDoc("MMMMMMMMMMMM");
71     private static SimpleDateFormat JavaDoc weekNumber = new SimpleDateFormat JavaDoc("ww");
72     private static SimpleDateFormat JavaDoc dayNumber = new SimpleDateFormat JavaDoc("d");
73     private static SimpleDateFormat JavaDoc year = new SimpleDateFormat JavaDoc("yyyy");
74     private static Date JavaDoc DEFAULTSTARTDATE = new Date JavaDoc(1);
75     
76     Calendar JavaDoc repeatDateStart = new GregorianCalendar JavaDoc();
77     Calendar JavaDoc repeatDateEnd = new GregorianCalendar JavaDoc();
78     private Logger JavaDoc logger = Logger.getLogger(this.getClass().getName());
79     
80     /**
81      * The sorted Expanded Events set holds all events from repeat
82      * events sorted by startdate/uid.
83      **/

84     public Set JavaDoc sortedExpandedEvents;
85
86     /** Holds value of property organizer. */
87     private String JavaDoc organizer;
88     
89     /** Holds value of property FBUrl. */
90     private String JavaDoc FBUrl;
91     
92     /** Holds value of property organizerEmail. */
93     private String JavaDoc organizerEmail;
94
95     /** Creates a new instance of ICalendar. */
96     public ICalendar() {
97         icaltimeZoneCollection = new ArrayList JavaDoc();
98         icalEventCollection = new ArrayList JavaDoc();
99         defaultTimeZone = TimeZone.getDefault();
100         sortedExpandedEvents = new TreeSet JavaDoc( new ICalendarVEvent.StartDateUIDComparator() );
101     }
102     
103     /** Getter for property calScale.
104      * @return Value of property calScale.
105      */

106     public String JavaDoc getCalScale ()
107     {
108         return calScale;
109     }
110
111     /** Setter for property calScale.
112      * @param calScale New value of property calScale.
113      */

114     public void setCalScale (String JavaDoc calScale)
115     {
116         this.calScale = calScale;
117     }
118
119     /** Getter for property prodId.
120      * @return Value of property prodId.
121      */

122     public String JavaDoc getProdId ()
123     {
124         return prodId;
125     }
126
127     /** Setter for property prodId.
128      * @param prodId New value of property prodId.
129      */

130     public void setProdId (String JavaDoc prodId)
131     {
132         this.prodId = prodId;
133     }
134
135     /** Getter for property version.
136      * @return Value of property version.
137      */

138     public String JavaDoc getVersion()
139     {
140         return iCalVersion;
141     }
142
143     /** Setter for property version.
144      * @param iCalVersion New value of property version.
145      */

146     public void setVersion (String JavaDoc iCalVersion)
147     {
148         this.iCalVersion = iCalVersion;
149     }
150
151     /** Getter for property organizer.
152      * @return Value of property organizer.
153      */

154     public String JavaDoc getOrganizer() {
155         return this.organizer;
156     }
157     
158     /** Setter for property organizer.
159      * @param organizer New value of property organizer.
160      */

161     public void setOrganizer(String JavaDoc organizer) {
162         this.organizer = organizer;
163     }
164     
165     /** Getter for property FBUrl.
166      * @return Value of property FBUrl.
167      */

168     public String JavaDoc getFBUrl() {
169         return this.FBUrl;
170     }
171     
172     /** Setter for property FBUrl.
173      * @param FBUrl New value of property FBUrl.
174      */

175     public void setFBUrl(String JavaDoc FBUrl) {
176         this.FBUrl = FBUrl;
177     }
178     
179     /** Getter for property organizerEmail.
180      * @return Value of property organizerEmail.
181      */

182     public String JavaDoc getOrganizerEmail() {
183         return this.organizerEmail;
184     }
185     
186     /** Setter for property organizerEmail.
187      * @param organizerEmail New value of property organizerEmail.
188      */

189     public void setOrganizerEmail(String JavaDoc organizerEmail) {
190         this.organizerEmail = organizerEmail;
191     }
192     /*
193      * TODO Refactor soon
194      * This is not the optimal place for this but it works!
195      *
196      */

197     public Date JavaDoc getDateFrom(String JavaDoc dateRangeOrDaysForward) throws Exception JavaDoc
198     {
199         try
200         {
201             return (Date JavaDoc)dateFormatter.parse(dateRangeOrDaysForward.substring(0,14));
202         }
203         catch (Exception JavaDoc e)
204         {
205             throw e;
206         }
207     }
208     public Date JavaDoc getDateTo(String JavaDoc dateRangeOrDaysForward) throws Exception JavaDoc
209     {
210         // Gets the From Date
211
try
212         {
213             return (Date JavaDoc)dateFormatter.parse(dateRangeOrDaysForward.substring(15));
214         }
215         catch (Exception JavaDoc e)
216         {
217             throw e;
218         }
219     }
220     /*
221      * TODO Moved to DateTimeRange utility.
222      */

223     public long getDaysForwardNumeric(String JavaDoc dateRangeOrDaysForward) throws Exception JavaDoc
224     {
225         try
226         {
227             return java.lang.Integer.parseInt(dateRangeOrDaysForward);
228         }
229         catch (Exception JavaDoc e)
230         {
231             throw e;
232         }
233     }
234     /*
235      * TODO retire once refactored
236      */

237     public Date JavaDoc getDateToFromDaysForward(long daysForward)
238     {
239         Date JavaDoc dateTo = new Date JavaDoc();
240         long rollMicroSecs = 86400000 * daysForward;
241         dateTo.setTime(dateTo.getTime() + (rollMicroSecs));
242         return dateTo;
243     }
244
245     public void getIcalExpandedEvents(Date JavaDoc dateFrom, Date JavaDoc dateTo, String JavaDoc timeRange)
246     {
247         /*
248          * Get time ranges.
249          */

250
251         int timeFrom = 0;// new Integer(0);
252
int timeTo = 2400; //new Integer(2400);
253
if (timeRange != null)
254         {
255             timeFrom=Integer.parseInt(timeRange.substring(0,4));
256             timeTo=Integer.parseInt(timeRange.substring(5));
257         }
258
259         formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
260                 
261         for(Iterator JavaDoc i=icalEventCollection.iterator(); i.hasNext(); )
262         {
263             ICalendarVEvent icalEvent = (ICalendarVEvent)i.next();
264             Date JavaDoc dateStart = icalEvent.getDateStart();
265             Date JavaDoc dateEnd = icalEvent.getDateEnd();
266
267             if ( (dateStart.after(dateFrom)
268             && dateStart.before(dateTo))
269             || dateStart.equals(dateFrom)
270             || dateStart.equals(dateTo) )
271             {
272                 logger.fine("Create This date: "+dateStart);
273                 // This is a qualified Event with no repeat rules!
274
createExpandedEvent(dateStart, dateEnd, icalEvent, dateFrom, dateTo, timeFrom, timeTo);
275             }
276
277             if (icalEvent.getRRule() != null)
278             {
279                 logger.fine("Repeat Rule is not null");
280                 /*
281                  * Moved to parser
282                     RepeatRules rr = new RepeatRules();
283                     icalEvent.getRepeatRules().parseRepeatRules(icalEvent.getRRule());
284                 */

285                 /*
286                  * We have now parsed the repeat rules.
287                  *
288                  * Now evaluate the repeat rules all together.
289                    From RFC 2445
290
291                  Here is an example of evaluating multiple BYxxx rule parts.
292
293                         DTSTART;TZID=US-Eastern:19970105T083000
294                         RRULE:FREQ=YEARLY;INTERVAL=2;BYMONTH=1;BYDAY=SU;BYHOUR=8,9;
295                         BYMINUTE=30
296
297                         First, the "INTERVAL=2" would be applied to "FREQ=YEARLY" to arrive
298                         at "every other year". Then, "BYMONTH=1" would be applied to arrive
299                         at "every January, every other year". Then, "BYDAY=SU" would be
300                         applied to arrive at "every Sunday in January, every other year".
301                         Then, "BYHOUR=8,9" would be applied to arrive at "every Sunday in
302                         January at 8 AM and 9 AM, every other year". Then, "BYMINUTE=30"
303                         would be applied to arrive at "every Sunday in January at 8:30 AM and
304                         9:30 AM, every other year". Then, lacking information from RRULE, the
305                         second is derived from DTSTART, to end up in "every Sunday in January
306                         at 8:30:00 AM and 9:30:00 AM, every other year". Similarly, if the
307                         BYMINUTE, BYHOUR, BYDAY, BYMONTHDAY or BYMONTH rule part were
308                         missing, the appropriate minute, hour, day or month would have been
309                         retrieved from the "DTSTART" property.
310                  *
311                  *
312                  */

313
314                 // Move on to the first repeatable date.
315
Calendar JavaDoc newCal = new GregorianCalendar JavaDoc();
316                 newCal.setTime(icalEvent.getDateStart());
317                 setRepeatDateStart(newCal);
318                 newCal = new GregorianCalendar JavaDoc();
319                 newCal.setTime(icalEvent.getDateEnd());
320                 setRepeatDateEnd(newCal);
321
322                 getNextRepeatDate(icalEvent);
323                 
324                 logger.fine("Repeat Date next date: "+getRepeatDateStart().getTime()
325                         + " Interval "+icalEvent.getRepeatRules().interval
326                         + " Repeat Unit "+icalEvent.getRepeatRules().dateRepeatUnit);
327
328                 Date JavaDoc repeatUntilDate = icalEvent.getRepeatRules().repeatUntilDate;
329                 if (repeatUntilDate == null)
330                     repeatUntilDate = dateTo;
331                 if (repeatUntilDate.after(dateTo))
332                     repeatUntilDate = dateTo;
333
334                 // In case we are creating up to a counter point, record the
335
// count of events for this loop.
336
int createCtr = 0;
337
338                 while (getRepeatDateStart() != null
339                         && !getRepeatDateStart().getTime().after(repeatUntilDate))
340                 {
341                     processRepeatEvent(icalEvent.getRepeatRules(), icalEvent.getRepeatRules().dateRepeatUnit, icalEvent, dateFrom, dateTo, timeFrom, timeTo);
342                     
343                     // Next repeat date to check.
344
getNextRepeatDate(icalEvent);
345                     
346                     logger.fine("Repeat Date next date: "+repeatDateStart.getTime()
347                             + " Interval "+icalEvent.getRepeatRules().interval
348                             + " Repeat Unit "+icalEvent.getRepeatRules().dateRepeatUnit);
349
350                     //repeatDateStart.add(icalEvent.getRepeatRules().dateRepeatUnit, icalEvent.getRepeatRules().interval);
351
//repeatDateEnd.add(icalEvent.getRepeatRules().dateRepeatUnit, icalEvent.getRepeatRules().interval);
352
}
353             }
354         }
355     }
356     
357     public void getNextRepeatDate(ICalendarVEvent icalEvent)
358     {
359         logger.fine("dateStart: "+getRepeatDateStart().getTime());
360         Calendar JavaDoc newDate = getRepeatDateStart();
361         Calendar JavaDoc newDateEnd = getRepeatDateEnd();
362         if (icalEvent.getRepeatRules().dateRepeatUnit==Calendar.DAY_OF_WEEK)
363         {
364             logger.fine("DAY_OF_WEEK: "+getRepeatDateStart().getTime() + " date: "+ newDate.getTime());
365             newDate.add(Calendar.DATE, 7 * icalEvent.getRepeatRules().interval);
366             logger.fine("DAY_OF_WEEK2 : "+newDate.getTime());
367             setRepeatDateStart(newDate);
368             newDate = getRepeatDateEnd();
369             newDate.add(Calendar.DATE, 7 * icalEvent.getRepeatRules().interval);
370             setRepeatDateEnd(newDate);
371         }
372         else
373         {
374             //
375
logger.fine("about to step to next repeat event unit:"+icalEvent.getRepeatRules().dateRepeatUnit
376                     + " Interval: " +icalEvent.getRepeatRules().interval);
377             
378             newDate.add(icalEvent.getRepeatRules().dateRepeatUnit, icalEvent.getRepeatRules().interval);
379             setRepeatDateStart(newDate);
380             
381             newDateEnd.add(icalEvent.getRepeatRules().dateRepeatUnit, icalEvent.getRepeatRules().interval);
382             setRepeatDateEnd(newDateEnd);
383             logger.fine("After date add - DateStart: "+getRepeatDateStart().getTime());
384         }
385     }
386     
387     public void processRepeatEvent(RepeatRules repeatRules, int dateConstraint,
388                     ICalendarVEvent icalEvent, Date JavaDoc dateFrom, Date JavaDoc dateTo, int timeFrom, int timeTo){
389         /*
390          * @Comment. This method will process an event and see if further examination is required prior to creating
391          * an expanded event.
392          */

393         if (dateConstraint == Calendar.YEAR){
394             if (repeatRules.repeatByYearDay !=null)
395                 repeatByYearDay(repeatDateStart, repeatDateEnd, repeatRules, dateConstraint,icalEvent, dateFrom, dateTo, timeFrom, timeTo);
396             else if (repeatRules.repeatByMonth !=null)
397                 repeatByMonth(repeatDateStart, repeatDateEnd, repeatRules, dateConstraint,icalEvent, dateFrom, dateTo, timeFrom, timeTo);
398                 // Too hard at present. if (repeatRules.repeatByWeekNo !=null)
399
// repeatByWeekNo(repeatDateStart, repeatDateEnd, repeatRules, dateConstraint);
400
else {
401                 // CREATE REPEATED EVENT!!!!
402
logger.fine("Year: Create: "+getRepeatDateStart().getTime());
403                 createExpandedEvent(repeatDateStart.getTime(), repeatDateEnd.getTime(), icalEvent, dateFrom, dateTo, timeFrom, timeTo);
404             }
405         }
406         else if (dateConstraint == Calendar.MONTH)
407         {
408             logger.fine("Repeat by Month, repeat by monthday:"+repeatRules.repeatByMonthDay );
409             logger.fine("Repeat by Month, repeat by day:"+repeatRules.repeatByDay );
410             if (repeatRules.repeatByMonthDay != null)
411             {
412                 repeatByMonthDay(repeatDateStart, repeatDateEnd, repeatRules, dateConstraint, icalEvent, dateFrom, dateTo, timeFrom, timeTo);
413             }
414             else if (repeatRules.repeatByDay != null)
415             {
416                 repeatByDay(repeatRules, dateConstraint,icalEvent, dateFrom, dateTo, timeFrom, timeTo);
417             }
418             else {
419                 // CREATE REPEATED EVENT!!!!
420
logger.fine("MONTH: Create: "+getRepeatDateStart().getTime());
421                 createExpandedEvent(repeatDateStart.getTime(), repeatDateEnd.getTime(), icalEvent, dateFrom, dateTo, timeFrom, timeTo);
422             }
423         }
424         // ie. Weekly.
425
else if (dateConstraint == Calendar.DAY_OF_WEEK)
426         {
427             if (repeatRules.repeatByDay != null)
428             {
429                 logger.fine("RepeatByDay:"+repeatRules.repeatByDay);
430                 repeatByWeekDay(repeatRules, dateConstraint, icalEvent, dateFrom, dateTo, timeFrom, timeTo);
431                 logger.fine("End RepeatByDay");
432             }
433             else
434             {
435                 logger.fine("Create Weekly Event"+getRepeatDateStart().getTime());
436                 createExpandedEvent(getRepeatDateStart().getTime(), getRepeatDateEnd().getTime(), icalEvent, dateFrom, dateTo, timeFrom, timeTo);
437             }
438         }
439         else if (dateConstraint == Calendar.DATE)
440         {
441             // This is probably the lowest common denominator at present.
442
logger.fine("DATE: Create: "+getRepeatDateStart().getTime());
443             createExpandedEvent(repeatDateStart.getTime(), repeatDateEnd.getTime(), icalEvent, dateFrom, dateTo, timeFrom, timeTo);
444         }
445         else if (dateConstraint == Calendar.HOUR)
446         {
447             logger.fine("HOUR: Create: "+getRepeatDateStart().getTime());
448             createExpandedEvent(repeatDateStart.getTime(), repeatDateEnd.getTime(), icalEvent, dateFrom, dateTo, timeFrom, timeTo);
449         }
450         else if (dateConstraint == Calendar.MINUTE)
451         {
452             logger.fine("MINUTE: Create: "+getRepeatDateStart().getTime());
453             createExpandedEvent(repeatDateStart.getTime(), repeatDateEnd.getTime(), icalEvent, dateFrom, dateTo, timeFrom, timeTo);
454         }
455         else if (dateConstraint == Calendar.SECOND)
456         {
457             logger.fine("SECOND: Create: "+getRepeatDateStart().getTime());
458             createExpandedEvent(repeatDateStart.getTime(), repeatDateEnd.getTime(), icalEvent, dateFrom, dateTo, timeFrom, timeTo);
459         }
460         else {
461             logger.severe("NO MATCHING INTERVAL");
462         }
463     }
464     public void repeatByYearDay(Calendar JavaDoc repeatDateStart, Calendar JavaDoc repeatDateEnd, RepeatRules repeatRules, int dateRepeatUnit,
465                     ICalendarVEvent icalEvent, Date JavaDoc dateFrom, Date JavaDoc dateTo, int timeFrom, int timeTo)
466     {
467         /*
468          *
469          * This routine will find the days of the year for which we require to repeat this event then
470          * create zoom into those days for more rules.
471          *
472          */

473         java.util.StringTokenizer JavaDoc st = new java.util.StringTokenizer JavaDoc(repeatRules.repeatByYearDay,",");
474         while (st.hasMoreTokens())
475         {
476             String JavaDoc rule = st.nextToken();
477             int firstLast = 0;
478             int dayOfYear = 0;
479             if (rule.startsWith("-"))
480             {
481                 // We are doing the Last X thingo.
482
firstLast = 1;
483             }
484             try {
485                 dayOfYear = Integer.parseInt(rule);
486             }
487             catch (Exception JavaDoc e){
488                 logger.severe("Error parsing integer value from repeatByYearDay: " +rule);
489                 return;
490             }
491             // OK so we know what day of year, now find it!
492
Calendar JavaDoc getDate = new GregorianCalendar JavaDoc();
493             getDate.setTime(repeatDateStart.getTime());
494             if (firstLast == 0)
495             {
496                 // Set to start of year then add the days to that.
497
getDate.set(Calendar.DAY_OF_MONTH,1);
498                 getDate.set(Calendar.MONTH,1);
499                 getDate.add(Calendar.DATE,dayOfYear - 1);
500             } else
501             {
502                 getDate.set(Calendar.MONTH,Calendar.DECEMBER);
503                 getDate.set(Calendar.DAY_OF_MONTH,31);
504                 getDate.add(Calendar.DATE, -1 * dayOfYear);
505             }
506             // Now move that back to the repeat date Start/End.
507
repeatDateStart.set(Calendar.DAY_OF_MONTH, 1);
508             repeatDateStart.set(Calendar.MONTH, getDate.get(Calendar.MONTH));
509             repeatDateStart.set(Calendar.DAY_OF_MONTH, getDate.get(Calendar.DAY_OF_MONTH));
510             repeatDateEnd.set(Calendar.DAY_OF_MONTH, 1);
511             repeatDateEnd.set(Calendar.MONTH, getDate.get(Calendar.MONTH));
512             repeatDateEnd.set(Calendar.DAY_OF_MONTH, getDate.get(Calendar.DAY_OF_MONTH));
513             
514             // This Date has been selected for processing. It may require further processing based upon the
515
// further contents of the repeatRule..
516
processRepeatEvent(repeatRules, Calendar.DATE, icalEvent, dateFrom, dateTo, timeFrom, timeTo);
517         }
518     }
519     
520     public void repeatByMonthDay(Calendar JavaDoc repeatDateStart, Calendar JavaDoc repeatDateEnd, RepeatRules repeatRules, int dateRepeatUnit,
521                     ICalendarVEvent icalEvent, Date JavaDoc dateFrom, Date JavaDoc dateTo, int timeFrom, int timeTo)
522     {
523         /*
524          *
525          * This routine will find the days of the Month for which we require to repeat this event then
526          *
527          */

528         java.util.StringTokenizer JavaDoc st = new java.util.StringTokenizer JavaDoc(repeatRules.repeatByMonthDay,",");
529         while (st.hasMoreTokens())
530         {
531             String JavaDoc rule = st.nextToken();
532             int firstLast = 0;
533             int dayOfMonth = 0;
534             
535             logger.fine("rule:"+rule);
536             
537             if (rule.startsWith("-"))
538             {
539                 // We are doing the Last X thingo.
540
firstLast = 1;
541             }
542             try {
543                 dayOfMonth = Integer.parseInt(rule);
544             }
545             catch (Exception JavaDoc e){
546                 logger.severe("Error parsing integer value from repeatByYearDay: " +rule);
547                 return;
548             }
549             // OK so we know what day of year, now find it!
550
Calendar JavaDoc getDate = new GregorianCalendar JavaDoc();
551             getDate.setTime(repeatDateStart.getTime());
552             if (firstLast == 0)
553             {
554                 // Set to start of year then add the days to that.
555
getDate.set(Calendar.DAY_OF_MONTH,1);
556                 getDate.add(Calendar.DATE,dayOfMonth-1);
557             } else
558             {
559                 // Get the last day of the month by going forward a month then back a day.
560
getDate.set(Calendar.DAY_OF_MONTH,1);
561                 getDate.add(Calendar.MONTH,1);
562                 getDate.add(Calendar.DATE,-1);
563                 // Now we are on the last day of the month, subtract the days (+1).
564
getDate.set(Calendar.DATE,1+dayOfMonth);
565             }
566             // Now move that back to the repeat date Start/End.
567
repeatDateStart.set(Calendar.DAY_OF_MONTH, 1);
568             repeatDateStart.set(Calendar.MONTH, getDate.get(Calendar.MONTH));
569             repeatDateStart.set(Calendar.DAY_OF_MONTH, getDate.get(Calendar.DAY_OF_MONTH));
570             repeatDateEnd.set(Calendar.DAY_OF_MONTH, 1);
571             repeatDateEnd.set(Calendar.MONTH, getDate.get(Calendar.MONTH));
572             repeatDateEnd.set(Calendar.DAY_OF_MONTH, getDate.get(Calendar.DAY_OF_MONTH));
573             
574             // This Date has been selected for processing. It may require further processing based upon the
575
// further contents of the repeatRule..
576
processRepeatEvent(repeatRules, Calendar.DATE, icalEvent, dateFrom, dateTo, timeFrom, timeTo);
577         }
578     }
579     
580     public void repeatByMonth(Calendar JavaDoc repeatDateStart, Calendar JavaDoc repeatDateEnd, RepeatRules repeatRules, int dateRepeatUnit,
581                     ICalendarVEvent icalEvent, Date JavaDoc dateFrom, Date JavaDoc dateTo, int timeFrom, int timeTo)
582     {
583         /*
584          *
585          * This routine will find the days of the year for which we require to repeat this event then
586          * zoom into those days for more rules.
587          *
588          */

589         java.util.StringTokenizer JavaDoc st = new java.util.StringTokenizer JavaDoc(repeatRules.repeatByMonth,",");
590         while (st.hasMoreTokens())
591         {
592             int monthOfYear = 0;
593             String JavaDoc rule = st.nextToken();
594             try
595             {
596                 monthOfYear = Integer.parseInt(rule);
597             }
598             catch (Exception JavaDoc e)
599             {
600                 logger.severe("Error parsing integer value from repeatByYearDay: " +rule);
601                 return;
602             }
603             
604             // Now move that back to the repeat date Start/End.
605

606             //logger.severe(repeatDateStart.getTime());
607
repeatDateStart.set(Calendar.MONTH, monthOfYear - 1);
608             if (repeatDateStart.get(Calendar.MONTH) != monthOfYear - 1)
609             {
610                 
611                 logger.severe("Error setting MonthOfYear for date: " +repeatDateStart.getTime()
612                                     +" to Month "+ monthOfYear
613                                     +" From DateStartMonth"+repeatDateStart.get(Calendar.MONTH)
614                                     +" Event: "+ icalEvent.getSummary());
615                 return;
616             }
617
618             //logger.severe(repeatDateEnd.getTime());
619
repeatDateEnd.set(Calendar.MONTH, monthOfYear - 1);
620             if (repeatDateEnd.get(Calendar.MONTH) != monthOfYear - 1)
621             {
622                 logger.severe("Error setting MonthOfYear for date: " +repeatDateEnd.getTime()
623                                     +" to Month "+ monthOfYear
624                                     +" From DateEndMonth"+repeatDateEnd.get(Calendar.MONTH)
625                                     +" Event: "+ icalEvent.getSummary());
626                 return;
627             }
628             // This Date has been selected for processing. It may require further processing based upon the
629
// further contents of the repeatRule..
630
processRepeatEvent(repeatRules, Calendar.MONTH, icalEvent, dateFrom, dateTo, timeFrom, timeTo);
631         }
632     }
633     /*
634      * Introduced to get weekly multi-day repeats correct.
635      */

636     public void repeatByWeekDay(RepeatRules repeatRules, int dateRepeatUnit,
637             ICalendarVEvent icalEvent, Date JavaDoc dateFrom, Date JavaDoc dateTo, int timeFrom, int timeTo)
638     {
639         
640         // Assumes starting date is set as repeatDateStart
641
// Does NOT increment it as we need to enable iterating through week but NOT upsetting the
642
// overall week incrementer.
643
java.util.StringTokenizer JavaDoc st = new java.util.StringTokenizer JavaDoc(repeatRules.repeatByDay,",");
644         while (st.hasMoreTokens())
645         {
646             
647             String JavaDoc rule = st.nextToken();
648             int dayOfWeek = ("SUMOTUWETHFRSA".indexOf(rule.substring(0,2)) / 2) + 1;
649             if (dayOfWeek == -1)
650                 return;
651             
652             // Find this DOW in the next 7 days..
653
int iDayCtr = 0;
654             Calendar JavaDoc workDateFrom = new GregorianCalendar JavaDoc();
655             workDateFrom.setTime(repeatDateStart.getTime());
656             Calendar JavaDoc workDateTo = new GregorianCalendar JavaDoc();
657             workDateTo.setTime(repeatDateEnd.getTime());
658             logger.fine("Going to loop 7 days from "+workDateFrom.getTime() +" as long as "+workDateTo.getTime()+ " is before "+dateTo
659                     +" and this" +!workDateTo.equals(dateTo)+ " is true");
660             // Loop through the 7 days and create for this day..
661
while(iDayCtr <= 7 && ( workDateTo.getTime().before(dateTo) && !workDateTo.equals(dateTo)))
662             {
663                 iDayCtr++;
664                 workDateFrom.add(Calendar.DATE,1);
665                 workDateTo.add(Calendar.DATE,1);
666                 logger.fine("Up to "+workDateFrom.getTime());
667                 if (workDateFrom.get(Calendar.DAY_OF_WEEK) == dayOfWeek)
668                 {
669                     logger.fine("Create expanded event "+workDateFrom.getTime());
670                     createExpandedEvent(workDateFrom.getTime(), workDateTo.getTime(), icalEvent, dateFrom, dateTo, timeFrom, timeTo);
671                     // found this dow so next dow of concern
672
break;
673                 }
674             }
675             
676         }
677         
678     }
679     public void repeatByDay(RepeatRules repeatRules, int dateRepeatUnit,
680                     ICalendarVEvent icalEvent, Date JavaDoc dateFrom, Date JavaDoc dateTo, int timeFrom, int timeTo)
681     {
682         /*
683          *
684          * This routine will find the days of the year for which we require to repeat this event then
685          * create zoom into those days for more rules.
686          *
687          */

688         java.util.StringTokenizer JavaDoc st = new java.util.StringTokenizer JavaDoc(repeatRules.repeatByDay,",");
689         while (st.hasMoreTokens())
690         {
691             String JavaDoc rule = st.nextToken();
692             
693             logger.fine("Next Rule: "+rule);
694             
695             int firstLast = 0;
696             int sequenceInMonth = 9999;
697             int dayOfWeek = 0;
698
699             Calendar JavaDoc workDateFrom = new GregorianCalendar JavaDoc();
700             workDateFrom.setTime(repeatDateStart.getTime());
701             Calendar JavaDoc workDateTo = new GregorianCalendar JavaDoc();
702             workDateTo.setTime(repeatDateEnd.getTime());
703
704             if (rule.startsWith("-"))
705             {
706                 // We are doing the Last X thingo.
707
firstLast = 1;
708                 try{
709                     sequenceInMonth = Integer.parseInt(rule.substring(1,1));
710                     //dayOfWeek = ("SUMOTUWETHFRSA".indexOf(rule.substring(2,2)) / 2) + 1;
711
// Fix a bug where the wrong index was being used in
712
// the substring for the dayOfWeek
713
dayOfWeek = ("SUMOTUWETHFRSA".indexOf(rule.substring(2,4)) / 2) + 1;
714                 }
715                 catch(Exception JavaDoc e){
716                     logger.severe("Error Parsing Day RRULE, rule: " +rule);
717                     e.printStackTrace(System.err);
718                     return;
719                 }
720             }
721             //else if ("0123456789".indexOf(rule.substring(0)) != -1)
722
else if ("0123456789".indexOf(rule.substring(0,1)) != -1)
723             {
724                 try{
725                     // We have a 1st/last Sunday in Jan type of situ.
726
sequenceInMonth = Integer.parseInt(rule.substring(0));
727                     dayOfWeek = ("SUMOTUWETHFRSA".indexOf(rule.substring(1,2)) / 2) + 1;
728                 }
729                 catch(Exception JavaDoc e){
730                     logger.severe("Error Parsing Day RRULE, rule: " +rule);
731                     e.printStackTrace(System.err);
732                     return;
733                 }
734             }
735             else
736             {
737                 // A (not so) simple day of week.
738
dayOfWeek = ("SUMOTUWETHFRSA".indexOf(rule.substring(0,2)) / 2) + 1;;
739             }
740             
741             logger.fine("RepeatRulesBySetPos"+repeatRules.repeatBySetPos);
742             if (repeatRules.repeatBySetPos != null){
743                 sequenceInMonth = repeatRules.getRepeatBySetPos().intValue();
744             }
745             
746             /*
747              * Now check the RepeatByDay rule for days of the week.
748              * If it exists, create an event for each of those days subject to
749              * date range etc, etc
750              *
751              */

752             
753              // First the repeated day of week.. ie MO,TU etc.
754
if (sequenceInMonth == 9999){
755                  if (dateRepeatUnit == Calendar.MONTH) {
756                     // Run through the month and processEvent every Calendar Day that matches.
757
// This is like the 3rd Monday in the Month type of thing.
758
int thisMonth = workDateFrom.get(Calendar.MONTH);
759                     while (workDateFrom.get(Calendar.MONTH) == thisMonth)
760                     {
761                         if (workDateFrom.get(Calendar.DAY_OF_WEEK) == dayOfWeek)
762                         {
763                             setRepeatDateStart(workDateFrom);
764                             setRepeatDateEnd(workDateTo);
765                             processRepeatEvent(repeatRules, Calendar.DATE, icalEvent, dateFrom, dateTo, timeFrom, timeTo);
766                         }
767                         workDateFrom.add(Calendar.DATE, 1);
768                         workDateTo.add(Calendar.DATE, 1);
769                         setRepeatDateStart(workDateFrom);
770                         setRepeatDateEnd(workDateTo);
771                     }
772                  }
773                  if (dateRepeatUnit == Calendar.DAY_OF_WEEK) {
774                      // Run through the days of the week and create an event for the day inferred.
775
// Like Every Monday type of thing.
776
int weekCount = 1;
777                      while (weekCount < 8)
778                      {
779                         if (workDateFrom.get(Calendar.DAY_OF_WEEK) == dayOfWeek)
780                             processRepeatEvent(repeatRules, Calendar.MONTH, icalEvent, dateFrom, dateTo, timeFrom, timeTo);
781                         workDateFrom.add(Calendar.DATE,1);
782                         workDateTo.add(Calendar.DATE,1);
783                         setRepeatDateStart(workDateFrom);
784                         setRepeatDateEnd(workDateTo);
785                         weekCount++;
786                     }
787                  }
788             }
789             else
790             {
791                 logger.fine("Attempting nth DD in Month from "+ workDateFrom.getTime());
792                 // Looking for the xth Sunday of the month etc etc.
793
Calendar JavaDoc getDate = new GregorianCalendar JavaDoc();
794                 getDate.setTime(workDateFrom.getTime());
795                 int thisMonth = workDateFrom.get(Calendar.MONTH);
796                 int dayIncrement = 0;
797                 int occuranceCtr = 0;
798                 logger.fine("sequenceInMonth: "+sequenceInMonth);
799                 if (sequenceInMonth < 0)
800                 {
801                     // Set last day of month.
802
getDate.set(Calendar.DAY_OF_MONTH,1);
803                     // Add one month,
804
getDate.add(Calendar.MONTH,1);
805                     // Substract 1 day should get last day of month.
806
getDate.add(Calendar.DATE,-1);
807                     logger.fine("Start from last day of month: "+getDate.getTime());
808                     // This determines that we are counting BACKWARDS.
809
dayIncrement = -1;
810                     
811                 }
812                 else {
813                     getDate.set(Calendar.DAY_OF_MONTH,1);
814                     dayIncrement = +1;
815                 }
816
817                 while (getDate.get(Calendar.MONTH) == thisMonth)
818                 {
819                     if (getDate.get(Calendar.DAY_OF_WEEK) == dayOfWeek)
820                     {
821                         logger.fine("Found that day of week:"+getDate.getTime());
822                         
823                         occuranceCtr++;
824                         if (occuranceCtr == sequenceInMonth * dayIncrement)
825                         {
826                             workDateFrom.set(Calendar.DAY_OF_MONTH, getDate.get(Calendar.DAY_OF_MONTH));
827                             workDateTo.set(Calendar.DAY_OF_MONTH, getDate.get(Calendar.DAY_OF_MONTH));
828                             setRepeatDateStart(workDateFrom);
829                             setRepeatDateEnd(workDateTo);
830                             logger.fine("Found one!"+workDateFrom);
831                             processRepeatEvent(repeatRules, Calendar.DATE, icalEvent, dateFrom, dateTo, timeFrom, timeTo);
832                             return;
833                         }
834                     }
835                     
836                     getDate.add(Calendar.DATE,dayIncrement);
837                     logger.fine("Next date is : "+getDate.getTime());
838                 }
839             }
840              
841         } // Has More Days to process.
842
}
843     public void createExpandedEvent(Date JavaDoc dateStartIn, Date JavaDoc dateEndIn, ICalendarVEvent iCalEventIn, Date JavaDoc dateFrom, Date JavaDoc dateTo, int timeFrom, int timeTo)
844     {
845         /*
846          * Moved repeat Exception check to where all repeat events are created.
847          */

848         
849         logger.fine("Create Expanded Event: "+dateStartIn);
850         
851         // Fix a NPE for repeating event with no end
852
if (dateEndIn == null) {
853             dateEndIn = iCalEventIn.getDateEnd();
854         }
855         
856         // Make sure date of event is within the date range we want
857
if (dateEndIn.before(dateFrom) || dateStartIn.after(dateTo))
858             return;
859         
860         
861         
862         int testTimeStart = Integer.parseInt(hoursMinutes.format(dateStartIn));
863         int testTimeEnd = Integer.parseInt(hoursMinutes.format(dateEndIn));
864
865        /* There are four conditions for inclusion of this event
866          in this day based on a time range.
867          1) Runs right across this date and others.
868         * ie day 23/2/2004. Event goes 22/2/2004 to 25/2/2004
869          2) Falls within the day
870         ** ie day 23/2/2004. Event goes 23/2/2004 to 23/2/2004
871          3) End period falls within the start day point or
872         * ie day 23/2/2004. Event goes 22/2/2004 to 23/2/2004 5am
873          4) Start period falls within the end day point.
874         * ie day 23/2/2004. Event goes 23/2/2004 12 noon to 25/2/2004
875         */

876         
877         // Condition 1.
878
if ( testTimeStart < timeFrom
879         && testTimeEnd > timeTo){}
880         // Condition 2.
881
else if (testTimeStart >= timeFrom
882         && testTimeEnd <= timeTo){}
883         // Condition 3.
884
else if (testTimeEnd > timeTo
885         && testTimeStart <= timeTo) {}
886         // Condition 4.
887
else if (testTimeEnd >= timeFrom
888         && testTimeStart < timeFrom) {}
889         // All Day Event!!
890
else if (testTimeStart == 0
891         && testTimeEnd == 0) {}
892         else
893             return;
894         
895         if (iCalEventIn.isExDatesExist())
896         {
897             boolean foundExDate = false;
898
899             for(Iterator JavaDoc itr=iCalEventIn.exDateCollection.iterator(); itr.hasNext(); )
900             {
901                 String JavaDoc exDate = (String JavaDoc)itr.next();
902                 // Bug fix 2004/10
903
if (exDate.startsWith(dateOnlyFormat.format(dateStartIn)))
904                    return;
905             }
906         }
907         
908         if (iCalEventIn.getRepeatRules().repeatUntilCount <= iCalEventIn.getRepeatCount())
909         {
910             return;
911         }
912
913         iCalEventIn.setRepeatCount(iCalEventIn.getRepeatCount()+1);
914         try {
915             ICalendarVEvent iCalEventNew = (ICalendarVEvent) iCalEventIn.clone();
916             iCalEventNew.setDateStart(dateStartIn);
917             iCalEventNew.setDateEnd(dateEndIn);
918             
919             if ((iCalEventNew.getOrganizer() == null || iCalEventNew.getOrganizer().length() == 0) &&
920                (iCalEventNew.getOrganizer() == null || iCalEventNew.getOrganizer().length() == 0))
921             {
922                 //iCalEventNew.setOrganizer(getOrganizer());
923
iCalEventNew.setOrganizer(getOrganizer());
924             }
925             // Make sure single custom events for a recurring event are added
926
if (sortedExpandedEvents.contains(iCalEventNew))
927             {
928                 if (iCalEventNew.isRecurrenceId())
929                 {
930                     // Replace default recurring event with a custom single occurrence
931
sortedExpandedEvents.remove(iCalEventNew);
932                  }
933             }
934             sortedExpandedEvents.add( iCalEventNew );
935             
936             logger.fine("Create This date: "+dateStartIn);
937             logger.fine("Create UID: "+iCalEventNew.getUid());
938             logger.fine("RepeatSummary: "+iCalEventNew.getSummary());
939         }
940         catch ( Exception JavaDoc ex ) {
941             logger.severe(ex.toString());
942             ex.printStackTrace();
943         }
944         
945         
946         
947     }
948     
949     public String JavaDoc getFBString(String JavaDoc dateRangeOrDaysForward) throws Exception JavaDoc
950     {
951         Date JavaDoc dateFrom = null;
952         Date JavaDoc dateTo = null;
953         try
954         {
955             long daysForward = getDaysForwardNumeric(dateRangeOrDaysForward);
956             try
957             {
958                 return getFBString(daysForward);
959             }
960             catch (Exception JavaDoc e)
961             {
962                 logger.severe("Cannot create FBURL due to error: " +e);
963                 return "";
964             }
965         }
966         catch (Exception JavaDoc e)
967         {
968             try
969             {
970                 dateFrom = getDateFrom(dateRangeOrDaysForward);
971                 dateTo = getDateTo(dateRangeOrDaysForward);
972                 
973             }
974             catch (Exception JavaDoc ee)
975             {
976                 logger.severe("1.Unable to read your input dates: "
977                                     + dateRangeOrDaysForward
978                                     + "They must be of the form ccYYmmDDhhMMss-ccYYmmDDhhMMss"
979                                     + ee);
980                 throw ee;
981             }
982         }
983         return getFBString(dateFrom , dateTo);
984     }
985     
986     public String JavaDoc getFBString(long daysForward)
987     {
988         Date JavaDoc dateFrom = new Date JavaDoc();
989         Date JavaDoc dateTo = getDateToFromDaysForward(daysForward);
990         /*
991          * Currently, keep this dateFrom/To as coarse. ie, dateFrom/To are DAYS not DAY/HH:MM
992          * ie for FROM date, set to time of 0000, for TO date set to time of 235959
993          */

994         try
995         {
996             dateFrom = (Date JavaDoc)dateOnlyFormat.parse(dateOnlyFormat.format(dateFrom));
997             dateTo = (Date JavaDoc)dateFormatter.parse(dateOnlyFormat.format(dateTo) + "235959");
998         }
999         catch (Exception JavaDoc e)
1000        {
1001            logger.severe(e.toString());
1002        }
1003        return getFBString(dateFrom, dateTo);
1004    }
1005    
1006    public String JavaDoc getFBString(Date JavaDoc dateFrom, Date JavaDoc dateTo)
1007    {
1008        /* Build a FBURL String for submitting to somewhere.
1009         * Remember to take into account all repeating events.
1010         */

1011        
1012        /* Read through all Vevents.
1013            The following is an example of a "VFREEBUSY" calendar component used
1014            to publish busy time information. *
1015                 FREEBUSY;FBTYPE=BUSY-UNAVAILABLE:19970308T160000Z/PT8H30M
1016                 FREEBUSY;FBTYPE=FREE:19970308T160000Z/PT3H,19970308T200000Z/PT1H
1017                 FREEBUSY;FBTYPE=FREE:19970308T160000Z/PT3H,19970308T200000Z/PT1H,
1018                  19970308T230000Z/19970309T000000Z
1019         
1020                 BEGIN:VFREEBUSY
1021                 ORGANIZER:jsmith@host.com
1022                 DTSTART:19980313T141711Z
1023                 DTEND:19980410T141711Z
1024                 FREEBUSY:19980314T233000Z/19980315T003000Z
1025                 FREEBUSY:19980316T153000Z/19980316T163000Z
1026                 FREEBUSY:19980318T030000Z/19980318T040000Z
1027                 URL:http://www.host.com/calendar/busytime/jsmith.ifb
1028                 END:VFREEBUSY
1029         */

1030        if (this.getFBUrl() == null
1031        || this.getOrganizerEmail() == null
1032        || this.getOrganizer() == null) {
1033            logger.severe("Cannot create FBURL unless FBURL, OrganizerEmail are Organizer provided to ICalendar");
1034            return "";
1035        }
1036        
1037        StringBuffer JavaDoc FBString = new StringBuffer JavaDoc("BEGIN:VCALENDAR\nBEGIN:VFREEBUSY\n");
1038        FBString.append("ORGANIZER:").append(this.getOrganizerEmail()).append("\n");
1039        FBString.append("DTSTART:").append(formatter.format(dateFrom)).append("\n");
1040        FBString.append("DTEND:").append(formatter.format(dateTo)).append("\n");
1041        
1042        // Must always work out expanded events from year dot as otherwise previous
1043
// dates where they repeat into this date range are missed.
1044

1045        Date JavaDoc trueStartDate = new Date JavaDoc(0);
1046        
1047        // 2004-10 patch - um. Don't think this is right.. Ignored.
1048
//Fix bug where expanded events were only generated from the
1049
//current time rather than from the start date jical was started with
1050
// getIcalExpandedEvents(null);
1051

1052        
1053        
1054        
1055        getIcalExpandedEvents(trueStartDate, dateTo, null);
1056
1057        Iterator JavaDoc eeIterator = sortedExpandedEvents.iterator();
1058        while (eeIterator.hasNext())
1059        {
1060        ICalendarVEvent icalEvent = (ICalendarVEvent) eeIterator.next();
1061        
1062            /* There are four conditions for inclusion of this event
1063             in this day.
1064             1) Runs right across this date and others.
1065             * ie day 23/2/2004. Event goes 22/2/2004 to 25/2/2004
1066             2) Falls within the day
1067             ** ie day 23/2/2004. Event goes 23/2/2004 to 23/2/2004
1068             3) End period falls within the start day point or
1069             * ie day 23/2/2004. Event goes 22/2/2004 to 23/2/2004 5am
1070             4) Start period falls within the end day point.
1071             * ie day 23/2/2004. Event goes 23/2/2004 12 noon to 25/2/2004
1072            */

1073            Date JavaDoc icalDateStart = icalEvent.getDateStart();
1074            Date JavaDoc icalDateEnd = icalEvent.getDateEnd();
1075
1076            /*
1077             * Whole day events are not handled well with this method as they run
1078             * exactly on the 24hr time line. We need to recognise them and
1079             * for the purposes of testing conditions, reduce the seconds so
1080             * that they fit within a day.
1081             */

1082            Date JavaDoc thisTimeFrom = dateFrom;
1083            Date JavaDoc thisTimeTo = dateTo;
1084
1085            // Condition 1.
1086
if ((thisTimeFrom.after(icalDateStart)
1087            || thisTimeFrom.equals(icalDateStart))
1088            && (thisTimeTo.before(icalDateEnd)
1089            || thisTimeTo.equals(icalDateEnd)))
1090            {
1091                // Create an all day event as this event wraps this day and others.
1092
icalEvent.setDateStart(thisTimeFrom);
1093                icalEvent.setDateEnd(thisTimeTo);
1094                FBString.append(createFBRow(formatter, icalEvent.getDateStart(), icalEvent.getDateEnd()));
1095            }
1096            // Condition 2.
1097
else if (thisTimeFrom.before(icalDateStart)
1098            && thisTimeTo.after(icalDateEnd))
1099            {
1100                // Create event as is.
1101
FBString.append(createFBRow(formatter, icalEvent.getDateStart(), icalEvent.getDateEnd()));
1102            }
1103            // Condition 3.
1104
else if (thisTimeFrom.before(icalDateEnd)
1105            && thisTimeTo.after(icalDateEnd))
1106            {
1107                // Create event with end time as thisTimeTo, start time as speced.
1108
icalEvent.setDateStart(thisTimeFrom);
1109                icalEvent.setDateEnd(icalDateEnd);
1110                FBString.append(createFBRow(formatter, icalEvent.getDateStart(), icalEvent.getDateEnd()));
1111            }
1112            // Condition 4.
1113
else if (thisTimeFrom.before(icalDateStart)
1114            && thisTimeTo.after(icalDateStart))
1115            {
1116                // Create event with starttime time as thisTimeFrom, end time as speced.
1117
icalEvent.setDateStart(icalDateStart);
1118                icalEvent.setDateEnd(thisTimeTo);
1119                FBString.append(createFBRow(formatter, icalEvent.getDateStart(), icalEvent.getDateEnd()));
1120            }
1121            else {
1122                //Event rejected for this date
1123
}
1124        }
1125
1126        //URL:http://www.host.com/calendar/busytime/jsmith.ifb
1127
FBString.append("URL:");
1128        FBString.append( this.getFBUrl()); // Expect this to start with http:// and end in /
1129
FBString.append( this.getOrganizer());
1130        FBString.append( ".ifb");
1131        FBString.append( "\n");
1132        FBString.append( "END:VFREEBUSY\nEND:VCALENDAR");
1133        FBString.append( "\n");
1134        return FBString.toString();
1135    }
1136    
1137    public String JavaDoc createFBRow(SimpleDateFormat JavaDoc formatter, Date JavaDoc repeatDateStart, Date JavaDoc repeatDateEnd)
1138    {
1139        StringBuffer JavaDoc FBData = new StringBuffer JavaDoc();
1140        FBData.append("FREEBUSY;FBTYPE=BUSY:");
1141        FBData.append(formatter.format(repeatDateStart));
1142        FBData.append("/");
1143        FBData.append(formatter.format(repeatDateEnd));
1144        FBData.append("\n");
1145        return FBData.toString();
1146    }
1147    
1148    /*
1149     * This returns the whole calendar as a string.
1150     * Of course, if you haven't filled in all the required bits,
1151     * it will be unreadable.
1152     */

1153    public String JavaDoc getVCalendar()
1154    {
1155        StringBuffer JavaDoc vCalBuffer = new StringBuffer JavaDoc();
1156        vCalBuffer.append(ICalUtil.makeVEventLines("BEGIN:VCALENDAR",""));
1157        vCalBuffer.append(ICalUtil.makeVEventLines("PRODID:",this.getProdId()));
1158        vCalBuffer.append(ICalUtil.makeVEventLines("VERSION:",this.getVersion()));
1159        vCalBuffer.append("\n");
1160        
1161        // Now loop through the current collection of VEVENTs and append them to the ultimate buffer.
1162
for(Iterator JavaDoc i=icalEventCollection.iterator(); i.hasNext(); )
1163        {
1164            ICalendarVEvent icalEvent = (ICalendarVEvent)i.next();
1165            vCalBuffer.append(icalEvent.toVEvent()).append("\n");
1166        }
1167        
1168        vCalBuffer.append(ICalUtil.makeVEventLines("END:VCALENDAR",""));
1169
1170        return vCalBuffer.toString();
1171    }
1172    
1173    
1174    public String JavaDoc getJiCalXML(String JavaDoc dateRangeOrDaysForward, String JavaDoc timeRange) throws Exception JavaDoc
1175    {
1176        Date JavaDoc dateFrom = null;
1177        Date JavaDoc dateTo = null;
1178        try
1179        {
1180            long daysForward = getDaysForwardNumeric(dateRangeOrDaysForward);
1181            try
1182            {
1183                return getJiCalXML(daysForward, timeRange);
1184            }
1185            catch (Exception JavaDoc e)
1186            {
1187                logger.severe("Error:" + e);
1188            }
1189        }
1190        catch (Exception JavaDoc e)
1191        {
1192            try
1193            {
1194                dateFrom = getDateFrom(dateRangeOrDaysForward);
1195                dateTo = getDateTo(dateRangeOrDaysForward);
1196                
1197            }
1198            catch (Exception JavaDoc ee)
1199            {
1200                logger.severe("Unable to read your input dates: "
1201                                    + dateRangeOrDaysForward
1202                                    + "They must be of the form ccYYmmDDhhMMss-ccYYmmDDhhMMss"
1203                                    + ee);
1204                throw ee;
1205            }
1206        }
1207        return getJiCalXML(dateFrom , dateTo, timeRange);
1208    }
1209    public String JavaDoc getJiCalXML(long daysForward, String JavaDoc timeRange)
1210    {
1211        Date JavaDoc dateFrom = new Date JavaDoc();
1212        Date JavaDoc dateTo = getDateToFromDaysForward(daysForward);
1213
1214        /*
1215         * Currently, keep this dateFrom/To as coarse. ie, dateFrom/To are DAYS not DAY/HH:MM
1216         * ie for FROM date, set to time of 0000, for TO date set to time of 235959
1217         */

1218        try
1219        {
1220            dateFrom = (Date JavaDoc)dateOnlyFormat.parse(dateOnlyFormat.format(dateFrom));
1221            dateTo = (Date JavaDoc)dateFormatter.parse(dateOnlyFormat.format(dateTo) + "235959");
1222        }
1223        catch (Exception JavaDoc e)
1224        {
1225        }
1226        return getJiCalXML(dateFrom, dateTo, timeRange);
1227    }
1228
1229    public String JavaDoc getJiCalXML(Date JavaDoc dateFrom, Date JavaDoc dateTo, String JavaDoc timeRange)
1230    {
1231        if (this.getOrganizerEmail() == null
1232        || this.getOrganizer() == null) {
1233            logger.severe("Cannot create XML unless OrganizerEmail are Organizer provided to ICalendar");
1234            return "";
1235        }
1236
1237        /*
1238         * XML Initial take
1239         * This is NOT a version of XCAL as it unravels the events to their
1240         * detail level. It is more useful for rendering as HTML or PDF an
1241         * Evolution Calendar.
1242         *
1243         */

1244
1245        StringBuffer JavaDoc XMLString= new StringBuffer JavaDoc("<jicalxml>\n");
1246        XMLString.append("\t<organizer>").append( this.getOrganizer()).append("</organizer>\n");
1247        XMLString.append("\t<organizeremail>").append(this.getOrganizerEmail()).append("</organizeremail>\n");
1248        XMLString.append("\t<datestart>").append(dateFormatter.format(dateFrom)).append("</datestart>\n");
1249        XMLString.append("\t<dateend>").append(dateFormatter.format(dateTo)).append("</dateend>\n");
1250        XMLString.append("<vevents>\n");
1251        /*
1252         * Modified to make sure repeat events pick up EVERYTHING!
1253         */

1254        Date JavaDoc trueStartDate = new Date JavaDoc(0);
1255        getIcalExpandedEvents(trueStartDate, dateTo, timeRange);
1256
1257        Iterator JavaDoc eeIterator = sortedExpandedEvents.iterator();
1258        while (eeIterator.hasNext())
1259        {
1260        ICalendarVEvent icalEvent = (ICalendarVEvent) eeIterator.next();
1261            /* There are four conditions for inclusion of this event
1262             in this day.
1263             1) Runs right across this date and others.
1264             * ie day 23/2/2004. Event goes 22/2/2004 to 25/2/2004
1265             2) Falls within the day
1266             ** ie day 23/2/2004. Event goes 23/2/2004 to 23/2/2004
1267             3) End period falls within the start day point or
1268             * ie day 23/2/2004. Event goes 22/2/2004 to 23/2/2004 5am
1269             4) Start period falls within the end day point.
1270             * ie day 23/2/2004. Event goes 23/2/2004 12 noon to 25/2/2004
1271            */

1272            Date JavaDoc icalDateStart = icalEvent.getDateStart();
1273            Date JavaDoc icalDateEnd = icalEvent.getDateEnd();
1274
1275            /*
1276             * Whole day events are not handled well with this method as they run
1277             * exactly on the 24hr time line. We need to recognise them and
1278             * for the purposes of testing conditions, reduce the seconds so
1279             * that they fit within a day.
1280             */

1281            Date JavaDoc thisTimeFrom = dateFrom;
1282            Date JavaDoc thisTimeTo = dateTo;
1283
1284            // Condition 1.
1285
if ((thisTimeFrom.after(icalDateStart)
1286            || thisTimeFrom.equals(icalDateStart))
1287            && (thisTimeTo.before(icalDateEnd)
1288            || thisTimeTo.equals(icalDateEnd)))
1289            {
1290                // Create an all day event as this event wraps this day and others.
1291
icalEvent.setDateStart(thisTimeFrom);
1292                icalEvent.setDateEnd(thisTimeTo);
1293                XMLString.append("\t\t");
1294                XMLString.append(icalEvent.toXML());
1295                XMLString.append("\n");
1296            }
1297            // Condition 2.
1298
else if (thisTimeFrom.before(icalDateStart)
1299            && thisTimeTo.after(icalDateEnd))
1300            {
1301                // Create event as is.
1302
// XMLString.append("Cond2");
1303
XMLString.append("\t\t");
1304                XMLString.append(icalEvent.toXML());
1305                XMLString.append("\n");
1306            }
1307            // Condition 3.
1308
else if (thisTimeFrom.before(icalDateEnd)
1309            && thisTimeTo.after(icalDateEnd))
1310            {
1311                // Create event with end time as thisTimeTo, start time as speced.
1312
// XMLString.append("Cond3" + thisTimeFrom + thisTimeTo);
1313
icalEvent.setDateStart(thisTimeFrom);
1314                icalEvent.setDateEnd(icalDateEnd);
1315                XMLString.append("\t\t");
1316                XMLString.append(icalEvent.toXML());
1317                XMLString.append("\n");
1318            }
1319            // Condition 4.
1320
else if (thisTimeFrom.before(icalDateStart)
1321            && thisTimeTo.after(icalDateStart))
1322            {
1323                // Create event with starttime time as thisTimeFrom, end time as speced.
1324
// XMLString.append("Cond4");
1325
icalEvent.setDateStart(icalDateStart);
1326                icalEvent.setDateEnd(thisTimeTo);
1327                XMLString.append("\t\t");
1328                XMLString.append(icalEvent.toXML());
1329                XMLString.append("\n");
1330            }
1331            else {
1332                //Event rejected for this date
1333
}
1334        }
1335        
1336        XMLString.append("</vevents></jicalxml>\n");
1337        return XMLString.toString();
1338    }
1339    
1340    public String JavaDoc getJiCaldisplayXML(String JavaDoc dateRangeOrDaysForward, String JavaDoc timeRange) throws Exception JavaDoc
1341    {
1342        DateTimeRange dtr = new DateTimeRange();
1343        dtr.calcDateTimeRange(dateRangeOrDaysForward,timeRange);
1344        
1345// Date dateFrom = null;
1346
// Date dateTo = null;
1347
// try
1348
// {
1349
// long daysForward = getDaysForwardNumeric(dateRangeOrDaysForward);
1350
// try
1351
// {
1352
// return getJiCaldisplayXML(daysForward, timeRange);
1353
// }
1354
// catch (Exception e)
1355
// {
1356
// logger.severe("Error:" + e);
1357
// }
1358
// }
1359
// catch (Exception e)
1360
// {
1361
// try
1362
// {
1363
// dateFrom = getDateFrom(dateRangeOrDaysForward);
1364
// dateTo = getDateTo(dateRangeOrDaysForward);
1365
//
1366
// }
1367
// catch (Exception ee)
1368
// {
1369
// logger.severe("Unable to read your input dates: "
1370
// + dateRangeOrDaysForward
1371
// + "They must be of the form ccYYmmDDhhMMss-ccYYmmDDhhMMss"
1372
// + ee);
1373
// throw ee;
1374
// }
1375
// }
1376
return getJiCaldisplayXML(dtr.dateFrom , dtr.dateTo, timeRange);
1377    }
1378// public String getJiCaldisplayXML(long daysForward, String timeRange)
1379
// {
1380
// Date dateFrom = new Date();
1381
// Date dateTo = getDateToFromDaysForward(daysForward);
1382
// /*
1383
// * Currently, keep this dateFrom/To as coarse. ie, dateFrom/To are DAYS not DAY/HH:MM
1384
// * ie for FROM date, set to time of 0000, for TO date set to time of 235959
1385
// */
1386
// try
1387
// {
1388
// dateFrom = (Date)dateOnlyFormat.parse(dateOnlyFormat.format(dateFrom));
1389
// dateTo = (Date)dateFormatter.parse(dateOnlyFormat.format(dateTo) + "235959");
1390
// }
1391
// catch (Exception e)
1392
// {
1393
// logger.severe("Error setting dates to process full day range." + e);
1394
// }
1395
// return getJiCaldisplayXML(dateFrom, dateTo, timeRange);
1396
// }
1397

1398    public String JavaDoc getJiCaldisplayXML(Date JavaDoc dateFrom, Date JavaDoc dateTo, String JavaDoc timeRange)
1399    {
1400        if (this.getOrganizerEmail() == null
1401        || this.getOrganizer() == null) {
1402            logger.severe("Cannot create XML unless OrganizerEmail are Organizer provided to ICalendar");
1403            return "";
1404        }
1405
1406        /*
1407         * This is more useful for rendering as HTML or PDF an
1408         * Evolution Calendar.
1409         *
1410         */

1411
1412        StringBuffer JavaDoc XMLString = new StringBuffer JavaDoc("<jicaldisplay>\n");
1413        XMLString.append("\t<organizer>").append( this.getOrganizer()).append("</organizer>\n");
1414        XMLString.append("\t<organizeremail>").append(this.getOrganizerEmail()).append("</organizeremail>\n");
1415        XMLString.append("\t<datestart>").append(dateFormatter.format(dateFrom)).append("</datestart>\n");
1416        XMLString.append("\t<dateend>").append(dateFormatter.format(dateTo)).append("</dateend>\n");
1417
1418        // Hmmm... If we truely want to represent this date range, we must get all dates from .
1419
// to the To range. Reason being that some might start before this date and repeat in
1420
// this range....
1421

1422        // Make starting date really old!!
1423

1424        Date JavaDoc trueStartDate = new Date JavaDoc(0);
1425        getIcalExpandedEvents(trueStartDate, dateTo, timeRange);
1426
1427        /*
1428         * This is the tricky bit, iterate from the datefrom date, through the
1429         * days to the dateto date. All days in between get some XML.
1430         */

1431        
1432        //int dateRepeatUnit = Calendar.HOUR_OF_DAY;
1433

1434        Calendar JavaDoc repeatXMLDateStart = new GregorianCalendar JavaDoc();
1435        repeatXMLDateStart.setTime(dateFrom);
1436        
1437        XMLString.append("<days>\n");
1438        
1439        while (repeatXMLDateStart != null
1440        && ! repeatXMLDateStart.getTime().after(dateTo))
1441        {
1442            XMLString.append("\t\t<day>\n");
1443            XMLString.append("\t\t\t<dayofweek>").append(dayOfWeek.format(repeatXMLDateStart.getTime())).append("</dayofweek>\n");
1444            XMLString.append("\t\t\t<monthofyear>").append(monthOfYear.format(repeatXMLDateStart.getTime())).append("</monthofyear>\n");
1445            XMLString.append("\t\t\t<weeknumber>").append(weekNumber.format(repeatXMLDateStart.getTime())).append("</weeknumber>\n");
1446            XMLString.append("\t\t\t<date>").append(dateOnlyFormat.format(repeatXMLDateStart.getTime())).append("</date>\n");
1447            // Add two new XML elements which can be used when styling with XSL
1448
XMLString.append("\t\t\t<dayofweeknum>").append(repeatDateStart.get(Calendar.DAY_OF_WEEK)).append("</dayofweeknum>\n");
1449            XMLString.append("\t\t\t<dayofmonth>").append(dayNumber.format(repeatDateStart.getTime())).append("</dayofmonth>\n");
1450            XMLString.append("\t\t\t<year>").append(year.format(repeatDateStart.getTime())).append("</year>\n");
1451            XMLString.append("\t\t\t<vevents>\n");
1452            // Now find all events that match this date.
1453
Calendar JavaDoc thisDateFrom = new GregorianCalendar JavaDoc();
1454            thisDateFrom.setTime(repeatXMLDateStart.getTime());
1455            thisDateFrom.set(Calendar.HOUR_OF_DAY, 0);
1456            thisDateFrom.set(Calendar.MINUTE, 0);
1457            thisDateFrom.set(Calendar.SECOND, 0);
1458
1459            Date JavaDoc thisTimeFrom = thisDateFrom.getTime();
1460            // Altered as was excluding all day events which END at 00:00 on the next day..
1461
Calendar JavaDoc thisDateTo = new GregorianCalendar JavaDoc();
1462            thisDateTo.setTime(repeatXMLDateStart.getTime());
1463            thisDateTo.set(Calendar.HOUR_OF_DAY,24);
1464            thisDateTo.set(java.util.Calendar.MINUTE,0);
1465            thisDateTo.set(java.util.Calendar.SECOND,0);
1466            Date JavaDoc thisTimeTo = thisDateTo.getTime();
1467            
1468            Iterator JavaDoc eeIterator = sortedExpandedEvents.iterator();
1469            while (eeIterator.hasNext())
1470            {
1471        ICalendarVEvent icalEvent = (ICalendarVEvent) eeIterator.next();
1472                /* There are four conditions for inclusion of this event
1473                 in this day.
1474                 1) Runs right across this date and others.
1475                 * ie day 23/2/2004. Event goes 22/2/2004 to 25/2/2004
1476                 2) Falls within the day
1477                 ** ie day 23/2/2004. Event goes 23/2/2004 to 23/2/2004
1478                 3) End period falls within the start day point or
1479                 * ie day 23/2/2004. Event goes 22/2/2004 to 23/2/2004 5am
1480                 4) Start period falls within the end day point.
1481                 * ie day 23/2/2004. Event goes 23/2/2004 12 noon to 25/2/2004
1482                */

1483                Date JavaDoc icalDateStart = icalEvent.getDateStart();
1484                Date JavaDoc icalDateEnd = icalEvent.getDateEnd();
1485
1486                /*
1487                 * Whole day events are not handled well with this method as they run
1488                 * exactly on the 24hr time line. We need to recognise them and
1489                 * for the purposes of testing conditions, reduce the seconds so
1490                 * that they fit within a day.
1491                 */

1492                thisDateFrom.setTime(icalDateStart);
1493                thisDateTo.setTime(icalDateEnd);
1494                
1495                // Condition 1.
1496
if ((thisTimeFrom.after(icalDateStart)
1497                || thisTimeFrom.equals(icalDateStart))
1498                && (thisTimeTo.before(icalDateEnd)
1499                || thisTimeTo.equals(icalDateEnd)))
1500                {
1501                    // Create an all day event as this event wraps this day and others.
1502
icalEvent.setDateStart(thisTimeFrom);
1503                    icalEvent.setDateEnd(thisTimeTo);
1504                    XMLString.append("\t\t");
1505                    XMLString.append(icalEvent.toXML());
1506                    XMLString.append("\n");
1507                }
1508                // Condition 2.
1509
else if (thisTimeFrom.before(icalDateStart)
1510                && thisTimeTo.after(icalDateEnd))
1511                {
1512                    // Create event as is.
1513
// XMLString.append("Cond2");
1514
XMLString.append("\t\t");
1515                    XMLString.append(icalEvent.toXML());
1516                    XMLString.append("\n");
1517                }
1518                // Condition 3.
1519
else if (thisTimeFrom.before(icalDateEnd)
1520                && thisTimeTo.after(icalDateEnd))
1521                {
1522                    // Create event with end time as thisTimeTo, start time as speced.
1523
// XMLString.append("Cond3" + thisTimeFrom + thisTimeTo);
1524
icalEvent.setDateStart(thisTimeFrom);
1525                    icalEvent.setDateEnd(icalDateEnd);
1526                    XMLString.append("\t\t");
1527                    XMLString.append(icalEvent.toXML());
1528                    XMLString.append("\n");
1529                }
1530                // Condition 4.
1531
else if (thisTimeFrom.before(icalDateStart)
1532                && thisTimeTo.after(icalDateStart))
1533                {
1534                    // Create event with starttime time as thisTimeFrom, end time as speced.
1535
// XMLString.append("Cond4");
1536
icalEvent.setDateStart(icalDateStart);
1537                    icalEvent.setDateEnd(thisTimeTo);
1538                    XMLString.append("\t\t");
1539                    XMLString.append(icalEvent.toXML());
1540                    XMLString.append("\n");
1541                }
1542                else {
1543                    //Event rejected for this date
1544
}
1545            }
1546
1547            XMLString.append("\t\t\t</vevents>");
1548            XMLString.append("\t\t</day>\n");
1549
1550            // On to the next day..
1551
repeatXMLDateStart.add(Calendar.HOUR_OF_DAY, 24);
1552            
1553        }
1554        
1555        XMLString.append("\t</days>\n");
1556        XMLString.append("</jicaldisplay>\n");
1557        return XMLString.toString();
1558    }
1559    /**
1560     * @return Returns the repeatDateEnd.
1561     */

1562    public Calendar JavaDoc getRepeatDateEnd() {
1563        return repeatDateEnd;
1564    }
1565    /**
1566     * @param repeatDateEnd The repeatDateEnd to set.
1567     */

1568    public void setRepeatDateEnd(Calendar JavaDoc repeatDateEndIn) {
1569        this.repeatDateEnd = repeatDateEndIn;
1570    }
1571    /**
1572     * @return Returns the repeatDateStart.
1573     */

1574    public Calendar JavaDoc getRepeatDateStart() {
1575        return repeatDateStart;
1576    }
1577    /**
1578     * @param repeatDateStart The repeatDateStart to set.
1579     */

1580    public void setRepeatDateStart(Calendar JavaDoc repeatDateStartIn) {
1581        this.repeatDateStart = repeatDateStartIn;
1582    }
1583}
1584
Popular Tags