001package biweekly.parameter;
002
003import java.util.AbstractList;
004import java.util.ArrayList;
005import java.util.Arrays;
006import java.util.Collections;
007import java.util.List;
008import java.util.Map;
009
010import com.github.mangstadt.vinnie.SyntaxStyle;
011import com.github.mangstadt.vinnie.validate.AllowedCharacters;
012import com.github.mangstadt.vinnie.validate.VObjectValidator;
013
014import biweekly.ICalDataType;
015import biweekly.ICalVersion;
016import biweekly.Messages;
017import biweekly.ValidationWarning;
018import biweekly.property.Attendee;
019import biweekly.property.Conference;
020import biweekly.property.FreeBusy;
021import biweekly.property.Image;
022import biweekly.property.Organizer;
023import biweekly.property.RecurrenceId;
024import biweekly.property.RelatedTo;
025import biweekly.property.Trigger;
026import biweekly.util.ListMultimap;
027
028/*
029 Copyright (c) 2013-2017, Michael Angstadt
030 All rights reserved.
031
032 Redistribution and use in source and binary forms, with or without
033 modification, are permitted provided that the following conditions are met: 
034
035 1. Redistributions of source code must retain the above copyright notice, this
036 list of conditions and the following disclaimer. 
037 2. Redistributions in binary form must reproduce the above copyright notice,
038 this list of conditions and the following disclaimer in the documentation
039 and/or other materials provided with the distribution. 
040
041 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
042 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
043 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
044 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
045 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
046 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
047 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
048 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
049 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
050 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
051 */
052
053/**
054 * Stores the parameters that belong to a property.
055 * @author Michael Angstadt
056 */
057public class ICalParameters extends ListMultimap<String, String> {
058        /**
059         * Contains a URI that points to additional information about the entity
060         * represented by the property.
061         * @see <a href="http://tools.ietf.org/html/rfc5545#page-14">RFC 5545
062         * p.14-5</a>
063         */
064        public static final String ALTREP = "ALTREP";
065
066        /**
067         * Defines the character set that the property value is encoded in (for
068         * example, "UTF-8"). It is only used in the vCal 1.0 standard, and is
069         * typically used when a property value is encoded in quoted-printable
070         * encoding.
071         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.16</a>
072         */
073        public static final String CHARSET = "CHARSET";
074
075        /**
076         * Contains a human-readable, display name of the entity represented by this
077         * property (for example, "John Doe"). It is used by the {@link Attendee}
078         * and {@link Organizer} properties.
079         * @see <a href="http://tools.ietf.org/html/rfc5545#page-15">RFC 5545
080         * p.15-6</a>
081         */
082        public static final String CN = "CN";
083
084        /**
085         * Used by the {@link Attendee} property. It defines the type of object that
086         * the attendee is (for example, an "individual" or a "room").
087         * @see <a href="http://tools.ietf.org/html/rfc5545#page-16">RFC 5545
088         * p.16</a>
089         */
090        public static final String CUTYPE = "CUTYPE";
091
092        /**
093         * Used by the {@link Attendee} property. It stores a list of people who
094         * have delegated their responsibility to the attendee. The values must be
095         * URIs. They are typically email URIs (for example,
096         * "mailto:janedoe@example.com").
097         * @see <a href="http://tools.ietf.org/html/rfc5545#page-17">RFC 5545
098         * p.17</a>
099         */
100        public static final String DELEGATED_FROM = "DELEGATED-FROM";
101
102        /**
103         * Used by the {@link Attendee} property. It stores a list of people to
104         * which the attendee has delegated his or her responsibility. The values
105         * must be URIs. They are typically email URIs (for example,
106         * "mailto:janedoe@example.com").
107         * @see <a href="http://tools.ietf.org/html/rfc5545#page-17">RFC 5545
108         * p.17-8</a>
109         */
110        public static final String DELEGATED_TO = "DELEGATED-TO";
111
112        /**
113         * Contains a URI (such as an LDAP URI) which points to additional
114         * information about the person that the property represents. It is used by
115         * the {@link Attendee} and {@link Organizer} properties.
116         * @see <a href="http://tools.ietf.org/html/rfc5545#page-18">RFC 5545
117         * p.18</a>
118         */
119        public static final String DIR = "DIR";
120
121        /**
122         * Used by the {@link Image} property. It defines the ways in which the
123         * client application should display the image (for example, as a
124         * thumbnail-sized image).
125         * @see <a href=
126         * "https://tools.ietf.org/html/draft-ietf-calext-extensions-01#page-13" >
127         * draft-ietf-calext-extensions p.13</a>
128         */
129        public static final String DISPLAY = "DISPLAY";
130
131        /**
132         * Used by the {@link Attendee} property. Normally, this property's value
133         * contains the email address of the attendee. But if the property value
134         * must hold something else, this parameter can be used to store the
135         * attendee's email address.
136         * @see <a href=
137         * "https://tools.ietf.org/html/draft-ietf-calext-extensions-01#page-14" >
138         * draft-ietf-calext-extensions p.14</a>
139         */
140        public static final String EMAIL = "EMAIL";
141
142        /**
143         * Defines how the property value is encoded (for example, "base64" for a
144         * binary value).
145         * @see <a href="http://tools.ietf.org/html/rfc5545#page-18">RFC 5545
146         * p.18-9</a>
147         */
148        public static final String ENCODING = "ENCODING";
149
150        /**
151         * Used by the {@link Attendee} property. It defines whether the event
152         * organizer expects the attendee to attend or not. It is only used in the
153         * vCal 1.0 standard.
154         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.25</a>
155         */
156        public static final String EXPECT = "EXPECT";
157
158        /**
159         * Used by the {@link Conference} property. It defines the features that the
160         * conference supports (for example, audio and video).
161         * @see <a href=
162         * "https://tools.ietf.org/html/draft-ietf-calext-extensions-01#page-15" >
163         * draft-ietf-calext-extensions p.15</a>
164         */
165        public static final String FEATURE = "FEATURE";
166
167        /**
168         * Defines the content type of the property value (for example, "image/jpg"
169         * if the property value is a JPEG image).
170         * @see <a href="http://tools.ietf.org/html/rfc5545#page-19">RFC 5545
171         * p.19-20</a>
172         */
173        public static final String FMTTYPE = "FMTTYPE";
174
175        /**
176         * Used by the {@link FreeBusy} property. It defines whether the person is
177         * "free" or "busy" over the time periods that are specified in the property
178         * value. If this parameter is not set, the user should be considered "busy"
179         * during these times.
180         * @see <a href="http://tools.ietf.org/html/rfc5545#page-20">RFC 5545
181         * p.20</a>
182         */
183        public static final String FBTYPE = "FBTYPE";
184
185        /**
186         * Defines a human-readable label for the property.
187         * @see <a href=
188         * "http://tools.ietf.org/html/draft-ietf-calext-extensions-01#page-16">
189         * draft-ietf-calext-extensions-01 p.16</a>
190         */
191        public static final String LABEL = "LABEL";
192
193        /**
194         * Defines the language that the property value is written in (for example,
195         * "en" for English).
196         * @see <a href="http://tools.ietf.org/html/rfc5545#page-21">RFC 5545
197         * p.21</a>
198         */
199        public static final String LANGUAGE = "LANGUAGE";
200
201        /**
202         * Used by the {@link Attendee} property. It defines the groups that the
203         * attendee is a member of in the form of URIs. Typically, these are email
204         * URIs (for example, "mailto:mailinglist@example.com").
205         * @see <a href="http://tools.ietf.org/html/rfc5545#page-21">RFC 5545
206         * p.21-2</a>
207         */
208        public static final String MEMBER = "MEMBER";
209
210        /**
211         * Used by the {@link Attendee} property. It defines the participation
212         * status of the attendee (for example, "ACCEPTED"). If none is defined,
213         * then the property should be treated as if this parameter was set to
214         * "NEEDS-ACTION".
215         * @see <a href="http://tools.ietf.org/html/rfc5545#page-22">RFC 5545
216         * p.22</a>
217         */
218        public static final String PARTSTAT = "PARTSTAT";
219
220        /**
221         * Used by the {@link RecurrenceId} property. It defines the effective range
222         * of recurrence instances that the property references.
223         * @see <a href="http://tools.ietf.org/html/rfc5545#page-23">RFC 5545
224         * p.23-4</a>
225         */
226        public static final String RANGE = "RANGE";
227
228        /**
229         * Used by the {@link Trigger} property. It defines the date-time field that
230         * the property's duration (if specified) is relative to (for example, the
231         * start date or the end date).
232         * @see <a href="http://tools.ietf.org/html/rfc5545#page-24">RFC 5545
233         * p.24</a>
234         */
235        public static final String RELATED = "RELATED";
236
237        /**
238         * Used by the {@link RelatedTo} property. It defines the kind of
239         * relationship the property is describing (for example, a "child"
240         * relationship).
241         * @see <a href="http://tools.ietf.org/html/rfc5545#page-25">RFC 5545
242         * p.25</a>
243         */
244        public static final String RELTYPE = "RELTYPE";
245
246        /**
247         * Used by the {@link Attendee} property. It defines the attendee's role
248         * and/or whether they must attend or not (for example, "OPT-PARTICIPANT"
249         * for "optional participant"). If none is defined, then the property should
250         * be treated as if this parameter was set to "REQ-PARTICIPANT" (required
251         * participant).
252         * @see <a href="http://tools.ietf.org/html/rfc5545#page-25">RFC 5545
253         * p.25</a>
254         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.25</a>
255         */
256        public static final String ROLE = "ROLE";
257
258        /**
259         * Used by the {@link Attendee} property. It defines whether the event
260         * organizer would like the attendee to reply with his or her intention of
261         * attending ("true" if the organizer would like a reply, "false" if not).
262         * If this parameter is not defined, then the property should be treated as
263         * if this parameter was set to "false".
264         * @see <a href="http://tools.ietf.org/html/rfc5545#page-26">RFC 5545
265         * p.26</a>
266         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.25</a>
267         */
268        public static final String RSVP = "RSVP";
269
270        /**
271         * Defines a URI which represents a person who is acting on behalf of the
272         * person that is defined in the property. Typically, the URI is an email
273         * URI (for example, "mailto:janedoe@example.com"). It is used by the
274         * {@link Attendee} and {@link Organizer} properties.
275         * @see <a href="http://tools.ietf.org/html/rfc5545#page-27">RFC 5545
276         * p.27</a>
277         */
278        public static final String SENT_BY = "SENT-BY";
279
280        /**
281         * Used by the {@link Attendee} property. It defines the status of the
282         * person's event invitation (for example, "TENTATIVE" if the person may or
283         * may not attend). It is only used in the vCal 1.0 standard.
284         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.25</a>
285         */
286        public static final String STATUS = "STATUS";
287
288        /**
289         * Defines the content type of the property value (for example, "WAVE" for
290         * an audio file). It is only used in the vCal 1.0 standard.
291         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.27</a>
292         */
293        public static final String TYPE = "TYPE";
294
295        /**
296         * Used by properties that contain date-time values. It defines the timezone
297         * that the property value is formatted in. It either references a timezone
298         * defined in a VTIMEZONE component, or contains an Olson timezone ID. To
299         * use an Olson timezone ID, the parameter value must be prepended with a
300         * "/" (for example, "/America/New_York").
301         * @see <a href="http://tools.ietf.org/html/rfc5545#page-27">RFC 5545
302         * p.27-8</a>
303         */
304        public static final String TZID = "TZID";
305
306        /**
307         * Defines the data type of the property value (for example, "date" if the
308         * property value is a date without a time component). It is used if the
309         * property accepts multiple values that have different data types.
310         * @see <a href="http://tools.ietf.org/html/rfc5545#page-29">RFC 5545
311         * p.29-50</a>
312         */
313        public static final String VALUE = "VALUE";
314
315        /**
316         * Creates a parameters list.
317         */
318        public ICalParameters() {
319                /*
320                 * Initialize map size to 0 because most properties don't use any
321                 * parameters.
322                 */
323                super(0);
324        }
325
326        /**
327         * Copies an existing parameters list.
328         * @param parameters the list to copy
329         */
330        public ICalParameters(ICalParameters parameters) {
331                super(parameters);
332        }
333
334        /**
335         * <p>
336         * Creates a parameter list that is backed by the given map. Any changes
337         * made to the given map will effect the parameter list and vice versa.
338         * </p>
339         * <p>
340         * Care must be taken to ensure that the given map's keys are all in
341         * uppercase.
342         * </p>
343         * <p>
344         * To avoid problems, it is highly recommended that the given map NOT be
345         * modified by anything other than this {@link ICalParameters} class after
346         * being passed into this constructor.
347         * </p>
348         * @param map the map
349         */
350        public ICalParameters(Map<String, List<String>> map) {
351                super(map);
352        }
353
354        /**
355         * <p>
356         * Gets the ALTREP (alternate representation) parameter value.
357         * </p>
358         * <p>
359         * This parameter contains a URI that points to additional information about
360         * the entity represented by the property.
361         * </p>
362         * @return the URI or null if not set
363         * @see <a href="http://tools.ietf.org/html/rfc5545#page-14">RFC 5545
364         * p.14-5</a>
365         */
366        public String getAltRepresentation() {
367                return first(ALTREP);
368        }
369
370        /**
371         * <p>
372         * Sets the ALTREP (alternate representation) parameter value.
373         * </p>
374         * <p>
375         * This parameter contains a URI that points to additional information about
376         * the entity represented by the property.
377         * </p>
378         * @param uri the URI or null to remove
379         * @see <a href="http://tools.ietf.org/html/rfc5545#page-14">RFC 5545
380         * p.14-5</a>
381         */
382        public void setAltRepresentation(String uri) {
383                replace(ALTREP, uri);
384        }
385
386        /**
387         * <p>
388         * Gets the CHARSET parameter value.
389         * </p>
390         * <p>
391         * This parameter contains the character set that the property value is
392         * encoded in (for example, "UTF-8"). It is only used in the vCal 1.0
393         * standard, and is typically used when a property value is encoded in
394         * quoted-printable encoding.
395         * </p>
396         * @return the character set or null if not set
397         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.16</a>
398         */
399        public String getCharset() {
400                return first(CHARSET);
401        }
402
403        /**
404         * <p>
405         * Sets the CHARSET parameter value.
406         * </p>
407         * <p>
408         * This parameter contains the character set that the property value is
409         * encoded in (for example, "UTF-8"). It is only used in the vCal 1.0
410         * standard, and is typically used when a property value is encoded in
411         * quoted-printable encoding.
412         * </p>
413         * @param charset the character set or null to remove
414         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.16</a>
415         */
416        public void setCharset(String charset) {
417                replace(CHARSET, charset);
418        }
419
420        /**
421         * <p>
422         * Gets the CN (common name) parameter value.
423         * </p>
424         * <p>
425         * This parameter contains a human-readable, display name of the entity
426         * represented by this property (for example, "John Doe"). It is used by the
427         * {@link Attendee} and {@link Organizer} properties.
428         * </p>
429         * @return the common name or null if not set
430         * @see <a href="http://tools.ietf.org/html/rfc5545#page-15">RFC 5545
431         * p.15-6</a>
432         */
433        public String getCommonName() {
434                return first(CN);
435        }
436
437        /**
438         * <p>
439         * Sets the CN (common name) parameter value.
440         * </p>
441         * <p>
442         * This parameter contains a human-readable, display name of the entity
443         * represented by this property (for example, "John Doe"). It is used by the
444         * {@link Attendee} and {@link Organizer} properties.
445         * </p>
446         * @param cn the common name or null to remove
447         * @see <a href="http://tools.ietf.org/html/rfc5545#page-15">RFC 5545
448         * p.15-6</a>
449         */
450        public void setCommonName(String cn) {
451                replace(CN, cn);
452        }
453
454        /**
455         * <p>
456         * Gets the CUTYPE (calendar user type) parameter value.
457         * </p>
458         * <p>
459         * This parameter is used by the {@link Attendee} property. It defines the
460         * type of object that the attendee is (for example, an "individual" or a
461         * "room").
462         * </p>
463         * @return the calendar user type or null if not set
464         * @see <a href="http://tools.ietf.org/html/rfc5545#page-16">RFC 5545
465         * p.16</a>
466         */
467        public CalendarUserType getCalendarUserType() {
468                String value = first(CUTYPE);
469                return (value == null) ? null : CalendarUserType.get(value);
470        }
471
472        /**
473         * <p>
474         * Sets the CUTYPE (calendar user type) parameter value.
475         * </p>
476         * <p>
477         * This parameter is used by the {@link Attendee} property. It defines the
478         * type of object that the attendee is (for example, an "individual" or a
479         * "room").
480         * </p>
481         * @param calendarUserType the calendar user type or null to remove
482         * @see <a href="http://tools.ietf.org/html/rfc5545#page-16">RFC 5545
483         * p.16</a>
484         */
485        public void setCalendarUserType(CalendarUserType calendarUserType) {
486                replace(CUTYPE, (calendarUserType == null) ? null : calendarUserType.getValue());
487        }
488
489        /**
490         * <p>
491         * Gets the DELEGATED-FROM parameter values.
492         * </p>
493         * <p>
494         * This parameter is used by the {@link Attendee} property. It stores a list
495         * of people who have delegated their responsibility to the attendee. The
496         * values must be URIs. They are typically email URIs (for example,
497         * "mailto:janedoe@example.com").
498         * </p>
499         * <p>
500         * Changes to the returned list will update the {@link ICalParameters}
501         * object, and vice versa.
502         * </p>
503         * @return the URIs or an empty list if none are set
504         * @see <a href="http://tools.ietf.org/html/rfc5545#page-17">RFC 5545
505         * p.17</a>
506         */
507        public List<String> getDelegatedFrom() {
508                return get(DELEGATED_FROM);
509        }
510
511        /**
512         * <p>
513         * Gets the DELEGATED-TO parameter values.
514         * </p>
515         * <p>
516         * This parameter is used by the {@link Attendee} property. It stores a list
517         * of people to which the attendee has delegated his or her responsibility.
518         * The values must be URIs. They are typically email URIs (for example,
519         * "mailto:janedoe@example.com").
520         * </p>
521         * <p>
522         * Changes to the returned list will update the {@link ICalParameters}
523         * object, and vice versa.
524         * </p>
525         * @return the URIs or an empty list if none are set
526         * @see <a href="http://tools.ietf.org/html/rfc5545#page-17">RFC 5545
527         * p.17-8</a>
528         */
529        public List<String> getDelegatedTo() {
530                return get(DELEGATED_TO);
531        }
532
533        /**
534         * <p>
535         * Gets the DIR (directory entry) parameter value.
536         * </p>
537         * <p>
538         * This parameter contains a URI (such as an LDAP URI) which points to
539         * additional information about the person that the property represents. It
540         * is used by the {@link Attendee} and {@link Organizer} properties.
541         * </p>
542         * @return the URI or null if not set
543         * @see <a href="http://tools.ietf.org/html/rfc5545#page-18">RFC 5545
544         * p.18</a>
545         */
546        public String getDirectoryEntry() {
547                return first(DIR);
548        }
549
550        /**
551         * <p>
552         * Sets the DIR (directory entry) parameter value.
553         * </p>
554         * <p>
555         * This parameter contains a URI (such as an LDAP URI) which points to
556         * additional information about the person that the property represents. It
557         * is used by the {@link Attendee} and {@link Organizer} properties.
558         * </p>
559         * @param uri the URI or null to remove
560         * @see <a href="http://tools.ietf.org/html/rfc5545#page-18">RFC 5545
561         * p.18</a>
562         */
563        public void setDirectoryEntry(String uri) {
564                replace(DIR, uri);
565        }
566
567        /**
568         * <p>
569         * Gets the DISPLAY parameter values.
570         * </p>
571         * <p>
572         * This parameter is used by the {@link Image} property. It defines the ways
573         * in which the client application should display the image (for example, as
574         * a thumbnail-sized image).
575         * </p>
576         * <p>
577         * Changes to the returned list will update the {@link ICalParameters}
578         * object, and vice versa.
579         * </p>
580         * @return the display suggestions or empty list if none are defined
581         * @see <a href=
582         * "https://tools.ietf.org/html/draft-ietf-calext-extensions-01#page-13" >
583         * draft-ietf-calext-extensions p.13</a>
584         */
585        public List<Display> getDisplays() {
586                return new EnumParameterList<Display>(DISPLAY) {
587                        @Override
588                        protected Display _asObject(String value) {
589                                return Display.get(value);
590                        }
591                };
592        }
593
594        /**
595         * <p>
596         * Gets the EMAIL parameter value.
597         * </p>
598         * <p>
599         * This parameter is used by the {@link Attendee} property. Normally, this
600         * property's value contains the email address of the attendee. But if the
601         * property value must hold something else, this parameter can be used to
602         * store the attendee's email address.
603         * </p>
604         * @return the email or null if not set
605         * @see <a href=
606         * "https://tools.ietf.org/html/draft-ietf-calext-extensions-01#page-14" >
607         * draft-ietf-calext-extensions p.14</a>
608         */
609        public String getEmail() {
610                return first(EMAIL);
611        }
612
613        /**
614         * <p>
615         * Sets the EMAIL parameter value.
616         * </p>
617         * <p>
618         * This parameter is used by the {@link Attendee} property. Normally, this
619         * property's value contains the email address of the attendee. But if the
620         * property value must hold something else, this parameter can be used to
621         * store the attendee's email address.
622         * </p>
623         * @param email the email or null to remove
624         * @see <a href=
625         * "https://tools.ietf.org/html/draft-ietf-calext-extensions-01#page-14" >
626         * draft-ietf-calext-extensions p.14</a>
627         */
628        public void setEmail(String email) {
629                replace(EMAIL, email);
630        }
631
632        /**
633         * <p>
634         * Gets the ENCODING parameter value.
635         * </p>
636         * <p>
637         * This parameter defines how the property value is encoded (for example,
638         * "base64" for a binary value).
639         * </p>
640         * @return the encoding or null if not set
641         * @see <a href="http://tools.ietf.org/html/rfc5545#page-18">RFC 5545
642         * p.18-9</a>
643         */
644        public Encoding getEncoding() {
645                String value = first(ENCODING);
646                return (value == null) ? null : Encoding.get(value);
647        }
648
649        /**
650         * <p>
651         * Sets the ENCODING parameter value.
652         * </p>
653         * <p>
654         * This parameter defines how the property value is encoded (for example,
655         * "base64" for a binary value).
656         * </p>
657         * @param encoding the encoding or null to remove
658         * @see <a href="http://tools.ietf.org/html/rfc5545#page-18">RFC 5545
659         * p.18-9</a>
660         */
661        public void setEncoding(Encoding encoding) {
662                replace(ENCODING, (encoding == null) ? null : encoding.getValue());
663        }
664
665        /**
666         * <p>
667         * Gets the EXPECT parameter value.
668         * </p>
669         * <p>
670         * This parameter is used by the {@link Attendee} property. It defines
671         * whether the event organizer expects the attendee to attend or not. It is
672         * only used in the vCal 1.0 standard.
673         * </p>
674         * @return the attendance expectation or null if not set
675         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.25</a>
676         */
677        public String getExpect() {
678                return first(EXPECT);
679        }
680
681        /**
682         * <p>
683         * Sets the EXPECT parameter value.
684         * </p>
685         * <p>
686         * This parameter is used by the {@link Attendee} property. It defines
687         * whether the event organizer expects the attendee to attend or not. It is
688         * only used in the vCal 1.0 standard.
689         * </p>
690         * @param expect the attendance expectation or null if not set
691         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.25</a>
692         */
693        public void setExpect(String expect) {
694                replace(EXPECT, expect);
695        }
696
697        /**
698         * <p>
699         * Gets the FEATURE parameter values.
700         * </p>
701         * <p>
702         * This parameter is used by the {@link Conference} property. It defines the
703         * features that the conference supports (for example, audio and video).
704         * </p>
705         * <p>
706         * Changes to the returned list will update the {@link ICalParameters}
707         * object, and vice versa.
708         * </p>
709         * @return the features or empty list if none are set
710         * @see <a href=
711         * "https://tools.ietf.org/html/draft-ietf-calext-extensions-01#page-15" >
712         * draft-ietf-calext-extensions p.15</a>
713         */
714        public List<Feature> getFeatures() {
715                return new EnumParameterList<Feature>(FEATURE) {
716                        @Override
717                        protected Feature _asObject(String value) {
718                                return Feature.get(value);
719                        }
720                };
721        }
722
723        /**
724         * <p>
725         * Gets the FMTTYPE (format type) parameter value.
726         * </p>
727         * <p>
728         * This parameter defines the content type of the property value (for
729         * example, "image/jpg" if the property value is a JPEG image).
730         * </p>
731         * @return the format type or null if not set
732         * @see <a href="http://tools.ietf.org/html/rfc5545#page-19">RFC 5545
733         * p.19-20</a>
734         */
735        public String getFormatType() {
736                return first(FMTTYPE);
737        }
738
739        /**
740         * <p>
741         * Sets the FMTTYPE (format type) parameter value.
742         * </p>
743         * <p>
744         * This parameter defines the content type of the property value (for
745         * example, "image/jpg" if the property value is a JPEG image).
746         * </p>
747         * @param formatType the format type or null to remove
748         * @see <a href="http://tools.ietf.org/html/rfc5545#page-19">RFC 5545
749         * p.19-20</a>
750         */
751        public void setFormatType(String formatType) {
752                replace(FMTTYPE, formatType);
753        }
754
755        /**
756         * <p>
757         * Gets the FBTYPE (free busy type) parameter value.
758         * </p>
759         * <p>
760         * This parameter is used by the {@link FreeBusy} property. It defines
761         * whether the person is "free" or "busy" over the time periods that are
762         * specified in the property value. If this parameter is not set, the user
763         * should be considered "busy" during these times.
764         * </p>
765         * @return the free busy type or null if not set
766         * @see <a href="http://tools.ietf.org/html/rfc5545#page-20">RFC 5545
767         * p.20</a>
768         */
769        public FreeBusyType getFreeBusyType() {
770                String value = first(FBTYPE);
771                return (value == null) ? null : FreeBusyType.get(value);
772        }
773
774        /**
775         * <p>
776         * Sets the FBTYPE (free busy type) parameter value.
777         * </p>
778         * <p>
779         * This parameter is used by the {@link FreeBusy} property. It defines
780         * whether the person is "free" or "busy" over the time periods that are
781         * specified in the property value. If this parameter is not set, the user
782         * should be considered "busy" during these times.
783         * </p>
784         * @param freeBusyType the free busy type or null to remove
785         * @see <a href="http://tools.ietf.org/html/rfc5545#page-20">RFC 5545
786         * p.20</a>
787         */
788        public void setFreeBusyType(FreeBusyType freeBusyType) {
789                replace(FBTYPE, (freeBusyType == null) ? null : freeBusyType.getValue());
790        }
791
792        /**
793         * <p>
794         * Gets the LABEL parameter value.
795         * </p>
796         * <p>
797         * This parameter defines a human-readable label for the property.
798         * </p>
799         * @return the label or null if not set
800         * @see <a href=
801         * "http://tools.ietf.org/html/draft-ietf-calext-extensions-01#page-16">
802         * draft-ietf-calext-extensions-01 p.16</a>
803         */
804        public String getLabel() {
805                return first(LABEL);
806        }
807
808        /**
809         * <p>
810         * Sets the LABEL parameter value.
811         * </p>
812         * <p>
813         * This parameter defines a human-readable label for the property.
814         * </p>
815         * @param label the label or null to remove
816         * @see <a href=
817         * "http://tools.ietf.org/html/draft-ietf-calext-extensions-01#page-16">
818         * draft-ietf-calext-extensions-01 p.16</a>
819         */
820        public void setLabel(String label) {
821                replace(LABEL, label);
822        }
823
824        /**
825         * <p>
826         * Gets the LANGUAGE parameter value.
827         * </p>
828         * <p>
829         * This parameter defines the language that the property value is written in
830         * (for example, "en" for English).
831         * </p>
832         * @return the language or null if not set
833         * @see <a href="http://tools.ietf.org/html/rfc5545#page-21">RFC 5545
834         * p.21</a>
835         */
836        public String getLanguage() {
837                return first(LANGUAGE);
838        }
839
840        /**
841         * <p>
842         * Sets the LANGUAGE parameter value.
843         * </p>
844         * <p>
845         * This parameter defines the language that the property value is written in
846         * (for example, "en" for English).
847         * </p>
848         * @param language the language or null to remove
849         * @see <a href="http://tools.ietf.org/html/rfc5545#page-21">RFC 5545
850         * p.21</a>
851         */
852        public void setLanguage(String language) {
853                replace(LANGUAGE, language);
854        }
855
856        /**
857         * <p>
858         * Gets the MEMBER property values.
859         * </p>
860         * <p>
861         * This parameter is used by the {@link Attendee} property. It defines the
862         * groups that the attendee is a member of in the form of URIs. Typically,
863         * these are email URIs (for example, "mailto:mailinglist@example.com").
864         * </p>
865         * <p>
866         * Changes to the returned list will update the {@link ICalParameters}
867         * object, and vice versa.
868         * </p>
869         * @return the groups or empty list if none are set
870         * @see <a href="http://tools.ietf.org/html/rfc5545#page-21">RFC 5545
871         * p.21-2</a>
872         */
873        public List<String> getMembers() {
874                return get(MEMBER);
875        }
876
877        /**
878         * <p>
879         * Gets the PARTSTAT (participation status) parameter value.
880         * </p>
881         * <p>
882         * This parameter is used by the {@link Attendee} property. It defines the
883         * participation status of the attendee (for example, "ACCEPTED"). If none
884         * is defined, then the property should be treated as if this parameter was
885         * set to "NEEDS-ACTION".
886         * </p>
887         * @return the participation status or null if not set
888         * @see <a href="http://tools.ietf.org/html/rfc5545#page-22">RFC 5545
889         * p.22</a>
890         */
891        public String getParticipationStatus() {
892                return first(PARTSTAT);
893        }
894
895        /**
896         * <p>
897         * Gets the PARTSTAT (participation status) parameter value.
898         * </p>
899         * <p>
900         * This parameter is used by the {@link Attendee} property. It defines the
901         * participation status of the attendee (for example, "ACCEPTED"). If none
902         * is defined, then the property should be treated as if this parameter was
903         * set to "NEEDS-ACTION".
904         * </p>
905         * @param participationStatus the participation status or null to remove
906         * @see <a href="http://tools.ietf.org/html/rfc5545#page-22">RFC 5545
907         * p.22</a>
908         */
909        public void setParticipationStatus(String participationStatus) {
910                replace(PARTSTAT, participationStatus);
911        }
912
913        /**
914         * <p>
915         * Gets the RANGE parameter value.
916         * </p>
917         * <p>
918         * This parameter is used by the {@link RecurrenceId} property. It defines
919         * the effective range of recurrence instances that the property references.
920         * </p>
921         * @return the range or null if not set
922         * @see <a href="http://tools.ietf.org/html/rfc5545#page-23">RFC 5545
923         * p.23-4</a>
924         */
925        public Range getRange() {
926                String value = first(RANGE);
927                return (value == null) ? null : Range.get(value);
928        }
929
930        /**
931         * <p>
932         * Sets the RANGE parameter value.
933         * </p>
934         * <p>
935         * This parameter is used by the {@link RecurrenceId} property. It defines
936         * the effective range of recurrence instances that the property references.
937         * </p>
938         * @param range the range or null to remove
939         * @see <a href="http://tools.ietf.org/html/rfc5545#page-23">RFC 5545
940         * p.23-4</a>
941         */
942        public void setRange(Range range) {
943                replace(RANGE, (range == null) ? null : range.getValue());
944        }
945
946        /**
947         * <p>
948         * Gets the RELATED parameter value.
949         * </p>
950         * <p>
951         * This parameter is used by the {@link Trigger} property. It defines the
952         * date-time field that the property's duration (if specified) is relative
953         * to (for example, the start date or the end date).
954         * </p>
955         * @return the related field or null if not set
956         * @see <a href="http://tools.ietf.org/html/rfc5545#page-24">RFC 5545
957         * p.24</a>
958         */
959        public Related getRelated() {
960                String value = first(RELATED);
961                return (value == null) ? null : Related.get(value);
962        }
963
964        /**
965         * <p>
966         * Sets the RELATED parameter value.
967         * </p>
968         * <p>
969         * This parameter is used by the {@link Trigger} property. It defines the
970         * date-time field that the property's duration (if specified) is relative
971         * to (for example, the start date or the end date).
972         * </p>
973         * @param related the related field or null to remove
974         * @see <a href="http://tools.ietf.org/html/rfc5545#page-24">RFC 5545
975         * p.24</a>
976         */
977        public void setRelated(Related related) {
978                replace(RELATED, (related == null) ? null : related.getValue());
979        }
980
981        /**
982         * <p>
983         * Gets the RELTYPE (relationship type) parameter value.
984         * </p>
985         * <p>
986         * This parameter is used by the {@link RelatedTo} property. It defines the
987         * kind of relationship the property is describing (for example, a "child"
988         * relationship).
989         * </p>
990         * @return the relationship type or null if not set
991         * @see <a href="http://tools.ietf.org/html/rfc5545#page-25">RFC 5545
992         * p.25</a>
993         */
994        public RelationshipType getRelationshipType() {
995                String value = first(RELTYPE);
996                return (value == null) ? null : RelationshipType.get(value);
997        }
998
999        /**
1000         * <p>
1001         * Sets the RELTYPE (relationship type) parameter value.
1002         * </p>
1003         * <p>
1004         * This parameter is used by the {@link RelatedTo} property. It defines the
1005         * kind of relationship the property is describing (for example, a "child"
1006         * relationship).
1007         * </p>
1008         * @param relationshipType the relationship type or null to remove
1009         * @see <a href="http://tools.ietf.org/html/rfc5545#page-25">RFC 5545
1010         * p.25</a>
1011         */
1012        public void setRelationshipType(RelationshipType relationshipType) {
1013                replace(RELTYPE, (relationshipType == null) ? null : relationshipType.getValue());
1014        }
1015
1016        /**
1017         * <p>
1018         * Gets the ROLE parameter value.
1019         * </p>
1020         * <p>
1021         * This parameter is used by the {@link Attendee} property. It defines the
1022         * attendee's role and/or whether they must attend or not (for example,
1023         * "OPT-PARTICIPANT" for "optional participant"). If none is defined, then
1024         * the property should be treated as if this parameter was set to
1025         * "REQ-PARTICIPANT" (required participant).
1026         * </p>
1027         * @return the role or null if not set
1028         * @see <a href="http://tools.ietf.org/html/rfc5545#page-25">RFC 5545
1029         * p.25</a>
1030         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.25</a>
1031         */
1032        public String getRole() {
1033                /*
1034                 * Note: The acceptable values for this parameter differs in vCal 1.0,
1035                 * which is why this method does not return an enum.
1036                 */
1037                return first(ROLE);
1038        }
1039
1040        /**
1041         * <p>
1042         * Sets the ROLE parameter value.
1043         * </p>
1044         * <p>
1045         * This parameter is used by the {@link Attendee} property. It defines the
1046         * attendee's role and/or whether they must attend or not (for example,
1047         * "OPT-PARTICIPANT" for "optional participant"). If none is defined, then
1048         * the property should be treated as if this parameter was set to
1049         * "REQ-PARTICIPANT" (required participant).
1050         * </p>
1051         * @param role the role or null to remove
1052         * @see <a href="http://tools.ietf.org/html/rfc5545#page-25">RFC 5545
1053         * p.25</a>
1054         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.25</a>
1055         */
1056        public void setRole(String role) {
1057                replace(ROLE, role);
1058        }
1059
1060        /**
1061         * <p>
1062         * Gets the RSVP parameter value.
1063         * </p>
1064         * <p>
1065         * This parameter is used by the {@link Attendee} property. It defines
1066         * whether the event organizer would like the attendee to reply with his or
1067         * her intention of attending ("true" if the organizer would like a reply,
1068         * "false" if not). If this parameter is not defined, then the property
1069         * should be treated as if this parameter was set to "false".
1070         * </p>
1071         * @return the value or null if not set
1072         * @see <a href="http://tools.ietf.org/html/rfc5545#page-26">RFC 5545
1073         * p.26</a>
1074         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.25</a>
1075         */
1076        public String getRsvp() {
1077                /*
1078                 * Note: The acceptable values for this parameter differs in vCal 1.0,
1079                 * which is why this method does not return a boolean.
1080                 */
1081                return first(RSVP);
1082        }
1083
1084        /**
1085         * <p>
1086         * Sets the RSVP parameter value.
1087         * </p>
1088         * <p>
1089         * This parameter is used by the {@link Attendee} property. It defines
1090         * whether the event organizer would like the attendee to reply with his or
1091         * her intention of attending ("true" if the organizer would like a reply,
1092         * "false" if not). If this parameter is not defined, then the property
1093         * should be treated as if this parameter was set to "false".
1094         * </p>
1095         * @param rsvp the value or null to remove
1096         * @see <a href="http://tools.ietf.org/html/rfc5545#page-26">RFC 5545
1097         * p.26</a>
1098         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.25</a>
1099         */
1100        public void setRsvp(String rsvp) {
1101                replace(RSVP, rsvp);
1102        }
1103
1104        /**
1105         * <p>
1106         * Gets the SENT-BY parameter value.
1107         * </p>
1108         * <p>
1109         * This parameter defines a URI which represents a person who is acting on
1110         * behalf of the person that is defined in the property. Typically, the URI
1111         * is an email URI (for example, "mailto:janedoe@example.com"). It is used
1112         * by the {@link Attendee} and {@link Organizer} properties.
1113         * </p>
1114         * @return the URI or null if not set
1115         * @see <a href="http://tools.ietf.org/html/rfc5545#page-27">RFC 5545
1116         * p.27</a>
1117         */
1118        public String getSentBy() {
1119                return first(SENT_BY);
1120        }
1121
1122        /**
1123         * <p>
1124         * Sets the SENT-BY parameter value.
1125         * </p>
1126         * <p>
1127         * This parameter defines a URI which represents a person who is acting on
1128         * behalf of the person that is defined in the property. Typically, the URI
1129         * is an email URI (for example, "mailto:janedoe@example.com"). It is used
1130         * by the {@link Attendee} and {@link Organizer} properties.
1131         * </p>
1132         * @param uri the URI or null to remove
1133         * @see <a href="http://tools.ietf.org/html/rfc5545#page-27">RFC 5545
1134         * p.27</a>
1135         */
1136        public void setSentBy(String uri) {
1137                replace(SENT_BY, uri);
1138        }
1139
1140        /**
1141         * <p>
1142         * Gets the STATUS parameter value.
1143         * </p>
1144         * <p>
1145         * This parameter is used by the {@link Attendee} property. It defines the
1146         * status of the person's event invitation (for example, "TENTATIVE" if the
1147         * person may or may not attend). It is only used in the vCal 1.0 standard.
1148         * </p>
1149         * @return the status or null if not set
1150         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.25</a>
1151         */
1152        public String getStatus() {
1153                return first(STATUS);
1154        }
1155
1156        /**
1157         * <p>
1158         * Sets the STATUS parameter value.
1159         * </p>
1160         * <p>
1161         * This parameter is used by the {@link Attendee} property. It defines the
1162         * status of the person's event invitation (for example, "TENTATIVE" if the
1163         * person may or may not attend). It is only used in the vCal 1.0 standard.
1164         * </p>
1165         * @param status the status or null to remove
1166         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.25</a>
1167         */
1168        public void setStatus(String status) {
1169                replace(STATUS, status);
1170        }
1171
1172        /**
1173         * <p>
1174         * Gets the TZID (timezone ID) parameter value.
1175         * </p>
1176         * <p>
1177         * This parameter is used by properties that contain date-time values. It
1178         * defines the timezone that the property value is formatted in. It either
1179         * references a timezone defined in a VTIMEZONE component, or contains an
1180         * Olson timezone ID. To use an Olson timezone ID, the parameter value must
1181         * be prepended with a "/" (for example, "/America/New_York").
1182         * </p>
1183         * @return the timezone ID or null if not set
1184         * @see <a href="http://tools.ietf.org/html/rfc5545#page-27">RFC 5545
1185         * p.27-8</a>
1186         */
1187        public String getTimezoneId() {
1188                return first(TZID);
1189        }
1190
1191        /**
1192         * <p>
1193         * Sets the TZID (timezone ID) parameter value.
1194         * </p>
1195         * <p>
1196         * This parameter is used by properties that contain date-time values. It
1197         * defines the timezone that the property value is formatted in. It either
1198         * references a timezone defined in a VTIMEZONE component, or contains an
1199         * Olson timezone ID. To use an Olson timezone ID, the parameter value must
1200         * be prepended with a "/" (for example, "/America/New_York").
1201         * </p>
1202         * @param timezoneId the timezone ID or null to remove
1203         * @see <a href="http://tools.ietf.org/html/rfc5545#page-27">RFC 5545
1204         * p.27-8</a>
1205         */
1206        public void setTimezoneId(String timezoneId) {
1207                replace(TZID, timezoneId);
1208        }
1209
1210        /**
1211         * <p>
1212         * Gets the TYPE parameter value.
1213         * </p>
1214         * <p>
1215         * This parameter defines the content type of the property value (for
1216         * example, "WAVE" for an audio file). It is only used in the vCal 1.0
1217         * standard.
1218         * </p>
1219         * @return the type or null if not set
1220         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.27</a>
1221         */
1222        public String getType() {
1223                return first(TYPE);
1224        }
1225
1226        /**
1227         * <p>
1228         * Sets the TYPE parameter value.
1229         * </p>
1230         * <p>
1231         * This parameter defines the content type of the property value (for
1232         * example, "WAVE" for an audio file). It is only used in the vCal 1.0
1233         * standard.
1234         * </p>
1235         * @param type the type or null to remove
1236         * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.27</a>
1237         */
1238        public void setType(String type) {
1239                replace(TYPE, type);
1240        }
1241
1242        /**
1243         * <p>
1244         * Gets the VALUE parameter value.
1245         * </p>
1246         * <p>
1247         * This parameter defines the data type of the property value (for example,
1248         * "date" if the property value is a date without a time component). It is
1249         * used if the property accepts multiple values that have different data
1250         * types.
1251         * </p>
1252         * @return the data type or null if not set
1253         * @see <a href="http://tools.ietf.org/html/rfc5545#page-29">RFC 5545
1254         * p.29-50</a>
1255         */
1256        public ICalDataType getValue() {
1257                String value = first(VALUE);
1258                return (value == null) ? null : ICalDataType.get(value);
1259        }
1260
1261        /**
1262         * <p>
1263         * Sets the VALUE parameter value.
1264         * </p>
1265         * <p>
1266         * This parameter defines the data type of the property value (for example,
1267         * "date" if the property value is a date without a time component). It is
1268         * used if the property accepts multiple values that have different data
1269         * types.
1270         * </p>
1271         * @param dataType the data type or null to remove
1272         * @see <a href="http://tools.ietf.org/html/rfc5545#page-29">RFC 5545
1273         * p.29-50</a>
1274         */
1275        public void setValue(ICalDataType dataType) {
1276                replace(VALUE, (dataType == null) ? null : dataType.getName());
1277        }
1278
1279        /**
1280         * <p>
1281         * Checks the parameters for data consistency problems or deviations from
1282         * the specification.
1283         * </p>
1284         * <p>
1285         * These problems will not prevent the iCalendar object from being written
1286         * to a data stream*, but may prevent it from being parsed correctly by the
1287         * consuming application.
1288         * </p>
1289         * <p>
1290         * *With a few exceptions: One thing this method does is check for illegal
1291         * characters. There are certain characters that will break the iCalendar
1292         * syntax if written (such as a newline character in a parameter name). If
1293         * one of these characters is present, it WILL prevent the iCalendar object
1294         * from being written.
1295         * </p>
1296         * @param version the version to validate against
1297         * @return a list of warnings or an empty list if no problems were found
1298         */
1299        public List<ValidationWarning> validate(ICalVersion version) {
1300                List<ValidationWarning> warnings = new ArrayList<ValidationWarning>(0);
1301
1302                SyntaxStyle syntax;
1303                switch (version) {
1304                case V1_0:
1305                        syntax = SyntaxStyle.OLD;
1306                        break;
1307                default:
1308                        syntax = SyntaxStyle.NEW;
1309                        break;
1310                }
1311
1312                /*
1313                 * Check for invalid characters in names and values.
1314                 */
1315                for (Map.Entry<String, List<String>> entry : this) {
1316                        String name = entry.getKey();
1317
1318                        //check the parameter name
1319                        if (!VObjectValidator.validateParameterName(name, syntax, true)) {
1320                                if (syntax == SyntaxStyle.OLD) {
1321                                        AllowedCharacters notAllowed = VObjectValidator.allowedCharactersParameterName(syntax, true).flip();
1322                                        warnings.add(new ValidationWarning(57, name, notAllowed.toString(true)));
1323                                } else {
1324                                        warnings.add(new ValidationWarning(54, name));
1325                                }
1326                        }
1327
1328                        //check the parameter value(s)
1329                        List<String> values = entry.getValue();
1330                        for (String value : values) {
1331                                if (!VObjectValidator.validateParameterValue(value, syntax, false, true)) {
1332                                        AllowedCharacters notAllowed = VObjectValidator.allowedCharactersParameterValue(syntax, false, true).flip();
1333                                        int code = (syntax == SyntaxStyle.OLD) ? 58 : 53;
1334                                        warnings.add(new ValidationWarning(code, name, value, notAllowed.toString(true)));
1335                                }
1336                        }
1337                }
1338
1339                final int nonStandardCode = 1, deprecated = 47;
1340
1341                String value = first(RSVP);
1342                if (value != null) {
1343                        value = value.toLowerCase();
1344                        List<String> validValues = Arrays.asList("true", "false", "yes", "no");
1345                        if (!validValues.contains(value)) {
1346                                warnings.add(new ValidationWarning(nonStandardCode, RSVP, value, validValues));
1347                        }
1348                }
1349
1350                value = first(CUTYPE);
1351                if (value != null && CalendarUserType.find(value) == null) {
1352                        warnings.add(new ValidationWarning(nonStandardCode, CUTYPE, value, CalendarUserType.all()));
1353                }
1354
1355                value = first(ENCODING);
1356                if (value != null && Encoding.find(value) == null) {
1357                        warnings.add(new ValidationWarning(nonStandardCode, ENCODING, value, Encoding.all()));
1358                }
1359
1360                value = first(FBTYPE);
1361                if (value != null && FreeBusyType.find(value) == null) {
1362                        warnings.add(new ValidationWarning(nonStandardCode, FBTYPE, value, FreeBusyType.all()));
1363                }
1364
1365                value = first(PARTSTAT);
1366                if (value != null && ParticipationStatus.find(value) == null) {
1367                        warnings.add(new ValidationWarning(nonStandardCode, PARTSTAT, value, ParticipationStatus.all()));
1368                }
1369
1370                value = first(RANGE);
1371                if (value != null) {
1372                        Range range = Range.find(value);
1373
1374                        if (range == null) {
1375                                warnings.add(new ValidationWarning(nonStandardCode, RANGE, value, Range.all()));
1376                        }
1377
1378                        if (range == Range.THIS_AND_PRIOR && version == ICalVersion.V2_0) {
1379                                warnings.add(new ValidationWarning(deprecated, RANGE, value));
1380                        }
1381                }
1382
1383                value = first(RELATED);
1384                if (value != null && Related.find(value) == null) {
1385                        warnings.add(new ValidationWarning(nonStandardCode, RELATED, value, Related.all()));
1386                }
1387
1388                value = first(RELTYPE);
1389                if (value != null && RelationshipType.find(value) == null) {
1390                        warnings.add(new ValidationWarning(nonStandardCode, RELTYPE, value, RelationshipType.all()));
1391                }
1392
1393                value = first(ROLE);
1394                if (value != null && Role.find(value) == null) {
1395                        warnings.add(new ValidationWarning(nonStandardCode, ROLE, value, Role.all()));
1396                }
1397
1398                value = first(VALUE);
1399                if (value != null && ICalDataType.find(value) == null) {
1400                        warnings.add(new ValidationWarning(nonStandardCode, VALUE, value, ICalDataType.all()));
1401                }
1402
1403                return warnings;
1404        }
1405
1406        @Override
1407        protected String sanitizeKey(String key) {
1408                return (key == null) ? null : key.toUpperCase();
1409        }
1410
1411        @Override
1412        public int hashCode() {
1413                /*
1414                 * Remember: Keys are case-insensitive, key order does not matter, and
1415                 * value order does not matter
1416                 */
1417                final int prime = 31;
1418                int result = 1;
1419
1420                for (Map.Entry<String, List<String>> entry : this) {
1421                        String key = entry.getKey();
1422                        List<String> value = entry.getValue();
1423
1424                        int valueHash = 1;
1425                        for (String v : value) {
1426                                valueHash += v.toLowerCase().hashCode();
1427                        }
1428
1429                        int entryHash = 1;
1430                        entryHash += prime * entryHash + ((key == null) ? 0 : key.toLowerCase().hashCode());
1431                        entryHash += prime * entryHash + valueHash;
1432
1433                        result += entryHash;
1434                }
1435
1436                return result;
1437        }
1438
1439        /**
1440         * <p>
1441         * Determines whether the given object is logically equivalent to this list
1442         * of parameters.
1443         * </p>
1444         * <p>
1445         * Note that iCalendar parameter names are case-insensitive. Also, note that
1446         * the order in which they are defined does not matter.
1447         * </p>
1448         * @param obj the object to compare to
1449         * @return true if the objects are equal, false if not
1450         */
1451        @Override
1452        public boolean equals(Object obj) {
1453                /*
1454                 * Remember: Keys are case-insensitive, key order does not matter, and
1455                 * value order does not matter
1456                 */
1457                if (this == obj) return true;
1458                if (obj == null) return false;
1459                if (getClass() != obj.getClass()) return false;
1460
1461                ICalParameters other = (ICalParameters) obj;
1462                if (size() != other.size()) return false;
1463
1464                for (Map.Entry<String, List<String>> entry : this) {
1465                        String key = entry.getKey();
1466                        List<String> value = entry.getValue();
1467                        List<String> otherValue = other.get(key);
1468
1469                        if (value.size() != otherValue.size()) {
1470                                return false;
1471                        }
1472
1473                        List<String> valueLower = new ArrayList<String>(value.size());
1474                        for (String v : value) {
1475                                valueLower.add(v.toLowerCase());
1476                        }
1477                        Collections.sort(valueLower);
1478
1479                        List<String> otherValueLower = new ArrayList<String>(otherValue.size());
1480                        for (String v : otherValue) {
1481                                otherValueLower.add(v.toLowerCase());
1482                        }
1483                        Collections.sort(otherValueLower);
1484
1485                        if (!valueLower.equals(otherValueLower)) {
1486                                return false;
1487                        }
1488                }
1489
1490                return true;
1491        }
1492
1493        /**
1494         * <p>
1495         * A list that converts the raw string values of a parameter to the
1496         * appropriate {@link EnumParameterValue} object that some parameters use.
1497         * </p>
1498         * <p>
1499         * This list is backed by the {@link ICalParameters} object. Any changes
1500         * made to the list will affect the {@link ICalParameters} object and vice
1501         * versa.
1502         * </p>
1503         * @param <T> the enum parameter class
1504         */
1505        public abstract class EnumParameterList<T extends EnumParameterValue> extends ICalParameterList<T> {
1506                public EnumParameterList(String parameterName) {
1507                        super(parameterName);
1508                }
1509
1510                @Override
1511                protected String _asString(T value) {
1512                        return value.getValue();
1513                }
1514        }
1515
1516        /**
1517         * <p>
1518         * A list that converts the raw string values of a parameter to another kind
1519         * of value (for example, Integers).
1520         * </p>
1521         * <p>
1522         * This list is backed by the {@link ICalParameters} object. Any changes
1523         * made to the list will affect the {@link ICalParameters} object and vice
1524         * versa.
1525         * </p>
1526         * <p>
1527         * If a String value cannot be converted to the appropriate data type, an
1528         * {@link IllegalStateException} is thrown.
1529         * </p>
1530         */
1531        public abstract class ICalParameterList<T> extends AbstractList<T> {
1532                protected final String parameterName;
1533                protected final List<String> parameterValues;
1534
1535                /**
1536                 * @param parameterName the name of the parameter (case insensitive)
1537                 */
1538                public ICalParameterList(String parameterName) {
1539                        this.parameterName = parameterName;
1540                        parameterValues = ICalParameters.this.get(parameterName);
1541                }
1542
1543                @Override
1544                public void add(int index, T value) {
1545                        String valueStr = _asString(value);
1546                        parameterValues.add(index, valueStr);
1547                }
1548
1549                @Override
1550                public T remove(int index) {
1551                        String removed = parameterValues.remove(index);
1552                        return asObject(removed);
1553                }
1554
1555                @Override
1556                public T get(int index) {
1557                        String value = parameterValues.get(index);
1558                        return asObject(value);
1559                }
1560
1561                @Override
1562                public T set(int index, T value) {
1563                        String valueStr = _asString(value);
1564                        String replaced = parameterValues.set(index, valueStr);
1565                        return asObject(replaced);
1566                }
1567
1568                @Override
1569                public int size() {
1570                        return parameterValues.size();
1571                }
1572
1573                private T asObject(String value) {
1574                        try {
1575                                return _asObject(value);
1576                        } catch (Exception e) {
1577                                throw new IllegalStateException(Messages.INSTANCE.getExceptionMessage(26, parameterName), e);
1578                        }
1579                }
1580
1581                /**
1582                 * Converts the object to a String value for storing in the
1583                 * {@link ICalParameters} object.
1584                 * @param value the value
1585                 * @return the string value
1586                 */
1587                protected abstract String _asString(T value);
1588
1589                /**
1590                 * Converts a String value to its object form.
1591                 * @param value the string value
1592                 * @return the object
1593                 * @throws Exception if there is a problem parsing the string
1594                 */
1595                protected abstract T _asObject(String value) throws Exception;
1596        }
1597}