001package biweekly.component;
002
003import static biweekly.property.ValuedProperty.getValue;
004
005import java.util.Date;
006import java.util.List;
007
008import biweekly.ICalVersion;
009import biweekly.Warning;
010import biweekly.property.Attachment;
011import biweekly.property.Attendee;
012import biweekly.property.Categories;
013import biweekly.property.Classification;
014import biweekly.property.Comment;
015import biweekly.property.Contact;
016import biweekly.property.Created;
017import biweekly.property.DateEnd;
018import biweekly.property.DateStart;
019import biweekly.property.DateTimeStamp;
020import biweekly.property.Description;
021import biweekly.property.DurationProperty;
022import biweekly.property.ExceptionDates;
023import biweekly.property.ExceptionRule;
024import biweekly.property.Geo;
025import biweekly.property.LastModified;
026import biweekly.property.Location;
027import biweekly.property.Method;
028import biweekly.property.Organizer;
029import biweekly.property.Priority;
030import biweekly.property.RecurrenceDates;
031import biweekly.property.RecurrenceId;
032import biweekly.property.RecurrenceRule;
033import biweekly.property.RelatedTo;
034import biweekly.property.RequestStatus;
035import biweekly.property.Resources;
036import biweekly.property.Sequence;
037import biweekly.property.Status;
038import biweekly.property.Summary;
039import biweekly.property.Transparency;
040import biweekly.property.Uid;
041import biweekly.property.Url;
042import biweekly.util.Duration;
043import biweekly.util.ICalDate;
044import biweekly.util.Recurrence;
045
046/*
047 Copyright (c) 2013-2015, Michael Angstadt
048 All rights reserved.
049
050 Redistribution and use in source and binary forms, with or without
051 modification, are permitted provided that the following conditions are met: 
052
053 1. Redistributions of source code must retain the above copyright notice, this
054 list of conditions and the following disclaimer. 
055 2. Redistributions in binary form must reproduce the above copyright notice,
056 this list of conditions and the following disclaimer in the documentation
057 and/or other materials provided with the distribution. 
058
059 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
060 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
061 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
062 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
063 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
064 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
065 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
066 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
067 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
068 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
069 */
070
071/**
072 * <p>
073 * Defines a scheduled activity, such as a two hour meeting.
074 * </p>
075 * <p>
076 * <b>Examples:</b>
077 * 
078 * <pre class="brush:java">
079 * VEvent event = new VEvent();
080 * Date start = ...
081 * event.setDateStart(start);
082 * Date end = ...
083 * event.setDateEnd(end);
084 * event.setSummary("Team Meeting");
085 * event.setLocation("Room 21C");
086 * event.setCreated(new Date());
087 * event.setRecurrenceRule(new Recurrence.Builder(Frequency.WEEKLY).build());
088 * </pre>
089 * 
090 * </p>
091 * @author Michael Angstadt
092 * @see <a href="http://tools.ietf.org/html/rfc5545#page-52">RFC 5545 p.52-5</a>
093 * @see <a href="http://tools.ietf.org/html/rfc2445#page-52">RFC 2445 p.52-4</a>
094 * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.13</a>
095 */
096public class VEvent extends ICalComponent {
097        /**
098         * <p>
099         * Creates a new event.
100         * </p>
101         * <p>
102         * The following properties are auto-generated on object creation. These
103         * properties <b>must</b> be present in order for the event to be valid:
104         * <ul>
105         * <li>{@link Uid} - Set to a UUID.</li>
106         * <li>{@link DateTimeStamp} - Set to the current date-time.</li>
107         * </ul>
108         * </p>
109         */
110        public VEvent() {
111                setUid(Uid.random());
112                setDateTimeStamp(new Date());
113        }
114
115        /**
116         * Gets the unique identifier for this event. This component object comes
117         * populated with a UID on creation. This is a <b>required</b> property.
118         * @return the UID or null if not set
119         * @see <a href="http://tools.ietf.org/html/rfc5545#page-117">RFC 5545
120         * p.117-8</a>
121         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.37</a>
122         */
123        public Uid getUid() {
124                return getProperty(Uid.class);
125        }
126
127        /**
128         * Sets the unique identifier for this event. This component object comes
129         * populated with a UID on creation. This is a <b>required</b> property.
130         * @param uid the UID or null to remove
131         * @see <a href="http://tools.ietf.org/html/rfc5545#page-117">RFC 5545
132         * p.117-8</a>
133         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.37</a>
134         */
135        public void setUid(Uid uid) {
136                setProperty(Uid.class, uid);
137        }
138
139        /**
140         * Sets the unique identifier for this event. This component object comes
141         * populated with a UID on creation. This is a <b>required</b> property.
142         * @param uid the UID or null to remove
143         * @return the property that was created
144         * @see <a href="http://tools.ietf.org/html/rfc5545#page-117">RFC 5545
145         * p.117-8</a>
146         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.37</a>
147         */
148        public Uid setUid(String uid) {
149                Uid prop = (uid == null) ? null : new Uid(uid);
150                setUid(prop);
151                return prop;
152        }
153
154        /**
155         * Gets either (a) the creation date of the iCalendar object (if the
156         * {@link Method} property is defined) or (b) the date that the event was
157         * last modified (the {@link LastModified} property also holds this
158         * information). This event object comes populated with a
159         * {@link DateTimeStamp} property that is set to the current time. This is a
160         * <b>required</b> property.
161         * @return the date time stamp or null if not set
162         * @see <a href="http://tools.ietf.org/html/rfc5545#page-137">RFC 5545
163         * p.137-8</a>
164         */
165        public DateTimeStamp getDateTimeStamp() {
166                return getProperty(DateTimeStamp.class);
167        }
168
169        /**
170         * Sets either (a) the creation date of the iCalendar object (if the
171         * {@link Method} property is defined) or (b) the date that the event was
172         * last modified (the {@link LastModified} property also holds this
173         * information). This event object comes populated with a
174         * {@link DateTimeStamp} property that is set to the current time. This is a
175         * <b>required</b> property.
176         * @param dateTimeStamp the date time stamp or null to remove
177         * @see <a href="http://tools.ietf.org/html/rfc5545#page-137">RFC 5545
178         * p.137-8</a>
179         */
180        public void setDateTimeStamp(DateTimeStamp dateTimeStamp) {
181                setProperty(DateTimeStamp.class, dateTimeStamp);
182        }
183
184        /**
185         * Sets either (a) the creation date of the iCalendar object (if the
186         * {@link Method} property is defined) or (b) the date that the event was
187         * last modified (the {@link LastModified} property also holds this
188         * information). This event object comes populated with a
189         * {@link DateTimeStamp} property that is set to the current time. This is a
190         * <b>required</b> property.
191         * @param dateTimeStamp the date time stamp or null to remove
192         * @return the property that was created
193         * @see <a href="http://tools.ietf.org/html/rfc5545#page-137">RFC 5545
194         * p.137-8</a>
195         */
196        public DateTimeStamp setDateTimeStamp(Date dateTimeStamp) {
197                DateTimeStamp prop = (dateTimeStamp == null) ? null : new DateTimeStamp(dateTimeStamp);
198                setDateTimeStamp(prop);
199                return prop;
200        }
201
202        /**
203         * Gets the date that the event starts.
204         * @return the start date or null if not set
205         * @see <a href="http://tools.ietf.org/html/rfc5545#page-97">RFC 5545
206         * p.97-8</a>
207         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.35</a>
208         */
209        public DateStart getDateStart() {
210                return getProperty(DateStart.class);
211        }
212
213        /**
214         * Sets the date that the event starts (required if no {@link Method}
215         * property is defined).
216         * @param dateStart the start date or null to remove
217         * @see <a href="http://tools.ietf.org/html/rfc5545#page-97">RFC 5545
218         * p.97-8</a>
219         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.35</a>
220         */
221        public void setDateStart(DateStart dateStart) {
222                setProperty(DateStart.class, dateStart);
223        }
224
225        /**
226         * Sets the date that the event starts (required if no {@link Method}
227         * property is defined).
228         * @param dateStart the start date or null to remove
229         * @return the property that was created
230         * @see <a href="http://tools.ietf.org/html/rfc5545#page-97">RFC 5545
231         * p.97-8</a>
232         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.35</a>
233         */
234        public DateStart setDateStart(Date dateStart) {
235                DateStart prop = (dateStart == null) ? null : new DateStart(dateStart);
236                setDateStart(prop);
237                return prop;
238        }
239
240        /**
241         * Gets the level of sensitivity of the event data. If not specified, the
242         * data within the event should be considered "public".
243         * @return the classification level or null if not set
244         * @see <a href="http://tools.ietf.org/html/rfc5545#page-82">RFC 5545
245         * p.82-3</a>
246         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.28-9</a>
247         */
248        public Classification getClassification() {
249                return getProperty(Classification.class);
250        }
251
252        /**
253         * Sets the level of sensitivity of the event data. If not specified, the
254         * data within the event should be considered "public".
255         * @param classification the classification level or null to remove
256         * @see <a href="http://tools.ietf.org/html/rfc5545#page-82">RFC 5545
257         * p.82-3</a>
258         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.28-9</a>
259         */
260        public void setClassification(Classification classification) {
261                setProperty(Classification.class, classification);
262        }
263
264        /**
265         * Sets the level of sensitivity of the event data. If not specified, the
266         * data within the event should be considered "public".
267         * @param classification the classification level (e.g. "CONFIDENTIAL") or
268         * null to remove
269         * @return the property that was created
270         * @see <a href="http://tools.ietf.org/html/rfc5545#page-82">RFC 5545
271         * p.82-3</a>
272         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.28-9</a>
273         */
274        public Classification setClassification(String classification) {
275                Classification prop = (classification == null) ? null : new Classification(classification);
276                setClassification(prop);
277                return prop;
278        }
279
280        /**
281         * Gets a detailed description of the event. The description should be more
282         * detailed than the one provided by the {@link Summary} property.
283         * @return the description or null if not set
284         * @see <a href="http://tools.ietf.org/html/rfc5545#page-84">RFC 5545
285         * p.84-5</a>
286         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.30</a>
287         */
288        public Description getDescription() {
289                return getProperty(Description.class);
290        }
291
292        /**
293         * Sets a detailed description of the event. The description should be more
294         * detailed than the one provided by the {@link Summary} property.
295         * @param description the description or null to remove
296         * @see <a href="http://tools.ietf.org/html/rfc5545#page-84">RFC 5545
297         * p.84-5</a>
298         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.30</a>
299         */
300        public void setDescription(Description description) {
301                setProperty(Description.class, description);
302        }
303
304        /**
305         * Sets a detailed description of the event. The description should be more
306         * detailed than the one provided by the {@link Summary} property.
307         * @param description the description or null to remove
308         * @return the property that was created
309         * @see <a href="http://tools.ietf.org/html/rfc5545#page-84">RFC 5545
310         * p.84-5</a>
311         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.30</a>
312         */
313        public Description setDescription(String description) {
314                Description prop = (description == null) ? null : new Description(description);
315                setDescription(prop);
316                return prop;
317        }
318
319        /**
320         * Gets a set of geographical coordinates.
321         * @return the geographical coordinates or null if not set
322         * @see <a href="http://tools.ietf.org/html/rfc5545#page-85">RFC 5545
323         * p.85-7</a>
324         */
325        public Geo getGeo() {
326                return getProperty(Geo.class);
327        }
328
329        /**
330         * Sets a set of geographical coordinates.
331         * @param geo the geographical coordinates or null to remove
332         * @see <a href="http://tools.ietf.org/html/rfc5545#page-85">RFC 5545
333         * p.85-7</a>
334         */
335        public void setGeo(Geo geo) {
336                setProperty(Geo.class, geo);
337        }
338
339        /**
340         * Gets the physical location of the event.
341         * @return the location or null if not set
342         * @see <a href="http://tools.ietf.org/html/rfc5545#page-87">RFC 5545
343         * p.87-8</a>
344         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.32</a>
345         */
346        public Location getLocation() {
347                return getProperty(Location.class);
348        }
349
350        /**
351         * Sets the physical location of the event.
352         * @param location the location or null to remove
353         * @see <a href="http://tools.ietf.org/html/rfc5545#page-87">RFC 5545
354         * p.87-8</a>
355         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.32</a>
356         */
357        public void setLocation(Location location) {
358                setProperty(Location.class, location);
359        }
360
361        /**
362         * Sets the physical location of the event.
363         * @param location the location (e.g. "Room 101") or null to remove
364         * @return the property that was created
365         * @see <a href="http://tools.ietf.org/html/rfc5545#page-87">RFC 5545
366         * p.87-8</a>
367         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.32</a>
368         */
369        public Location setLocation(String location) {
370                Location prop = (location == null) ? null : new Location(location);
371                setLocation(prop);
372                return prop;
373        }
374
375        /**
376         * Gets the priority of the event.
377         * @return the priority or null if not set
378         * @see <a href="http://tools.ietf.org/html/rfc5545#page-89">RFC 5545
379         * p.89-90</a>
380         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.33</a>
381         */
382        public Priority getPriority() {
383                return getProperty(Priority.class);
384        }
385
386        /**
387         * Sets the priority of the event.
388         * @param priority the priority or null to remove
389         * @see <a href="http://tools.ietf.org/html/rfc5545#page-89">RFC 5545
390         * p.89-90</a>
391         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.33</a>
392         */
393        public void setPriority(Priority priority) {
394                setProperty(Priority.class, priority);
395        }
396
397        /**
398         * Sets the priority of the event.
399         * @param priority the priority ("0" is undefined, "1" is the highest, "9"
400         * is the lowest) or null to remove
401         * @return the property that was created
402         * @see <a href="http://tools.ietf.org/html/rfc5545#page-89">RFC 5545
403         * p.89-90</a>
404         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.33</a>
405         */
406        public Priority setPriority(Integer priority) {
407                Priority prop = (priority == null) ? null : new Priority(priority);
408                setPriority(prop);
409                return prop;
410        }
411
412        /**
413         * Gets the status of the event.
414         * @return the status or null if not set
415         * @see <a href="http://tools.ietf.org/html/rfc5545#page-92">RFC 5545
416         * p.92-3</a>
417         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.35-6</a>
418         */
419        public Status getStatus() {
420                return getProperty(Status.class);
421        }
422
423        /**
424         * Sets the status of the event.
425         * <p>
426         * Valid event status codes are:
427         * <ul>
428         * <li>TENTATIVE</li>
429         * <li>CONFIRMED</li>
430         * <li>CANCELLED</li>
431         * </ul>
432         * </p>
433         * @param status the status or null to remove
434         * @see <a href="http://tools.ietf.org/html/rfc5545#page-92">RFC 5545
435         * p.92-3</a>
436         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.35-6</a>
437         */
438        public void setStatus(Status status) {
439                setProperty(Status.class, status);
440        }
441
442        /**
443         * Gets the summary of the event.
444         * @return the summary or null if not set
445         * @see <a href="http://tools.ietf.org/html/rfc5545#page-93">RFC 5545
446         * p.93-4</a>
447         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.36</a>
448         */
449        public Summary getSummary() {
450                return getProperty(Summary.class);
451        }
452
453        /**
454         * Sets the summary of the event.
455         * @param summary the summary or null to remove
456         * @see <a href="http://tools.ietf.org/html/rfc5545#page-93">RFC 5545
457         * p.93-4</a>
458         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.36</a>
459         */
460        public void setSummary(Summary summary) {
461                setProperty(Summary.class, summary);
462        }
463
464        /**
465         * Sets the summary of the event.
466         * @param summary the summary or null to remove
467         * @return the property that was created
468         * @see <a href="http://tools.ietf.org/html/rfc5545#page-93">RFC 5545
469         * p.93-4</a>
470         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.36</a>
471         */
472        public Summary setSummary(String summary) {
473                Summary prop = (summary == null) ? null : new Summary(summary);
474                setSummary(prop);
475                return prop;
476        }
477
478        /**
479         * Gets whether an event is visible to free/busy time searches. If the event
480         * does not have this property, it should be considered visible ("opaque").
481         * @return the transparency or null if not set
482         * @see <a href="http://tools.ietf.org/html/rfc5545#page-101">RFC 5545
483         * p.101-2</a>
484         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.36-7</a>
485         */
486        public Transparency getTransparency() {
487                return getProperty(Transparency.class);
488        }
489
490        /**
491         * Sets whether an event is visible to free/busy time searches.
492         * @param transparency the transparency or null to remove
493         * @see <a href="http://tools.ietf.org/html/rfc5545#page-101">RFC 5545
494         * p.101-2</a>
495         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.36-7</a>
496         */
497        public void setTransparency(Transparency transparency) {
498                setProperty(Transparency.class, transparency);
499        }
500
501        /**
502         * Sets whether an event is visible to free/busy time searches.
503         * @param transparent true to hide the event, false to make it visible it,
504         * or null to remove the property
505         * @return the property that was created
506         * @see <a href="http://tools.ietf.org/html/rfc5545#page-101">RFC 5545
507         * p.101-2</a>
508         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.36-7</a>
509         */
510        public Transparency setTransparency(Boolean transparent) {
511                Transparency prop = null;
512                if (transparent != null) {
513                        prop = transparent ? Transparency.transparent() : Transparency.opaque();
514                }
515                setTransparency(prop);
516                return prop;
517        }
518
519        /**
520         * Gets the organizer of the event.
521         * @return the organizer or null if not set
522         * @see <a href="http://tools.ietf.org/html/rfc5545#page-111">RFC 5545
523         * p.111-2</a>
524         */
525        public Organizer getOrganizer() {
526                return getProperty(Organizer.class);
527        }
528
529        /**
530         * Sets the organizer of the event.
531         * @param organizer the organizer or null to remove
532         * @see <a href="http://tools.ietf.org/html/rfc5545#page-111">RFC 5545
533         * p.111-2</a>
534         */
535        public void setOrganizer(Organizer organizer) {
536                setProperty(Organizer.class, organizer);
537        }
538
539        /**
540         * Sets the organizer of the event.
541         * @param email the organizer's email address (e.g. "johndoe@example.com")
542         * or null to remove
543         * @return the property that was created
544         * @see <a href="http://tools.ietf.org/html/rfc5545#page-111">RFC 5545
545         * p.111-2</a>
546         */
547        public Organizer setOrganizer(String email) {
548                Organizer prop = (email == null) ? null : new Organizer(null, email);
549                setOrganizer(prop);
550                return prop;
551        }
552
553        /**
554         * Gets the original value of the {@link DateStart} property if the event is
555         * recurring and has been modified. Used in conjunction with the {@link Uid}
556         * and {@link Sequence} properties to uniquely identify a recurrence
557         * instance.
558         * @return the recurrence ID or null if not set
559         * @see <a href="http://tools.ietf.org/html/rfc5545#page-112">RFC 5545
560         * p.112-4</a>
561         */
562        public RecurrenceId getRecurrenceId() {
563                return getProperty(RecurrenceId.class);
564        }
565
566        /**
567         * Sets the original value of the {@link DateStart} property if the event is
568         * recurring and has been modified. Used in conjunction with the {@link Uid}
569         * and {@link Sequence} properties to uniquely identify a recurrence
570         * instance.
571         * @param recurrenceId the recurrence ID or null to remove
572         * @see <a href="http://tools.ietf.org/html/rfc5545#page-112">RFC 5545
573         * p.112-4</a>
574         */
575        public void setRecurrenceId(RecurrenceId recurrenceId) {
576                setProperty(RecurrenceId.class, recurrenceId);
577        }
578
579        /**
580         * Sets the original value of the {@link DateStart} property if the event is
581         * recurring and has been modified. Used in conjunction with the {@link Uid}
582         * and {@link Sequence} properties to uniquely identify a recurrence
583         * instance.
584         * @param originalStartDate the original start date or null to remove
585         * @return the property that was created
586         * @see <a href="http://tools.ietf.org/html/rfc5545#page-112">RFC 5545
587         * p.112-4</a>
588         */
589        public RecurrenceId setRecurrenceId(Date originalStartDate) {
590                RecurrenceId prop = (originalStartDate == null) ? null : new RecurrenceId(originalStartDate);
591                setRecurrenceId(prop);
592                return prop;
593        }
594
595        /**
596         * Gets a URL to a resource that contains additional information about the
597         * event.
598         * @return the URL or null if not set
599         * @see <a href="http://tools.ietf.org/html/rfc5545#page-116">RFC 5545
600         * p.116-7</a>
601         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.37</a>
602         */
603        public Url getUrl() {
604                return getProperty(Url.class);
605        }
606
607        /**
608         * Sets a URL to a resource that contains additional information about the
609         * event.
610         * @param url the URL or null to remove
611         * @see <a href="http://tools.ietf.org/html/rfc5545#page-116">RFC 5545
612         * p.116-7</a>
613         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.37</a>
614         */
615        public void setUrl(Url url) {
616                setProperty(Url.class, url);
617        }
618
619        /**
620         * Sets a URL to a resource that contains additional information about the
621         * event.
622         * @param url the URL (e.g. "http://example.com/resource.ics") or null to
623         * remove
624         * @return the property that was created
625         * @see <a href="http://tools.ietf.org/html/rfc5545#page-116">RFC 5545
626         * p.116-7</a>
627         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.37</a>
628         */
629        public Url setUrl(String url) {
630                Url prop = (url == null) ? null : new Url(url);
631                setUrl(prop);
632                return prop;
633        }
634
635        /**
636         * Gets how often the event repeats.
637         * @return the recurrence rule or null if not set
638         * @see <a href="http://tools.ietf.org/html/rfc5545#page-122">RFC 5545
639         * p.122-32</a>
640         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.34</a>
641         */
642        public RecurrenceRule getRecurrenceRule() {
643                return getProperty(RecurrenceRule.class);
644        }
645
646        /**
647         * Sets how often the event repeats.
648         * @param recur the recurrence rule or null to remove
649         * @return the property that was created
650         * @see <a href="http://tools.ietf.org/html/rfc5545#page-122">RFC 5545
651         * p.122-32</a>
652         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.34</a>
653         */
654        public RecurrenceRule setRecurrenceRule(Recurrence recur) {
655                RecurrenceRule prop = (recur == null) ? null : new RecurrenceRule(recur);
656                setRecurrenceRule(prop);
657                return prop;
658        }
659
660        /**
661         * Sets how often the event repeats.
662         * @param recurrenceRule the recurrence rule or null to remove
663         * @see <a href="http://tools.ietf.org/html/rfc5545#page-122">RFC 5545
664         * p.122-32</a>
665         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.34</a>
666         */
667        public void setRecurrenceRule(RecurrenceRule recurrenceRule) {
668                setProperty(RecurrenceRule.class, recurrenceRule);
669        }
670
671        /**
672         * Gets the date that the event ends.
673         * @return the end date or null if not set
674         * @see <a href="http://tools.ietf.org/html/rfc5545#page-95">RFC 5545
675         * p.95-6</a>
676         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.31</a>
677         */
678        public DateEnd getDateEnd() {
679                return getProperty(DateEnd.class);
680        }
681
682        /**
683         * Sets the date that the event ends. This must NOT be set if a
684         * {@link DurationProperty} is defined.
685         * @param dateEnd the end date or null to remove
686         * @see <a href="http://tools.ietf.org/html/rfc5545#page-95">RFC 5545
687         * p.95-6</a>
688         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.31</a>
689         */
690        public void setDateEnd(DateEnd dateEnd) {
691                setProperty(DateEnd.class, dateEnd);
692        }
693
694        /**
695         * Sets the date that the event ends. This must NOT be set if a
696         * {@link DurationProperty} is defined.
697         * @param dateEnd the end date or null to remove
698         * @return the property that was created
699         * @see <a href="http://tools.ietf.org/html/rfc5545#page-95">RFC 5545
700         * p.95-6</a>
701         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.31</a>
702         */
703        public DateEnd setDateEnd(Date dateEnd) {
704                DateEnd prop = (dateEnd == null) ? null : new DateEnd(dateEnd);
705                setDateEnd(prop);
706                return prop;
707        }
708
709        /**
710         * Gets the duration of the event.
711         * @return the duration or null if not set
712         * @see <a href="http://tools.ietf.org/html/rfc5545#page-99">RFC 5545
713         * p.99</a>
714         */
715        public DurationProperty getDuration() {
716                return getProperty(DurationProperty.class);
717        }
718
719        /**
720         * Sets the duration of the event. This must NOT be set if a {@link DateEnd}
721         * is defined.
722         * @param duration the duration or null to remove
723         * @see <a href="http://tools.ietf.org/html/rfc5545#page-99">RFC 5545
724         * p.99</a>
725         */
726        public void setDuration(DurationProperty duration) {
727                setProperty(DurationProperty.class, duration);
728        }
729
730        /**
731         * Sets the duration of the event. This must NOT be set if a {@link DateEnd}
732         * is defined.
733         * @param duration the duration or null to remove
734         * @return the property that was created
735         * @see <a href="http://tools.ietf.org/html/rfc5545#page-99">RFC 5545
736         * p.99</a>
737         */
738        public DurationProperty setDuration(Duration duration) {
739                DurationProperty prop = (duration == null) ? null : new DurationProperty(duration);
740                setDuration(prop);
741                return prop;
742        }
743
744        /**
745         * Gets the date-time that the event was initially created.
746         * @return the creation date-time or null if not set
747         * @see <a href="http://tools.ietf.org/html/rfc5545#page-136">RFC 5545
748         * p.136</a>
749         */
750        public Created getCreated() {
751                return getProperty(Created.class);
752        }
753
754        /**
755         * Sets the date-time that the event was initially created.
756         * @param created the creation date-time or null to remove
757         * @see <a href="http://tools.ietf.org/html/rfc5545#page-136">RFC 5545
758         * p.136</a>
759         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.29</a>
760         */
761        public void setCreated(Created created) {
762                setProperty(Created.class, created);
763        }
764
765        /**
766         * Sets the date-time that the event was initially created.
767         * @param created the creation date-time or null to remove
768         * @return the property that was created
769         * @see <a href="http://tools.ietf.org/html/rfc5545#page-136">RFC 5545
770         * p.136</a>
771         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.29</a>
772         */
773        public Created setCreated(Date created) {
774                Created prop = (created == null) ? null : new Created(created);
775                setCreated(prop);
776                return prop;
777        }
778
779        /**
780         * Gets the date-time that the event was last changed.
781         * @return the last modified date or null if not set
782         * @see <a href="http://tools.ietf.org/html/rfc5545#page-138">RFC 5545
783         * p.138</a>
784         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.31</a>
785         */
786        public LastModified getLastModified() {
787                return getProperty(LastModified.class);
788        }
789
790        /**
791         * Sets the date-time that event was last changed.
792         * @param lastModified the last modified date or null to remove
793         * @see <a href="http://tools.ietf.org/html/rfc5545#page-138">RFC 5545
794         * p.138</a>
795         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.31</a>
796         */
797        public void setLastModified(LastModified lastModified) {
798                setProperty(LastModified.class, lastModified);
799        }
800
801        /**
802         * Sets the date-time that the event was last changed.
803         * @param lastModified the last modified date or null to remove
804         * @return the property that was created
805         * @see <a href="http://tools.ietf.org/html/rfc5545#page-138">RFC 5545
806         * p.138</a>
807         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.31</a>
808         */
809        public LastModified setLastModified(Date lastModified) {
810                LastModified prop = (lastModified == null) ? null : new LastModified(lastModified);
811                setLastModified(prop);
812                return prop;
813        }
814
815        /**
816         * Gets the revision number of the event. The organizer can increment this
817         * number every time he or she makes a significant change.
818         * @return the sequence number
819         * @see <a href="http://tools.ietf.org/html/rfc5545#page-138">RFC 5545
820         * p.138-9</a>
821         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.35</a>
822         */
823        public Sequence getSequence() {
824                return getProperty(Sequence.class);
825        }
826
827        /**
828         * Sets the revision number of the event. The organizer can increment this
829         * number every time he or she makes a significant change.
830         * @param sequence the sequence number
831         * @see <a href="http://tools.ietf.org/html/rfc5545#page-138">RFC 5545
832         * p.138-9</a>
833         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.35</a>
834         */
835        public void setSequence(Sequence sequence) {
836                setProperty(Sequence.class, sequence);
837        }
838
839        /**
840         * Sets the revision number of the event. The organizer can increment this
841         * number every time he or she makes a significant change.
842         * @param sequence the sequence number
843         * @return the property that was created
844         * @see <a href="http://tools.ietf.org/html/rfc5545#page-138">RFC 5545
845         * p.138-9</a>
846         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.35</a>
847         */
848        public Sequence setSequence(Integer sequence) {
849                Sequence prop = (sequence == null) ? null : new Sequence(sequence);
850                setSequence(prop);
851                return prop;
852        }
853
854        /**
855         * Increments the revision number of the event. The organizer can increment
856         * this number every time he or she makes a significant change.
857         * @see <a href="http://tools.ietf.org/html/rfc5545#page-138">RFC 5545
858         * p.138-9</a>
859         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.35</a>
860         */
861        public void incrementSequence() {
862                Sequence sequence = getSequence();
863                if (sequence == null) {
864                        setSequence(1);
865                } else {
866                        sequence.increment();
867                }
868        }
869
870        /**
871         * Gets any attachments that are associated with the event.
872         * @return the attachments
873         * @see <a href="http://tools.ietf.org/html/rfc5545#page-80">RFC 5545
874         * p.80-1</a>
875         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.25</a>
876         */
877        public List<Attachment> getAttachments() {
878                return getProperties(Attachment.class);
879        }
880
881        /**
882         * Adds an attachment to the event.
883         * @param attachment the attachment to add
884         * @see <a href="http://tools.ietf.org/html/rfc5545#page-80">RFC 5545
885         * p.80-1</a>
886         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.25</a>
887         */
888        public void addAttachment(Attachment attachment) {
889                addProperty(attachment);
890        }
891
892        /**
893         * Gets the people who are attending the event.
894         * @return the attendees
895         * @see <a href="http://tools.ietf.org/html/rfc5545#page-107">RFC 5545
896         * p.107-9</a>
897         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.25-7</a>
898         */
899        public List<Attendee> getAttendees() {
900                return getProperties(Attendee.class);
901        }
902
903        /**
904         * Adds a person who is attending the event.
905         * @param attendee the attendee
906         * @see <a href="http://tools.ietf.org/html/rfc5545#page-107">RFC 5545
907         * p.107-9</a>
908         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.25-7</a>
909         */
910        public void addAttendee(Attendee attendee) {
911                addProperty(attendee);
912        }
913
914        /**
915         * Adds a person who is attending the event.
916         * @param email the attendee's email address
917         * @return the property that was created
918         * @see <a href="http://tools.ietf.org/html/rfc5545#page-107">RFC 5545
919         * p.107-9</a>
920         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.25-7</a>
921         */
922        public Attendee addAttendee(String email) {
923                Attendee prop = new Attendee(null, email);
924                addAttendee(prop);
925                return prop;
926        }
927
928        /**
929         * Gets a list of "tags" or "keywords" that describe the event.
930         * @return the categories
931         * @see <a href="http://tools.ietf.org/html/rfc5545#page-81">RFC 5545
932         * p.81-2</a>
933         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.28</a>
934         */
935        public List<Categories> getCategories() {
936                return getProperties(Categories.class);
937        }
938
939        /**
940         * Adds a list of "tags" or "keywords" that describe the event. Note that a
941         * single property can hold multiple keywords.
942         * @param categories the categories to add
943         * @see <a href="http://tools.ietf.org/html/rfc5545#page-81">RFC 5545
944         * p.81-2</a>
945         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.28</a>
946         */
947        public void addCategories(Categories categories) {
948                addProperty(categories);
949        }
950
951        /**
952         * Adds a list of "tags" or "keywords" that describe the event.
953         * @param categories the categories to add
954         * @return the property that was created
955         * @see <a href="http://tools.ietf.org/html/rfc5545#page-81">RFC 5545
956         * p.81-2</a>
957         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.28</a>
958         */
959        public Categories addCategories(String... categories) {
960                Categories prop = new Categories(categories);
961                addCategories(prop);
962                return prop;
963        }
964
965        /**
966         * Adds a list of "tags" or "keywords" that describe the event.
967         * @param categories the categories to add
968         * @return the property that was created
969         * @see <a href="http://tools.ietf.org/html/rfc5545#page-81">RFC 5545
970         * p.81-2</a>
971         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.28</a>
972         */
973        public Categories addCategories(List<String> categories) {
974                Categories prop = new Categories(categories);
975                addCategories(prop);
976                return prop;
977        }
978
979        /**
980         * Gets the comments attached to the event.
981         * @return the comments
982         * @see <a href="http://tools.ietf.org/html/rfc5545#page-83">RFC 5545
983         * p.83-4</a>
984         */
985        public List<Comment> getComments() {
986                return getProperties(Comment.class);
987        }
988
989        /**
990         * Adds a comment to the event.
991         * @param comment the comment to add
992         * @see <a href="http://tools.ietf.org/html/rfc5545#page-83">RFC 5545
993         * p.83-4</a>
994         */
995        public void addComment(Comment comment) {
996                addProperty(comment);
997        }
998
999        /**
1000         * Adds a comment to the event.
1001         * @param comment the comment to add
1002         * @return the property that was created
1003         * @see <a href="http://tools.ietf.org/html/rfc5545#page-83">RFC 5545
1004         * p.83-4</a>
1005         */
1006        public Comment addComment(String comment) {
1007                Comment prop = new Comment(comment);
1008                addComment(prop);
1009                return prop;
1010        }
1011
1012        /**
1013         * Gets the contacts associated with the event.
1014         * @return the contacts
1015         * @see <a href="http://tools.ietf.org/html/rfc5545#page-109">RFC 5545
1016         * p.109-11</a>
1017         */
1018        public List<Contact> getContacts() {
1019                return getProperties(Contact.class);
1020        }
1021
1022        /**
1023         * Adds a contact to the event.
1024         * @param contact the contact
1025         * @see <a href="http://tools.ietf.org/html/rfc5545#page-109">RFC 5545
1026         * p.109-11</a>
1027         */
1028        public void addContact(Contact contact) {
1029                addProperty(contact);
1030        }
1031
1032        /**
1033         * Adds a contact to the event.
1034         * @param contact the contact (e.g. "ACME Co - (123) 555-1234")
1035         * @return the property that was created
1036         * @see <a href="http://tools.ietf.org/html/rfc5545#page-109">RFC 5545
1037         * p.109-11</a>
1038         */
1039        public Contact addContact(String contact) {
1040                Contact prop = new Contact(contact);
1041                addContact(prop);
1042                return prop;
1043        }
1044
1045        /**
1046         * Gets the list of exceptions to the recurrence rule defined in the event
1047         * (if one is defined).
1048         * @return the list of exceptions
1049         * @see <a href="http://tools.ietf.org/html/rfc5545#page-118">RFC 5545
1050         * p.118-20</a>
1051         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.31</a>
1052         */
1053        public List<ExceptionDates> getExceptionDates() {
1054                return getProperties(ExceptionDates.class);
1055        }
1056
1057        /**
1058         * Adds a list of exceptions to the recurrence rule defined in the event (if
1059         * one is defined). Note that this property can contain multiple dates.
1060         * @param exceptionDates the list of exceptions
1061         * @see <a href="http://tools.ietf.org/html/rfc5545#page-118">RFC 5545
1062         * p.118-20</a>
1063         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.31</a>
1064         */
1065        public void addExceptionDates(ExceptionDates exceptionDates) {
1066                addProperty(exceptionDates);
1067        }
1068
1069        /**
1070         * Gets the response to a scheduling request.
1071         * @return the response
1072         * @see <a href="http://tools.ietf.org/html/rfc5545#page-141">RFC 5545
1073         * p.141-3</a>
1074         */
1075        public RequestStatus getRequestStatus() {
1076                return getProperty(RequestStatus.class);
1077        }
1078
1079        /**
1080         * Sets the response to a scheduling request.
1081         * @param requestStatus the response
1082         * @see <a href="http://tools.ietf.org/html/rfc5545#page-141">RFC 5545
1083         * p.141-3</a>
1084         */
1085        public void setRequestStatus(RequestStatus requestStatus) {
1086                setProperty(RequestStatus.class, requestStatus);
1087        }
1088
1089        /**
1090         * Gets the components that the event is related to.
1091         * @return the relationships
1092         * @see <a href="http://tools.ietf.org/html/rfc5545#page-115">RFC 5545
1093         * p.115-6</a>
1094         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.33-4</a>
1095         */
1096        public List<RelatedTo> getRelatedTo() {
1097                return getProperties(RelatedTo.class);
1098        }
1099
1100        /**
1101         * Adds a component that the event is related to.
1102         * @param relatedTo the relationship
1103         * @see <a href="http://tools.ietf.org/html/rfc5545#page-115">RFC 5545
1104         * p.115-6</a>
1105         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.33-4</a>
1106         */
1107        public void addRelatedTo(RelatedTo relatedTo) {
1108                //TODO create a method that accepts a component and make the RelatedTo property invisible to the user
1109                //@formatter:off
1110                /*
1111                 * addRelation(RelationshipType relType, ICalComponent component){
1112                 *   RelatedTo prop = new RelatedTo(component.getUid().getValue());
1113                 *   prop.setRelationshipType(relType);
1114                 *   addProperty(prop);
1115                 * }
1116                 */
1117                //@formatter:on
1118                addProperty(relatedTo);
1119        }
1120
1121        /**
1122         * Adds a component that the event is related to.
1123         * @param uid the UID of the other component
1124         * @return the property that was created
1125         * @see <a href="http://tools.ietf.org/html/rfc5545#page-115">RFC 5545
1126         * p.115-6</a>
1127         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.33-4</a>
1128         */
1129        public RelatedTo addRelatedTo(String uid) {
1130                RelatedTo prop = new RelatedTo(uid);
1131                addRelatedTo(prop);
1132                return prop;
1133        }
1134
1135        /**
1136         * Gets the resources that are needed for the event.
1137         * @return the resources
1138         * @see <a href="http://tools.ietf.org/html/rfc5545#page-91">RFC 5545
1139         * p.91</a>
1140         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.34-5</a>
1141         */
1142        public List<Resources> getResources() {
1143                return getProperties(Resources.class);
1144        }
1145
1146        /**
1147         * Adds a list of resources that are needed for the event. Note that a
1148         * single property can hold multiple resources.
1149         * @param resources the resources to add
1150         * @see <a href="http://tools.ietf.org/html/rfc5545#page-91">RFC 5545
1151         * p.91</a>
1152         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.34-5</a>
1153         */
1154        public void addResources(Resources resources) {
1155                addProperty(resources);
1156        }
1157
1158        /**
1159         * Adds a list of resources that are needed for the event.
1160         * @param resources the resources to add (e.g. "easel", "projector")
1161         * @return the property that was created
1162         * @see <a href="http://tools.ietf.org/html/rfc5545#page-91">RFC 5545
1163         * p.91</a>
1164         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.34-5</a>
1165         */
1166        public Resources addResources(String... resources) {
1167                Resources prop = new Resources(resources);
1168                addResources(prop);
1169                return prop;
1170        }
1171
1172        /**
1173         * Adds a list of resources that are needed for the event.
1174         * @param resources the resources to add (e.g. "easel", "projector")
1175         * @return the property that was created
1176         * @see <a href="http://tools.ietf.org/html/rfc5545#page-91">RFC 5545
1177         * p.91</a>
1178         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.34-5</a>
1179         */
1180        public Resources addResources(List<String> resources) {
1181                Resources prop = new Resources(resources);
1182                addResources(prop);
1183                return prop;
1184        }
1185
1186        /**
1187         * Gets the list of dates/periods that help define the recurrence rule of
1188         * this event (if one is defined).
1189         * @return the recurrence dates
1190         * @see <a href="http://tools.ietf.org/html/rfc5545#page-120">RFC 5545
1191         * p.120-2</a>
1192         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.34</a>
1193         */
1194        public List<RecurrenceDates> getRecurrenceDates() {
1195                return getProperties(RecurrenceDates.class);
1196        }
1197
1198        /**
1199         * Adds a list of dates/periods that help define the recurrence rule of this
1200         * event (if one is defined).
1201         * @param recurrenceDates the recurrence dates
1202         * @see <a href="http://tools.ietf.org/html/rfc5545#page-120">RFC 5545
1203         * p.120-2</a>
1204         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.34</a>
1205         */
1206        public void addRecurrenceDates(RecurrenceDates recurrenceDates) {
1207                addProperty(recurrenceDates);
1208        }
1209
1210        /**
1211         * Gets the alarms that are assigned to this event.
1212         * @return the alarms
1213         * @see <a href="http://tools.ietf.org/html/rfc5545#page-71">RFC 5545
1214         * p.71-6</a>
1215         */
1216        public List<VAlarm> getAlarms() {
1217                return getComponents(VAlarm.class);
1218        }
1219
1220        /**
1221         * Adds an alarm to this event.
1222         * @param alarm the alarm
1223         * @see <a href="http://tools.ietf.org/html/rfc5545#page-71">RFC 5545
1224         * p.71-6</a>
1225         */
1226        public void addAlarm(VAlarm alarm) {
1227                addComponent(alarm);
1228        }
1229
1230        /**
1231         * <p>
1232         * Gets the exceptions for the {@link RecurrenceRule} property.
1233         * </p>
1234         * <p>
1235         * Note that this property has been removed from the latest version of the
1236         * iCal specification. Its use should be avoided.
1237         * </p>
1238         * @return the exception rules
1239         * @see <a href="http://tools.ietf.org/html/rfc2445#page-114">RFC 2445
1240         * p.114-15</a>
1241         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.31</a>
1242         */
1243        public List<ExceptionRule> getExceptionRules() {
1244                return getProperties(ExceptionRule.class);
1245        }
1246
1247        /**
1248         * <p>
1249         * Adds an exception for the {@link RecurrenceRule} property.
1250         * </p>
1251         * <p>
1252         * Note that this property has been removed from the latest version of the
1253         * iCal specification. Its use should be avoided.
1254         * </p>
1255         * @param recur the exception rule to add
1256         * @return the property that was created
1257         * @see <a href="http://tools.ietf.org/html/rfc2445#page-114">RFC 2445
1258         * p.114-15</a>
1259         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.31</a>
1260         */
1261        public ExceptionRule addExceptionRule(Recurrence recur) {
1262                ExceptionRule prop = new ExceptionRule(recur);
1263                addExceptionRule(prop);
1264                return prop;
1265        }
1266
1267        /**
1268         * <p>
1269         * Adds an exception for the {@link RecurrenceRule} property.
1270         * </p>
1271         * <p>
1272         * Note that this property has been removed from the latest version of the
1273         * iCal specification. Its use should be avoided.
1274         * </p>
1275         * @param exceptionRule the exception rule to add
1276         * @see <a href="http://tools.ietf.org/html/rfc2445#page-114">RFC 2445
1277         * p.114-15</a>
1278         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.31</a>
1279         */
1280        public void addExceptionRule(ExceptionRule exceptionRule) {
1281                addProperty(exceptionRule);
1282        }
1283
1284        @SuppressWarnings("unchecked")
1285        @Override
1286        protected void validate(List<ICalComponent> components, ICalVersion version, List<Warning> warnings) {
1287                if (version != ICalVersion.V1_0) {
1288                        checkRequiredCardinality(warnings, Uid.class, DateTimeStamp.class);
1289                        checkOptionalCardinality(warnings, Classification.class, Created.class, Description.class, Geo.class, LastModified.class, Location.class, Organizer.class, Priority.class, Status.class, Summary.class, Transparency.class, Url.class, RecurrenceId.class);
1290                }
1291
1292                Status validStatuses[];
1293                switch (version) {
1294                case V1_0:
1295                        validStatuses = new Status[] { Status.tentative(), Status.confirmed(), Status.cancelled(), Status.declined(), Status.delegated(), Status.sent() };
1296                        break;
1297                default:
1298                        validStatuses = new Status[] { Status.tentative(), Status.confirmed(), Status.cancelled() };
1299                        break;
1300                }
1301                checkStatus(warnings, validStatuses);
1302
1303                ICalDate dateStart = getValue(getDateStart());
1304                ICalDate dateEnd = getValue(getDateEnd());
1305
1306                //DTSTART is always required, unless there is a METHOD property at the iCal root
1307                ICalComponent ical = components.get(0);
1308                if (version != ICalVersion.V1_0 && dateStart == null && ical.getProperty(Method.class) == null) {
1309                        warnings.add(Warning.validate(14));
1310                }
1311
1312                //DTSTART is required if DTEND exists
1313                if (dateEnd != null && dateStart == null) {
1314                        warnings.add(Warning.validate(15));
1315                }
1316
1317                if (dateStart != null && dateEnd != null) {
1318                        //DTSTART must come before DTEND
1319                        if (dateStart.compareTo(dateEnd) > 0) {
1320                                warnings.add(Warning.validate(16));
1321                        }
1322
1323                        //DTSTART and DTEND must have the same data type
1324                        if (dateStart.hasTime() != dateEnd.hasTime()) {
1325                                warnings.add(Warning.validate(17));
1326                        }
1327                }
1328
1329                //DTEND and DURATION cannot both exist
1330                if (dateEnd != null && getDuration() != null) {
1331                        warnings.add(Warning.validate(18));
1332                }
1333
1334                //DTSTART and RECURRENCE-ID must have the same data type
1335                ICalDate recurrenceId = getValue(getRecurrenceId());
1336                if (recurrenceId != null && dateStart != null && dateStart.hasTime() != recurrenceId.hasTime()) {
1337                        warnings.add(Warning.validate(19));
1338                }
1339
1340                //BYHOUR, BYMINUTE, and BYSECOND cannot be specified in RRULE if DTSTART's data type is "date"
1341                //RFC 5545 p. 167
1342                Recurrence rrule = getValue(getRecurrenceRule());
1343                if (dateStart != null && rrule != null) {
1344                        if (!dateStart.hasTime() && (!rrule.getByHour().isEmpty() || !rrule.getByMinute().isEmpty() || !rrule.getBySecond().isEmpty())) {
1345                                warnings.add(Warning.validate(5));
1346                        }
1347                }
1348
1349                //there *should* be only 1 instance of RRULE
1350                //RFC 5545 p. 167
1351                if (getProperties(RecurrenceRule.class).size() > 1) {
1352                        warnings.add(Warning.validate(6));
1353                }
1354        }
1355}