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