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