001package biweekly.component;
002
003import java.util.Date;
004import java.util.List;
005
006import biweekly.Warning;
007import biweekly.property.Attachment;
008import biweekly.property.Attendee;
009import biweekly.property.Categories;
010import biweekly.property.Classification;
011import biweekly.property.Comment;
012import biweekly.property.Contact;
013import biweekly.property.Created;
014import biweekly.property.DateStart;
015import biweekly.property.DateTimeStamp;
016import biweekly.property.Description;
017import biweekly.property.ExceptionDates;
018import biweekly.property.ExceptionRule;
019import biweekly.property.LastModified;
020import biweekly.property.Method;
021import biweekly.property.Organizer;
022import biweekly.property.RecurrenceDates;
023import biweekly.property.RecurrenceId;
024import biweekly.property.RecurrenceRule;
025import biweekly.property.RelatedTo;
026import biweekly.property.RequestStatus;
027import biweekly.property.Sequence;
028import biweekly.property.Status;
029import biweekly.property.Summary;
030import biweekly.property.Uid;
031import biweekly.property.Url;
032import biweekly.util.Recurrence;
033
034/*
035 Copyright (c) 2013, Michael Angstadt
036 All rights reserved.
037
038 Redistribution and use in source and binary forms, with or without
039 modification, are permitted provided that the following conditions are met: 
040
041 1. Redistributions of source code must retain the above copyright notice, this
042 list of conditions and the following disclaimer. 
043 2. Redistributions in binary form must reproduce the above copyright notice,
044 this list of conditions and the following disclaimer in the documentation
045 and/or other materials provided with the distribution. 
046
047 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
048 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
049 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
050 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
051 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
052 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
053 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
054 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
055 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
056 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
057 */
058
059/**
060 * <p>
061 * Defines a journal entry.
062 * </p>
063 * <p>
064 * <b>Examples:</b>
065 * 
066 * <pre class="brush:java">
067 * VJournal journal = new VJournal();
068 * journal.setSummary("Team Meeting");
069 * journal.setDescription("The following items were discussed: ...");
070 * byte[] slides = ...
071 * journal.addAttachment(new Attachment("application/vnd.ms-powerpoint", slides));
072 * </pre>
073 * 
074 * </p>
075 * @author Michael Angstadt
076 * @see <a href="http://tools.ietf.org/html/rfc5545#page-57">RFC 5545 p.57-9</a>
077 */
078public class VJournal extends ICalComponent {
079        /**
080         * <p>
081         * Creates a new journal entry.
082         * </p>
083         * <p>
084         * The following properties are auto-generated on object creation. These
085         * properties <b>must</b> be present in order for the journal entry to be
086         * valid:
087         * <ul>
088         * <li>{@link Uid} - Set to a UUID.</li>
089         * <li>{@link DateTimeStamp} - Set to the current date-time.</li>
090         * </ul>
091         * </p>
092         */
093        public VJournal() {
094                setUid(Uid.random());
095                setDateTimeStamp(new Date());
096        }
097
098        /**
099         * Gets the unique identifier for this journal entry. This component object
100         * comes populated with a UID on creation. This is a <b>required</b>
101         * property.
102         * @return the UID or null if not set
103         * @see <a href="http://tools.ietf.org/html/rfc5545#page-117">RFC 5545
104         * p.117-8</a>
105         */
106        public Uid getUid() {
107                return getProperty(Uid.class);
108        }
109
110        /**
111         * Sets the unique identifier for this journal entry. This component object
112         * comes populated with a UID on creation. This is a <b>required</b>
113         * property.
114         * @param uid the UID or null to remove
115         * @see <a href="http://tools.ietf.org/html/rfc5545#page-117">RFC 5545
116         * p.117-8</a>
117         */
118        public void setUid(Uid uid) {
119                setProperty(Uid.class, uid);
120        }
121
122        /**
123         * Sets the unique identifier for this journal entry. This component object
124         * comes populated with a UID on creation. This is a <b>required</b>
125         * property.
126         * @param uid the UID or null to remove
127         * @return the property that was created
128         * @see <a href="http://tools.ietf.org/html/rfc5545#page-117">RFC 5545
129         * p.117-8</a>
130         */
131        public Uid setUid(String uid) {
132                Uid prop = (uid == null) ? null : new Uid(uid);
133                setUid(prop);
134                return prop;
135        }
136
137        /**
138         * Gets either (a) the creation date of the iCalendar object (if the
139         * {@link Method} property is defined) or (b) the date that the journal
140         * entry was last modified (the {@link LastModified} property also holds
141         * this information). This journal entry object comes populated with a
142         * {@link DateTimeStamp} property that is set to the current time. This is a
143         * <b>required</b> property.
144         * @return the date time stamp or null if not set
145         * @see <a href="http://tools.ietf.org/html/rfc5545#page-137">RFC 5545
146         * p.137-8</a>
147         */
148        public DateTimeStamp getDateTimeStamp() {
149                return getProperty(DateTimeStamp.class);
150        }
151
152        /**
153         * Sets either (a) the creation date of the iCalendar object (if the
154         * {@link Method} property is defined) or (b) the date that the journal
155         * entry was last modified (the {@link LastModified} property also holds
156         * this information). This journal entry object comes populated with a
157         * {@link DateTimeStamp} property that is set to the current time. This is a
158         * <b>required</b> property.
159         * @param dateTimeStamp the date time stamp or null to remove
160         * @see <a href="http://tools.ietf.org/html/rfc5545#page-137">RFC 5545
161         * p.137-8</a>
162         */
163        public void setDateTimeStamp(DateTimeStamp dateTimeStamp) {
164                setProperty(DateTimeStamp.class, dateTimeStamp);
165        }
166
167        /**
168         * Sets either (a) the creation date of the iCalendar object (if the
169         * {@link Method} property is defined) or (b) the date that the journal
170         * entry was last modified (the {@link LastModified} property also holds
171         * this information). This journal entry object comes populated with a
172         * {@link DateTimeStamp} property that is set to the current time. This is a
173         * <b>required</b> property.
174         * @param dateTimeStamp the date time stamp or null to remove
175         * @return the property that was created
176         * @see <a href="http://tools.ietf.org/html/rfc5545#page-137">RFC 5545
177         * p.137-8</a>
178         */
179        public DateTimeStamp setDateTimeStamp(Date dateTimeStamp) {
180                DateTimeStamp prop = (dateTimeStamp == null) ? null : new DateTimeStamp(dateTimeStamp);
181                setDateTimeStamp(prop);
182                return prop;
183        }
184
185        /**
186         * Gets the level of sensitivity of the journal entry. If not specified, the
187         * data within the journal entry should be considered "public".
188         * @return the classification level or null if not set
189         * @see <a href="http://tools.ietf.org/html/rfc5545#page-82">RFC 5545
190         * p.82-3</a>
191         */
192        public Classification getClassification() {
193                return getProperty(Classification.class);
194        }
195
196        /**
197         * Sets the level of sensitivity of the journal entry. If not specified, the
198         * data within the journal entry should be considered "public".
199         * @param classification the classification level or null to remove
200         * @see <a href="http://tools.ietf.org/html/rfc5545#page-82">RFC 5545
201         * p.82-3</a>
202         */
203        public void setClassification(Classification classification) {
204                setProperty(Classification.class, classification);
205        }
206
207        /**
208         * Sets the level of sensitivity of the journal entry. If not specified, the
209         * data within the journal entry should be considered "public".
210         * @param classification the classification level (e.g. "CONFIDENTIAL") or
211         * null to remove
212         * @return the property that was created
213         * @see <a href="http://tools.ietf.org/html/rfc5545#page-82">RFC 5545
214         * p.82-3</a>
215         */
216        public Classification setClassification(String classification) {
217                Classification prop = (classification == null) ? null : new Classification(classification);
218                setClassification(prop);
219                return prop;
220        }
221
222        /**
223         * Gets the date-time that the journal entry was initially created.
224         * @return the creation date-time or null if not set
225         * @see <a href="http://tools.ietf.org/html/rfc5545#page-136">RFC 5545
226         * p.136</a>
227         */
228        public Created getCreated() {
229                return getProperty(Created.class);
230        }
231
232        /**
233         * Sets the date-time that the journal entry was initially created.
234         * @param created the creation date-time or null to remove
235         * @see <a href="http://tools.ietf.org/html/rfc5545#page-136">RFC 5545
236         * p.136</a>
237         */
238        public void setCreated(Created created) {
239                setProperty(Created.class, created);
240        }
241
242        /**
243         * Sets the date-time that the journal entry was initially created.
244         * @param created the creation date-time or null to remove
245         * @return the property that was created
246         * @see <a href="http://tools.ietf.org/html/rfc5545#page-136">RFC 5545
247         * p.136</a>
248         */
249        public Created setCreated(Date created) {
250                Created prop = (created == null) ? null : new Created(created);
251                setCreated(prop);
252                return prop;
253        }
254
255        /**
256         * Gets the date that the journal entry starts.
257         * @return the start date or null if not set
258         * @see <a href="http://tools.ietf.org/html/rfc5545#page-97">RFC 5545
259         * p.97-8</a>
260         */
261        public DateStart getDateStart() {
262                return getProperty(DateStart.class);
263        }
264
265        /**
266         * Sets the date that the journal entry starts.
267         * @param dateStart the start date or null to remove
268         * @see <a href="http://tools.ietf.org/html/rfc5545#page-97">RFC 5545
269         * p.97-8</a>
270         */
271        public void setDateStart(DateStart dateStart) {
272                setProperty(DateStart.class, dateStart);
273        }
274
275        /**
276         * Sets the date that the journal entry starts.
277         * @param dateStart the start date or null to remove
278         * @return the property that was created
279         * @see <a href="http://tools.ietf.org/html/rfc5545#page-97">RFC 5545
280         * p.97-8</a>
281         */
282        public DateStart setDateStart(Date dateStart) {
283                DateStart prop = (dateStart == null) ? null : new DateStart(dateStart);
284                setDateStart(prop);
285                return prop;
286        }
287
288        /**
289         * Gets the date-time that the journal entry was last changed.
290         * @return the last modified date or null if not set
291         * @see <a href="http://tools.ietf.org/html/rfc5545#page-138">RFC 5545
292         * p.138</a>
293         */
294        public LastModified getLastModified() {
295                return getProperty(LastModified.class);
296        }
297
298        /**
299         * Sets the date-time that the journal entry was last changed.
300         * @param lastModified the last modified date or null to remove
301         * @see <a href="http://tools.ietf.org/html/rfc5545#page-138">RFC 5545
302         * p.138</a>
303         */
304        public void setLastModified(LastModified lastModified) {
305                setProperty(LastModified.class, lastModified);
306        }
307
308        /**
309         * Sets the date-time that the journal entry was last changed.
310         * @param lastModified the last modified date or null to remove
311         * @return the property that was created
312         * @see <a href="http://tools.ietf.org/html/rfc5545#page-138">RFC 5545
313         * p.138</a>
314         */
315        public LastModified setLastModified(Date lastModified) {
316                LastModified prop = (lastModified == null) ? null : new LastModified(lastModified);
317                setLastModified(prop);
318                return prop;
319        }
320
321        /**
322         * Gets the organizer of the journal entry.
323         * @return the organizer or null if not set
324         * @see <a href="http://tools.ietf.org/html/rfc5545#page-111">RFC 5545
325         * p.111-2</a>
326         */
327        public Organizer getOrganizer() {
328                return getProperty(Organizer.class);
329        }
330
331        /**
332         * Sets the organizer of the journal entry.
333         * @param organizer the organizer or null to remove
334         * @see <a href="http://tools.ietf.org/html/rfc5545#page-111">RFC 5545
335         * p.111-2</a>
336         */
337        public void setOrganizer(Organizer organizer) {
338                setProperty(Organizer.class, organizer);
339        }
340
341        /**
342         * Sets the organizer of the journal entry.
343         * @param email the organizer's email address (e.g. "johndoe@example.com")
344         * or null to remove
345         * @return the property that was created
346         * @see <a href="http://tools.ietf.org/html/rfc5545#page-111">RFC 5545
347         * p.111-2</a>
348         */
349        public Organizer setOrganizer(String email) {
350                Organizer prop = (email == null) ? null : Organizer.email(email);
351                setOrganizer(prop);
352                return prop;
353        }
354
355        /**
356         * Gets the original value of the {@link DateStart} property if the event is
357         * recurring and has been modified. Used in conjunction with the {@link Uid}
358         * and {@link Sequence} properties to uniquely identify a recurrence
359         * instance.
360         * @return the recurrence ID or null if not set
361         * @see <a href="http://tools.ietf.org/html/rfc5545#page-112">RFC 5545
362         * p.112-4</a>
363         */
364        public RecurrenceId getRecurrenceId() {
365                return getProperty(RecurrenceId.class);
366        }
367
368        /**
369         * Sets the original value of the {@link DateStart} property if the event is
370         * recurring and has been modified. Used in conjunction with the {@link Uid}
371         * and {@link Sequence} properties to uniquely identify a recurrence
372         * instance.
373         * @param recurrenceId the recurrence ID or null to remove
374         * @see <a href="http://tools.ietf.org/html/rfc5545#page-112">RFC 5545
375         * p.112-4</a>
376         */
377        public void setRecurrenceId(RecurrenceId recurrenceId) {
378                setProperty(RecurrenceId.class, recurrenceId);
379        }
380
381        /**
382         * Sets the original value of the {@link DateStart} property if the journal
383         * entry is recurring and has been modified. Used in conjunction with the
384         * {@link Uid} and {@link Sequence} properties to uniquely identify a
385         * recurrence instance.
386         * @param originalStartDate the original start date or null to remove
387         * @return the property that was created
388         * @see <a href="http://tools.ietf.org/html/rfc5545#page-112">RFC 5545
389         * p.112-4</a>
390         */
391        public RecurrenceId setRecurrenceId(Date originalStartDate) {
392                RecurrenceId prop = (originalStartDate == null) ? null : new RecurrenceId(originalStartDate);
393                setRecurrenceId(prop);
394                return prop;
395        }
396
397        /**
398         * Gets the revision number of the journal entry. The organizer can
399         * increment this number every time he or she makes a significant change.
400         * @return the sequence number
401         * @see <a href="http://tools.ietf.org/html/rfc5545#page-138">RFC 5545
402         * p.138-9</a>
403         */
404        public Sequence getSequence() {
405                return getProperty(Sequence.class);
406        }
407
408        /**
409         * Sets the revision number of the journal entry. The organizer can
410         * increment this number every time he or she makes a significant change.
411         * @param sequence the sequence number
412         * @see <a href="http://tools.ietf.org/html/rfc5545#page-138">RFC 5545
413         * p.138-9</a>
414         */
415        public void setSequence(Sequence sequence) {
416                setProperty(Sequence.class, sequence);
417        }
418
419        /**
420         * Sets the revision number of the journal entry. The organizer can
421         * increment this number every time he or she makes a significant change.
422         * @param sequence the sequence number
423         * @return the property that was created
424         * @see <a href="http://tools.ietf.org/html/rfc5545#page-138">RFC 5545
425         * p.138-9</a>
426         */
427        public Sequence setSequence(Integer sequence) {
428                Sequence prop = (sequence == null) ? null : new Sequence(sequence);
429                setSequence(prop);
430                return prop;
431        }
432
433        /**
434         * Increments the revision number of the journal entry. The organizer can
435         * increment this number every time he or she makes a significant change.
436         * @see <a href="http://tools.ietf.org/html/rfc5545#page-138">RFC 5545
437         * p.138-9</a>
438         */
439        public void incrementSequence() {
440                Sequence sequence = getSequence();
441                if (sequence == null) {
442                        setSequence(1);
443                } else {
444                        sequence.increment();
445                }
446        }
447
448        /**
449         * Gets the status of the journal entry.
450         * @return the status or null if not set
451         * @see <a href="http://tools.ietf.org/html/rfc5545#page-92">RFC 5545
452         * p.92-3</a>
453         */
454        public Status getStatus() {
455                return getProperty(Status.class);
456        }
457
458        /**
459         * Sets the status of the journal entry.
460         * <p>
461         * Valid journal status codes are:
462         * <ul>
463         * <li>DRAFT</li>
464         * <li>FINAL</li>
465         * <li>CANCELLED</li>
466         * </ul>
467         * </p>
468         * @param status the status or null to remove
469         * @see <a href="http://tools.ietf.org/html/rfc5545#page-92">RFC 5545
470         * p.92-3</a>
471         */
472        public void setStatus(Status status) {
473                setProperty(Status.class, status);
474        }
475
476        /**
477         * Gets the summary of the journal entry.
478         * @return the summary or null if not set
479         * @see <a href="http://tools.ietf.org/html/rfc5545#page-93">RFC 5545
480         * p.93-4</a>
481         */
482        public Summary getSummary() {
483                return getProperty(Summary.class);
484        }
485
486        /**
487         * Sets the summary of the journal entry.
488         * @param summary the summary or null to remove
489         * @see <a href="http://tools.ietf.org/html/rfc5545#page-93">RFC 5545
490         * p.93-4</a>
491         */
492        public void setSummary(Summary summary) {
493                setProperty(Summary.class, summary);
494        }
495
496        /**
497         * Sets the summary of the journal entry.
498         * @param summary the summary or null to remove
499         * @return the property that was created
500         * @see <a href="http://tools.ietf.org/html/rfc5545#page-93">RFC 5545
501         * p.93-4</a>
502         */
503        public Summary setSummary(String summary) {
504                Summary prop = (summary == null) ? null : new Summary(summary);
505                setSummary(prop);
506                return prop;
507        }
508
509        /**
510         * Gets a URL to a resource that contains additional information about the
511         * journal entry.
512         * @return the URL or null if not set
513         * @see <a href="http://tools.ietf.org/html/rfc5545#page-116">RFC 5545
514         * p.116-7</a>
515         */
516        public Url getUrl() {
517                return getProperty(Url.class);
518        }
519
520        /**
521         * Sets a URL to a resource that contains additional information about the
522         * journal entry.
523         * @param url the URL or null to remove
524         * @see <a href="http://tools.ietf.org/html/rfc5545#page-116">RFC 5545
525         * p.116-7</a>
526         */
527        public void setUrl(Url url) {
528                setProperty(Url.class, url);
529        }
530
531        /**
532         * Sets a URL to a resource that contains additional information about the
533         * journal entry.
534         * @param url the URL (e.g. "http://example.com/resource.ics") or null to
535         * remove
536         * @return the property that was created
537         * @see <a href="http://tools.ietf.org/html/rfc5545#page-116">RFC 5545
538         * p.116-7</a>
539         */
540        public Url setUrl(String url) {
541                Url prop = (url == null) ? null : new Url(url);
542                setUrl(prop);
543                return prop;
544        }
545
546        /**
547         * Gets how often the journal entry repeats.
548         * @return the recurrence rule or null if not set
549         * @see <a href="http://tools.ietf.org/html/rfc5545#page-122">RFC 5545
550         * p.122-32</a>
551         */
552        public RecurrenceRule getRecurrenceRule() {
553                return getProperty(RecurrenceRule.class);
554        }
555
556        /**
557         * Sets how often the journal entry repeats.
558         * @param recur the recurrence rule or null to remove
559         * @return the property that was created
560         * @see <a href="http://tools.ietf.org/html/rfc5545#page-122">RFC 5545
561         * p.122-32</a>
562         */
563        public RecurrenceRule setRecurrenceRule(Recurrence recur) {
564                RecurrenceRule prop = (recur == null) ? null : new RecurrenceRule(recur);
565                setRecurrenceRule(prop);
566                return prop;
567        }
568
569        /**
570         * Sets how often the journal entry repeats.
571         * @param recurrenceRule the recurrence rule or null to remove
572         * @see <a href="http://tools.ietf.org/html/rfc5545#page-122">RFC 5545
573         * p.122-32</a>
574         */
575        public void setRecurrenceRule(RecurrenceRule recurrenceRule) {
576                setProperty(RecurrenceRule.class, recurrenceRule);
577        }
578
579        /**
580         * Gets any attachments that are associated with the journal entry.
581         * @return the attachments
582         * @see <a href="http://tools.ietf.org/html/rfc5545#page-80">RFC 5545
583         * p.80-1</a>
584         */
585        public List<Attachment> getAttachments() {
586                return getProperties(Attachment.class);
587        }
588
589        /**
590         * Adds an attachment to the journal entry.
591         * @param attachment the attachment to add
592         * @see <a href="http://tools.ietf.org/html/rfc5545#page-80">RFC 5545
593         * p.80-1</a>
594         */
595        public void addAttachment(Attachment attachment) {
596                addProperty(attachment);
597        }
598
599        /**
600         * Gets the people who are involved in the journal entry.
601         * @return the attendees
602         * @see <a href="http://tools.ietf.org/html/rfc5545#page-107">RFC 5545
603         * p.107-9</a>
604         */
605        public List<Attendee> getAttendees() {
606                return getProperties(Attendee.class);
607        }
608
609        /**
610         * Adds a person who is involved in the journal entry.
611         * @param attendee the attendee
612         * @see <a href="http://tools.ietf.org/html/rfc5545#page-107">RFC 5545
613         * p.107-9</a>
614         */
615        public void addAttendee(Attendee attendee) {
616                addProperty(attendee);
617        }
618
619        /**
620         * Adds a person who is involved in the journal entry.
621         * @param email the attendee's email address
622         * @return the property that was created
623         * @see <a href="http://tools.ietf.org/html/rfc5545#page-107">RFC 5545
624         * p.107-9</a>
625         */
626        public Attendee addAttendee(String email) {
627                Attendee prop = Attendee.email(email);
628                addAttendee(prop);
629                return prop;
630        }
631
632        /**
633         * Gets a list of "tags" or "keywords" that describe the journal entry.
634         * @return the categories
635         * @see <a href="http://tools.ietf.org/html/rfc5545#page-81">RFC 5545
636         * p.81-2</a>
637         */
638        public List<Categories> getCategories() {
639                return getProperties(Categories.class);
640        }
641
642        /**
643         * Adds a list of "tags" or "keywords" that describe the journal entry. Note
644         * that a single property can hold multiple keywords.
645         * @param categories the categories to add
646         * @see <a href="http://tools.ietf.org/html/rfc5545#page-81">RFC 5545
647         * p.81-2</a>
648         */
649        public void addCategories(Categories categories) {
650                addProperty(categories);
651        }
652
653        /**
654         * Adds a list of "tags" or "keywords" that describe the journal entry.
655         * @param categories the categories to add
656         * @return the property that was created
657         * @see <a href="http://tools.ietf.org/html/rfc5545#page-81">RFC 5545
658         * p.81-2</a>
659         */
660        public Categories addCategories(String... categories) {
661                Categories prop = new Categories(categories);
662                addCategories(prop);
663                return prop;
664        }
665
666        /**
667         * Adds a list of "tags" or "keywords" that describe the journal entry.
668         * @param categories the categories to add
669         * @return the property that was created
670         * @see <a href="http://tools.ietf.org/html/rfc5545#page-81">RFC 5545
671         * p.81-2</a>
672         */
673        public Categories addCategories(List<String> categories) {
674                Categories prop = new Categories(categories);
675                addCategories(prop);
676                return prop;
677        }
678
679        /**
680         * Gets the comments attached to the journal entry.
681         * @return the comments
682         * @see <a href="http://tools.ietf.org/html/rfc5545#page-83">RFC 5545
683         * p.83-4</a>
684         */
685        public List<Comment> getComments() {
686                return getProperties(Comment.class);
687        }
688
689        /**
690         * Adds a comment to the journal entry.
691         * @param comment the comment to add
692         * @see <a href="http://tools.ietf.org/html/rfc5545#page-83">RFC 5545
693         * p.83-4</a>
694         */
695        public void addComment(Comment comment) {
696                addProperty(comment);
697        }
698
699        /**
700         * Adds a comment to the journal entry.
701         * @param comment the comment to add
702         * @return the property that was created
703         * @see <a href="http://tools.ietf.org/html/rfc5545#page-83">RFC 5545
704         * p.83-4</a>
705         */
706        public Comment addComment(String comment) {
707                Comment prop = new Comment(comment);
708                addComment(prop);
709                return prop;
710        }
711
712        /**
713         * Gets the contacts associated with the journal entry.
714         * @return the contacts
715         * @see <a href="http://tools.ietf.org/html/rfc5545#page-109">RFC 5545
716         * p.109-11</a>
717         */
718        public List<Contact> getContacts() {
719                return getProperties(Contact.class);
720        }
721
722        /**
723         * Adds a contact to the journal entry.
724         * @param contact the contact
725         * @see <a href="http://tools.ietf.org/html/rfc5545#page-109">RFC 5545
726         * p.109-11</a>
727         */
728        public void addContact(Contact contact) {
729                addProperty(contact);
730        }
731
732        /**
733         * Adds a contact to the journal entry.
734         * @param contact the contact (e.g. "ACME Co - (123) 555-1234")
735         * @return the property that was created
736         * @see <a href="http://tools.ietf.org/html/rfc5545#page-109">RFC 5545
737         * p.109-11</a>
738         */
739        public Contact addContact(String contact) {
740                Contact prop = new Contact(contact);
741                addContact(prop);
742                return prop;
743        }
744
745        /**
746         * Gets the detailed descriptions to the journal entry. The descriptions
747         * should be a more detailed version of the one provided by the
748         * {@link Summary} property.
749         * @return the descriptions
750         * @see <a href="http://tools.ietf.org/html/rfc5545#page-84">RFC 5545
751         * p.84-5</a>
752         */
753        public List<Description> getDescriptions() {
754                return getProperties(Description.class);
755        }
756
757        /**
758         * Adds a detailed description to the journal entry. The description should
759         * be a more detailed version of the one provided by the {@link Summary}
760         * property.
761         * @param description the description
762         * @see <a href="http://tools.ietf.org/html/rfc5545#page-84">RFC 5545
763         * p.84-5</a>
764         */
765        public void addDescription(Description description) {
766                addProperty(description);
767        }
768
769        /**
770         * Adds a detailed description to the journal entry. The description should
771         * be a more detailed version of the one provided by the {@link Summary}
772         * property.
773         * @param description the description
774         * @return the property that was created
775         * @see <a href="http://tools.ietf.org/html/rfc5545#page-84">RFC 5545
776         * p.84-5</a>
777         */
778        public Description addDescription(String description) {
779                Description prop = new Description(description);
780                addDescription(prop);
781                return prop;
782        }
783
784        /**
785         * Gets the list of exceptions to the recurrence rule defined in the journal
786         * entry (if one is defined).
787         * @return the list of exceptions
788         * @see <a href="http://tools.ietf.org/html/rfc5545#page-118">RFC 5545
789         * p.118-20</a>
790         */
791        public List<ExceptionDates> getExceptionDates() {
792                return getProperties(ExceptionDates.class);
793        }
794
795        /**
796         * Adds a list of exceptions to the recurrence rule defined in the journal
797         * entry (if one is defined). Note that this property can contain multiple
798         * dates.
799         * @param exceptionDates the list of exceptions
800         * @see <a href="http://tools.ietf.org/html/rfc5545#page-118">RFC 5545
801         * p.118-20</a>
802         */
803        public void addExceptionDates(ExceptionDates exceptionDates) {
804                addProperty(exceptionDates);
805        }
806
807        /**
808         * Gets the components that the journal entry is related to.
809         * @return the relationships
810         * @see <a href="http://tools.ietf.org/html/rfc5545#page-115">RFC 5545
811         * p.115-6</a>
812         */
813        public List<RelatedTo> getRelatedTo() {
814                return getProperties(RelatedTo.class);
815        }
816
817        /**
818         * Adds a component that the journal entry is related to.
819         * @param relatedTo the relationship
820         * @see <a href="http://tools.ietf.org/html/rfc5545#page-115">RFC 5545
821         * p.115-6</a>
822         */
823        public void addRelatedTo(RelatedTo relatedTo) {
824                //TODO create a method that accepts a component and make the RelatedTo property invisible to the user
825                //@formatter:off
826                /*
827                 * addRelation(RelationshipType relType, ICalComponent component){
828                 *   RelatedTo prop = new RelatedTo(component.getUid().getValue());
829                 *   prop.setRelationshipType(relType);
830                 *   addProperty(prop);
831                 * }
832                 */
833                //@formatter:on
834                addProperty(relatedTo);
835        }
836
837        /**
838         * Adds a component that the journal entry is related to.
839         * @param uid the UID of the other component
840         * @return the property that was created
841         * @see <a href="http://tools.ietf.org/html/rfc5545#page-115">RFC 5545
842         * p.115-6</a>
843         */
844        public RelatedTo addRelatedTo(String uid) {
845                RelatedTo prop = new RelatedTo(uid);
846                addRelatedTo(prop);
847                return prop;
848        }
849
850        /**
851         * Gets the list of dates/periods that help define the recurrence rule of
852         * this journal entry (if one is defined).
853         * @return the recurrence dates
854         * @see <a href="http://tools.ietf.org/html/rfc5545#page-120">RFC 5545
855         * p.120-2</a>
856         */
857        public List<RecurrenceDates> getRecurrenceDates() {
858                return getProperties(RecurrenceDates.class);
859        }
860
861        /**
862         * Adds a list of dates/periods that help define the recurrence rule of this
863         * journal entry (if one is defined).
864         * @param recurrenceDates the recurrence dates
865         * @see <a href="http://tools.ietf.org/html/rfc5545#page-120">RFC 5545
866         * p.120-2</a>
867         */
868        public void addRecurrenceDates(RecurrenceDates recurrenceDates) {
869                addProperty(recurrenceDates);
870        }
871
872        /**
873         * Gets the response to a scheduling request.
874         * @return the response
875         * @see <a href="http://tools.ietf.org/html/rfc5545#page-141">RFC 5545
876         * p.141-3</a>
877         */
878        public RequestStatus getRequestStatus() {
879                return getProperty(RequestStatus.class);
880        }
881
882        /**
883         * Sets the response to a scheduling request.
884         * @param requestStatus the response
885         * @see <a href="http://tools.ietf.org/html/rfc5545#page-141">RFC 5545
886         * p.141-3</a>
887         */
888        public void setRequestStatus(RequestStatus requestStatus) {
889                setProperty(RequestStatus.class, requestStatus);
890        }
891
892        /**
893         * <p>
894         * Gets the exceptions for the {@link RecurrenceRule} property.
895         * </p>
896         * <p>
897         * Note that this property has been removed from the latest version of the
898         * iCal specification. Its use should be avoided.
899         * </p>
900         * @return the exception rules
901         * @see <a href="http://tools.ietf.org/html/rfc2445#page-114">RFC 2445
902         * p.114-15</a>
903         */
904        public List<ExceptionRule> getExceptionRules() {
905                return getProperties(ExceptionRule.class);
906        }
907
908        /**
909         * <p>
910         * Adds an exception for the {@link RecurrenceRule} property.
911         * </p>
912         * <p>
913         * Note that this property has been removed from the latest version of the
914         * iCal specification. Its use should be avoided.
915         * </p>
916         * @param recur the exception rule to add
917         * @return the property that was created
918         * @see <a href="http://tools.ietf.org/html/rfc2445#page-114">RFC 2445
919         * p.114-15</a>
920         */
921        public ExceptionRule addExceptionRule(Recurrence recur) {
922                ExceptionRule prop = new ExceptionRule(recur);
923                addExceptionRule(prop);
924                return prop;
925        }
926
927        /**
928         * <p>
929         * Adds an exception for the {@link RecurrenceRule} property.
930         * </p>
931         * <p>
932         * Note that this property has been removed from the latest version of the
933         * iCal specification. Its use should be avoided.
934         * </p>
935         * @param exceptionRule the exception rule to add
936         * @see <a href="http://tools.ietf.org/html/rfc2445#page-114">RFC 2445
937         * p.114-15</a>
938         */
939        public void addExceptionRule(ExceptionRule exceptionRule) {
940                addProperty(exceptionRule);
941        }
942
943        @SuppressWarnings("unchecked")
944        @Override
945        protected void validate(List<ICalComponent> components, List<Warning> warnings) {
946                checkRequiredCardinality(warnings, Uid.class, DateTimeStamp.class);
947                checkOptionalCardinality(warnings, Classification.class, Created.class, DateStart.class, LastModified.class, Organizer.class, RecurrenceId.class, Sequence.class, Status.class, Summary.class, Url.class);
948                checkStatus(warnings, Status.draft(), Status.final_(), Status.cancelled());
949
950                //DTSTART and RECURRENCE-ID must have the same data type
951                RecurrenceId recurrenceId = getRecurrenceId();
952                DateStart dateStart = getDateStart();
953                if (recurrenceId != null && dateStart != null && dateStart.hasTime() != recurrenceId.hasTime()) {
954                        warnings.add(Warning.validate(19));
955                }
956
957                //BYHOUR, BYMINUTE, and BYSECOND cannot be specified in RRULE if DTSTART's data type is "date"
958                //RFC 5545 p. 167
959                RecurrenceRule rrule = getRecurrenceRule();
960                if (dateStart != null && rrule != null) {
961                        Date start = dateStart.getValue();
962                        Recurrence recur = rrule.getValue();
963                        if (start != null && recur != null) {
964                                if (!dateStart.hasTime() && (!recur.getByHour().isEmpty() || !recur.getByMinute().isEmpty() || !recur.getBySecond().isEmpty())) {
965                                        warnings.add(Warning.validate(5));
966                                }
967                        }
968                }
969
970                //there *should* be only 1 instance of RRULE
971                //RFC 5545 p. 167
972                if (getProperties(RecurrenceRule.class).size() > 1) {
973                        warnings.add(Warning.validate(6));
974                }
975        }
976}