001package biweekly.property;
002
003import java.util.ArrayList;
004import java.util.Date;
005import java.util.List;
006
007import biweekly.ICalVersion;
008import biweekly.Warning;
009import biweekly.component.ICalComponent;
010import biweekly.util.ICalDate;
011import biweekly.util.Period;
012
013/*
014 Copyright (c) 2013-2015, Michael Angstadt
015 All rights reserved.
016
017 Redistribution and use in source and binary forms, with or without
018 modification, are permitted provided that the following conditions are met: 
019
020 1. Redistributions of source code must retain the above copyright notice, this
021 list of conditions and the following disclaimer. 
022 2. Redistributions in binary form must reproduce the above copyright notice,
023 this list of conditions and the following disclaimer in the documentation
024 and/or other materials provided with the distribution. 
025
026 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
027 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
028 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
029 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
030 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
031 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
032 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
033 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
034 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
035 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
036 */
037
038/**
039 * <p>
040 * Defines a list of dates or time periods that help define a recurrence rule.
041 * It must contain either dates or time periods. It cannot contain a combination
042 * of both.
043 * </p>
044 * <p>
045 * <b>Code sample:</b>
046 * 
047 * <pre class="brush:java">
048 * VEvent event = new VEvent();
049 * 
050 * //date-time values
051 * Date datetime = ...
052 * RecurrenceDates rdate = new RecurrenceDates();
053 * rdate.addDate(new ICalDate(datetime, true));
054 * event.addRecurrenceDates(rdate);
055 * 
056 * //date values
057 * Date date = ...
058 * RecurrenceDates rdate = new RecurrenceDates();
059 * rdate.addDate(new ICalDate(date, false));
060 * event.addRecurrenceDates(rdate);
061 * 
062 * //periods
063 * Period period = ...
064 * rdate = new RecurrenceDates();
065 * rdate.addPeriod(period);
066 * event.addRecurrenceDates(rdate);
067 * </pre>
068 * 
069 * </p>
070 * @author Michael Angstadt
071 * @see <a href="http://tools.ietf.org/html/rfc5545#page-120">RFC 5545
072 * p.120-2</a>
073 * @see <a href="http://tools.ietf.org/html/rfc2445#page-115">RFC 2445
074 * p.115-7</a>
075 * @see <a href="http://www.imc.org/pdi/vcal-10.doc">vCal 1.0 p.34</a>
076 */
077public class RecurrenceDates extends ICalProperty {
078        private List<ICalDate> dates = new ArrayList<ICalDate>();
079        private List<Period> periods = new ArrayList<Period>();
080
081        /**
082         * Gets the recurrence dates.
083         * @return the dates
084         */
085        public List<ICalDate> getDates() {
086                return dates;
087        }
088
089        /**
090         * Adds a date.
091         * @param date the date to add
092         */
093        public void addDate(ICalDate date) {
094                dates.add(date);
095        }
096
097        /**
098         * Adds a date
099         * @param date the date to add
100         */
101        public void addDate(Date date) {
102                addDate(new ICalDate(date, true));
103        }
104
105        /**
106         * Gets the time periods.
107         * @return the time periods
108         */
109        public List<Period> getPeriods() {
110                return periods;
111        }
112
113        /**
114         * Adds a period
115         * @param period the period to add
116         */
117        public void addPeriod(Period period) {
118                periods.add(period);
119        }
120
121        @Override
122        protected void validate(List<ICalComponent> components, ICalVersion version, List<Warning> warnings) {
123                if (dates.isEmpty() && periods.isEmpty()) {
124                        //no value
125                        warnings.add(Warning.validate(26));
126                }
127
128                if (!dates.isEmpty() && !periods.isEmpty()) {
129                        //can't mix dates and periods
130                        warnings.add(Warning.validate(49));
131                }
132
133                if (version == ICalVersion.V1_0 && !periods.isEmpty()) {
134                        //1.0 doesn't support periods
135                        warnings.add(Warning.validate(51));
136                }
137
138                if (!dates.isEmpty()) {
139                        //can't mix date and date-time values
140                        boolean hasTime = dates.get(0).hasTime();
141                        for (ICalDate date : dates.subList(1, dates.size())) {
142                                if (date.hasTime() != hasTime) {
143                                        warnings.add(Warning.validate(50));
144                                        break;
145                                }
146                        }
147                }
148        }
149}