001package biweekly;
002
003import java.io.File;
004import java.io.IOException;
005import java.io.OutputStream;
006import java.io.Writer;
007import java.util.ArrayList;
008import java.util.List;
009
010import javax.xml.transform.TransformerException;
011
012import biweekly.ValidationWarnings.WarningsGroup;
013import biweekly.component.ICalComponent;
014import biweekly.component.VEvent;
015import biweekly.component.VFreeBusy;
016import biweekly.component.VJournal;
017import biweekly.component.VTimezone;
018import biweekly.component.VTodo;
019import biweekly.property.CalendarScale;
020import biweekly.property.Method;
021import biweekly.property.ProductId;
022import biweekly.property.Version;
023
024/*
025 Copyright (c) 2013, Michael Angstadt
026 All rights reserved.
027
028 Redistribution and use in source and binary forms, with or without
029 modification, are permitted provided that the following conditions are met: 
030
031 1. Redistributions of source code must retain the above copyright notice, this
032 list of conditions and the following disclaimer. 
033 2. Redistributions in binary form must reproduce the above copyright notice,
034 this list of conditions and the following disclaimer in the documentation
035 and/or other materials provided with the distribution. 
036
037 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
038 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
039 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
040 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
041 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
042 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
043 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
044 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
045 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
046 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
047 */
048
049/**
050 * <p>
051 * Represents an iCalendar object.
052 * </p>
053 * 
054 * <p>
055 * <b>Examples:</b>
056 * 
057 * <pre class="brush:java">
058 * ICalendar ical = new ICalendar();
059 * 
060 * VEvent event = new VEvent();
061 * event.setSummary("Team Meeting");
062 * Date start = ...;
063 * event.setDateStart(start);
064 * Date end = ...;
065 * event.setDateEnd(end);
066 * ical.addEvent(event);
067 * </pre>
068 * 
069 * </p>
070 * @author Michael Angstadt
071 * @see <a href="http://tools.ietf.org/html/rfc5545">RFC 5545</a>
072 */
073public class ICalendar extends ICalComponent {
074        /**
075         * <p>
076         * Creates a new iCalendar object.
077         * </p>
078         * <p>
079         * The following properties are auto-generated on object creation. These
080         * properties <b>must</b> be present in order for the iCalendar object to be
081         * valid:
082         * <ul>
083         * <li>{@link Version} - Set to the default iCalendar version ("2.0").</li>
084         * <li>{@link ProductId} - Set to a value that represents this library.</li>
085         * </ul>
086         * </p>
087         */
088        public ICalendar() {
089                setVersion(Version.v2_0());
090                setProductId(ProductId.biweekly());
091        }
092
093        /**
094         * Gets the min/max versions a consumer must support in order to
095         * successfully parse the iCalendar object. All {@link ICalendar} objects
096         * are initialized with a version of "2.0" (the default version). It is a
097         * <b>required</b> property.
098         * @return the version
099         * @see <a href="http://tools.ietf.org/html/rfc5545#page-79">RFC 5545 p.79-80</a>
100         */
101        public Version getVersion() {
102                return getProperty(Version.class);
103        }
104
105        /**
106         * Sets the min/max versions a consumer must support in order to
107         * successfully parse the iCalendar object. All {@link ICalendar} objects
108         * are initialized with a version of "2.0" (the default version). It is a
109         * <b>required</b> property.
110         * @param version the version
111         * @see <a href="http://tools.ietf.org/html/rfc5545#page-79">RFC 5545 p.79-80</a>
112         */
113        public void setVersion(Version version) {
114                setProperty(Version.class, version);
115        }
116
117        /**
118         * Gets the name of the application that created the iCalendar object. All
119         * {@link ICalendar} objects are initialized with a product ID representing
120         * this library. It is a <b>required</b> property.
121         * @return the property instance or null if not set
122         * @see <a href="http://tools.ietf.org/html/rfc5545#page-78">RFC 5545 p.78-9</a>
123         */
124        public ProductId getProductId() {
125                return getProperty(ProductId.class);
126        }
127
128        /**
129         * Sets the name of the application that created the iCalendar object. All
130         * {@link ICalendar} objects are initialized with a product ID representing
131         * this library. It is a <b>required</b> property.
132         * @param prodId the property instance or null to remove
133         * @see <a href="http://tools.ietf.org/html/rfc5545#page-78">RFC 5545 p.78-9</a>
134         */
135        public void setProductId(ProductId prodId) {
136                setProperty(ProductId.class, prodId);
137        }
138
139        /**
140         * Sets the application that created the iCalendar object. All
141         * {@link ICalendar} objects are initialized with a product ID representing
142         * this library.
143         * @param prodId a unique string representing the application (e.g.
144         * "-//Company//Application//EN") or null to remove
145         * @return the property that was created
146         * @see <a href="http://tools.ietf.org/html/rfc5545#page-78">RFC 5545 p.78-9</a>
147         */
148        public ProductId setProductId(String prodId) {
149                ProductId prop = (prodId == null) ? null : new ProductId(prodId);
150                setProductId(prop);
151                return prop;
152        }
153
154        /**
155         * Gets the calendar system that this iCalendar object uses. If none is
156         * specified, then the calendar is assumed to be in Gregorian format.
157         * @return the calendar system or null if not set
158         * @see <a href="http://tools.ietf.org/html/rfc5545#page-76">RFC 5545 p.76-7</a>
159         */
160        public CalendarScale getCalendarScale() {
161                return getProperty(CalendarScale.class);
162        }
163
164        /**
165         * Sets the calendar system that this iCalendar object uses. If none is
166         * specified, then the calendar is assumed to be in Gregorian format.
167         * @param calendarScale the calendar system or null to remove
168         * @see <a href="http://tools.ietf.org/html/rfc5545#page-76">RFC 5545 p.76-7</a>
169         */
170        public void setCalendarScale(CalendarScale calendarScale) {
171                setProperty(CalendarScale.class, calendarScale);
172        }
173
174        /**
175         * Gets the value of the Content-Type "method" parameter if the iCalendar
176         * object is defined as a MIME message entity.
177         * @return the property or null if not set
178         * @see <a href="http://tools.ietf.org/html/rfc5545#page-77">RFC 5545 p.77-8</a>
179         */
180        public Method getMethod() {
181                return getProperty(Method.class);
182        }
183
184        /**
185         * Sets the value of the Content-Type "method" parameter if the iCalendar
186         * object is defined as a MIME message entity.
187         * @param method the property or null to remove
188         * @see <a href="http://tools.ietf.org/html/rfc5545#page-77">RFC 5545 p.77-8</a>
189         */
190        public void setMethod(Method method) {
191                setProperty(Method.class, method);
192        }
193
194        /**
195         * Sets the value of the Content-Type "method" parameter if the iCalendar
196         * object is defined as a MIME message entity.
197         * @param method the method or null to remove
198         * @return the property that was created
199         * @see <a href="http://tools.ietf.org/html/rfc5545#page-77">RFC 5545 p.77-8</a>
200         */
201        public Method setMethod(String method) {
202                Method prop = (method == null) ? null : new Method(method);
203                setMethod(prop);
204                return prop;
205        }
206
207        /**
208         * Gets the events.
209         * @return the events
210         */
211        public List<VEvent> getEvents() {
212                return getComponents(VEvent.class);
213        }
214
215        /**
216         * Adds an event.
217         * @param event the event
218         */
219        public void addEvent(VEvent event) {
220                addComponent(event);
221        }
222
223        /**
224         * Gets the to-dos.
225         * @return the to-dos
226         */
227        public List<VTodo> getTodos() {
228                return getComponents(VTodo.class);
229        }
230
231        /**
232         * Adds a to-do.
233         * @param todo the to-do
234         */
235        public void addTodo(VTodo todo) {
236                addComponent(todo);
237        }
238
239        /**
240         * Gets the journal entries.
241         * @return the journal entries
242         */
243        public List<VJournal> getJournals() {
244                return getComponents(VJournal.class);
245        }
246
247        /**
248         * Adds a journal entry.
249         * @param journal the journal entry
250         */
251        public void addJournal(VJournal journal) {
252                addComponent(journal);
253        }
254
255        /**
256         * Gets the free/busy entries.
257         * @return the free/busy entries
258         */
259        public List<VFreeBusy> getFreeBusies() {
260                return getComponents(VFreeBusy.class);
261        }
262
263        /**
264         * Adds a free/busy entry.
265         * @param freeBusy the free/busy entry
266         */
267        public void addFreeBusy(VFreeBusy freeBusy) {
268                addComponent(freeBusy);
269        }
270
271        /**
272         * Gets the timezones.
273         * @return the timezones
274         */
275        public List<VTimezone> getTimezones() {
276                return getComponents(VTimezone.class);
277        }
278
279        /**
280         * Adds a timezone.
281         * @param timezone the timezone
282         */
283        public void addTimezone(VTimezone timezone) {
284                addComponent(timezone);
285        }
286
287        /**
288         * Checks this iCalendar object for data consistency problems or deviations
289         * from the spec. These problems will not prevent the iCalendar object from
290         * being written to a data stream, but may prevent it from being parsed
291         * correctly by the consuming application. These problems can largely be
292         * avoided by reading the Javadocs of the component and property classes, or
293         * by being familiar with the iCalendar standard.
294         * @return the validation warnings
295         */
296        public ValidationWarnings validate() {
297                //TODO make concurrent
298                List<WarningsGroup> warnings = validate(new ArrayList<ICalComponent>(0));
299                return new ValidationWarnings(warnings);
300        }
301
302        @SuppressWarnings("unchecked")
303        @Override
304        protected void validate(List<ICalComponent> components, List<Warning> warnings) {
305                checkRequiredCardinality(warnings, ProductId.class, Version.class);
306
307                if (this.components.isEmpty()) {
308                        warnings.add(Warning.validate(4));
309                }
310        }
311
312        /**
313         * Marshals this iCalendar object to its plain text representation.
314         * @return the plain text representation
315         */
316        public String write() {
317                return Biweekly.write(this).go();
318        }
319
320        /**
321         * Marshals this iCalendar object to its plain text representation.
322         * @param file the file to write to
323         * @throws IOException if there's an I/O problem
324         */
325        public void write(File file) throws IOException {
326                Biweekly.write(this).go(file);
327        }
328
329        /**
330         * Marshals this iCalendar object to its plain text representation.
331         * @param out the data stream to write to
332         * @throws IOException if there's an I/O problem
333         */
334        public void write(OutputStream out) throws IOException {
335                Biweekly.write(this).go(out);
336        }
337
338        /**
339         * Marshals this iCalendar object to its plain text representation.
340         * @param writer the data stream to write to
341         * @throws IOException if there's an I/O problem
342         */
343        public void write(Writer writer) throws IOException {
344                Biweekly.write(this).go(writer);
345        }
346
347        /**
348         * Marshals this iCalendar object to its XML representation (xCal). If the
349         * iCalendar object contains user-defined property or component objects, use
350         * the {@link Biweekly} class instead, in order to register the scribe
351         * classes.
352         * @return the XML document
353         * @throws IllegalArgumentException if the iCalendar object contains
354         * user-defined property or component objects
355         */
356        public String writeXml() {
357                return Biweekly.writeXml(this).indent(2).go();
358        }
359
360        /**
361         * Marshals this iCalendar object to its XML representation (xCal). If the
362         * iCalendar object contains user-defined property or component objects, use
363         * the {@link Biweekly} class instead, in order to register the scribe
364         * classes.
365         * @param file the file to write to
366         * @throws IllegalArgumentException if the iCalendar object contains
367         * user-defined property or component objects
368         * @throws TransformerException if there's an I/O problem
369         * @throws IOException if the file cannot be written to
370         */
371        public void writeXml(File file) throws TransformerException, IOException {
372                Biweekly.writeXml(this).indent(2).go(file);
373        }
374
375        /**
376         * Marshals this iCalendar object to its XML representation (xCal). If the
377         * iCalendar object contains user-defined property or component objects, use
378         * the {@link Biweekly} class instead, in order to register the scribe
379         * classes.
380         * @param out the data stream to write to
381         * @throws IllegalArgumentException if the iCalendar object contains
382         * user-defined property or component objects
383         * @throws TransformerException if there's an I/O problem
384         */
385        public void writeXml(OutputStream out) throws TransformerException {
386                Biweekly.writeXml(this).indent(2).go(out);
387        }
388
389        /**
390         * Marshals this iCalendar object to its XML representation (xCal). If the
391         * iCalendar object contains user-defined property or component objects, use
392         * the {@link Biweekly} class instead, in order to register the scribe
393         * classes.
394         * @param writer the data stream to write to
395         * @throws IllegalArgumentException if the iCalendar object contains
396         * user-defined property or component objects
397         * @throws TransformerException if there's an I/O problem
398         */
399        public void writeXml(Writer writer) throws TransformerException {
400                Biweekly.writeXml(this).indent(2).go(writer);
401        }
402
403        /**
404         * Marshals this iCalendar object to its JSON representation (jCal). If the
405         * iCalendar object contains user-defined property or component objects, use
406         * the {@link Biweekly} class instead, in order to register the scribe
407         * classes.
408         * @return the JSON string
409         * @throws IllegalArgumentException if the iCalendar object contains
410         * user-defined property or component objects
411         */
412        public String writeJson() {
413                return Biweekly.writeJson(this).go();
414        }
415
416        /**
417         * Marshals this iCalendar object to its JSON representation (jCal). If the
418         * iCalendar object contains user-defined property or component objects, use
419         * the {@link Biweekly} class instead, in order to register the scribe
420         * classes.
421         * @param file the file to write to
422         * @throws IllegalArgumentException if the iCalendar object contains
423         * user-defined property or component objects
424         * @throws IOException if there's a problem writing to the file
425         */
426        public void writeJson(File file) throws IOException {
427                Biweekly.writeJson(this).go(file);
428        }
429
430        /**
431         * Marshals this iCalendar object to its JSON representation (jCal). If the
432         * iCalendar object contains user-defined property or component objects, use
433         * the {@link Biweekly} class instead, in order to register the scribe
434         * classes.
435         * @param out the data stream to write to
436         * @throws IllegalArgumentException if the iCalendar object contains
437         * user-defined property or component objects
438         * @throws IOException if there's a problem writing to the output stream
439         */
440        public void writeJson(OutputStream out) throws IOException {
441                Biweekly.writeJson(this).go(out);
442        }
443
444        /**
445         * Marshals this iCalendar object to its JSON representation (jCal). If the
446         * iCalendar object contains user-defined property or component objects, use
447         * the {@link Biweekly} class instead, in order to register the scribe
448         * classes.
449         * @param writer the data stream to write to
450         * @throws IllegalArgumentException if the iCalendar object contains
451         * user-defined property or component objects
452         * @throws IOException if there's a problem writing to the writer
453         */
454        public void writeJson(Writer writer) throws IOException {
455                Biweekly.writeJson(this).go(writer);
456        }
457}