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