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