001package biweekly.io.scribe.property;
002
003import static biweekly.ICalDataType.DATE;
004import static biweekly.ICalDataType.DATE_TIME;
005
006import java.util.ArrayList;
007import java.util.List;
008
009import biweekly.ICalDataType;
010import biweekly.ICalVersion;
011import biweekly.io.CannotParseException;
012import biweekly.io.ParseContext;
013import biweekly.io.WriteContext;
014import biweekly.io.json.JCalValue;
015import biweekly.io.xml.XCalElement;
016import biweekly.parameter.ICalParameters;
017import biweekly.property.ExceptionDates;
018import biweekly.util.ICalDate;
019
020/*
021 Copyright (c) 2013-2015, Michael Angstadt
022 All rights reserved.
023
024 Redistribution and use in source and binary forms, with or without
025 modification, are permitted provided that the following conditions are met: 
026
027 1. Redistributions of source code must retain the above copyright notice, this
028 list of conditions and the following disclaimer. 
029 2. Redistributions in binary form must reproduce the above copyright notice,
030 this list of conditions and the following disclaimer in the documentation
031 and/or other materials provided with the distribution. 
032
033 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
034 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
035 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
036 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
037 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
038 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
039 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
040 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
041 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
042 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
043 */
044
045/**
046 * Marshals {@link ExceptionDates} properties.
047 * @author Michael Angstadt
048 */
049public class ExceptionDatesScribe extends ListPropertyScribe<ExceptionDates, ICalDate> {
050        public ExceptionDatesScribe() {
051                super(ExceptionDates.class, "EXDATE");
052        }
053
054        @Override
055        protected ICalDataType _defaultDataType(ICalVersion version) {
056                return DATE_TIME;
057        }
058
059        @Override
060        protected ICalParameters _prepareParameters(ExceptionDates property, WriteContext context) {
061                if (isInObservance(context)) {
062                        return property.getParameters();
063                }
064
065                boolean hasTime;
066                if (property.getValues().isEmpty()) {
067                        hasTime = false;
068                } else {
069                        hasTime = (dataType(property, context.getVersion()) == DATE_TIME);
070                }
071                return handleTzidParameter(property, hasTime, context);
072        }
073
074        @Override
075        protected ICalDataType _dataType(ExceptionDates property, ICalVersion version) {
076                List<ICalDate> dates = property.getValues();
077                if (!dates.isEmpty()) {
078                        return dates.get(0).hasTime() ? DATE_TIME : DATE;
079                }
080
081                return defaultDataType(version);
082        }
083
084        @Override
085        protected ExceptionDates newInstance(ICalDataType dataType, ICalParameters parameters) {
086                return new ExceptionDates();
087        }
088
089        @Override
090        protected String writeValue(ExceptionDates property, ICalDate value, WriteContext context) {
091                if (isInObservance(context)) {
092                        return date(value).observance(true).extended(false).write();
093                }
094
095                return date(value, property, context).extended(false).write();
096        }
097
098        @Override
099        protected ICalDate readValue(ExceptionDates property, String value, ICalDataType dataType, ICalParameters parameters, ParseContext context) {
100                ICalDate date;
101                try {
102                        boolean hasTime = (dataType == DATE_TIME);
103                        date = date(value).hasTime(hasTime).parse();
104                } catch (IllegalArgumentException e) {
105                        throw new CannotParseException(19);
106                }
107                context.addDate(date, property, parameters);
108
109                return date;
110        }
111
112        @Override
113        protected void _writeXml(ExceptionDates property, XCalElement element, WriteContext context) {
114                List<ICalDate> values = property.getValues();
115                if (values.isEmpty()) {
116                        element.append(defaultDataType(context.getVersion()), "");
117                        return;
118                }
119
120                if (isInObservance(context)) {
121                        for (ICalDate value : values) {
122                                String valueStr = date(value).observance(true).extended(true).write();
123                                element.append(DATE_TIME, valueStr);
124                        }
125                        return;
126                }
127
128                for (ICalDate value : values) {
129                        ICalDataType dataType = value.hasTime() ? DATE_TIME : DATE;
130                        String dateStr = date(value, property, context).extended(true).write();
131                        element.append(dataType, dateStr);
132                }
133        }
134
135        @Override
136        protected ExceptionDates _parseXml(XCalElement element, ICalParameters parameters, ParseContext context) {
137                List<String> dateTimeElements = element.all(DATE_TIME);
138                List<String> dateElements = element.all(DATE);
139                if (dateTimeElements.isEmpty() && dateElements.isEmpty()) {
140                        throw missingXmlElements(DATE_TIME, DATE);
141                }
142
143                ExceptionDates property = new ExceptionDates();
144                for (String value : dateTimeElements) {
145                        ICalDate datetime = readValue(property, value, DATE_TIME, parameters, context);
146                        property.addValue(datetime);
147                }
148                for (String value : dateElements) {
149                        ICalDate date = readValue(property, value, DATE, parameters, context);
150                        property.addValue(date);
151                }
152                return property;
153        }
154
155        @Override
156        protected JCalValue _writeJson(ExceptionDates property, WriteContext context) {
157                List<ICalDate> values = property.getValues();
158                if (values.isEmpty()) {
159                        return JCalValue.single("");
160                }
161
162                List<String> valuesStr = new ArrayList<String>();
163                if (isInObservance(context)) {
164                        for (ICalDate value : values) {
165                                String valueStr = date(value).observance(true).extended(true).write();
166                                valuesStr.add(valueStr);
167                        }
168                        return JCalValue.multi(valuesStr);
169                }
170
171                for (ICalDate value : values) {
172                        String dateStr = date(value, property, context).extended(true).write();
173                        valuesStr.add(dateStr);
174                }
175                return JCalValue.multi(valuesStr);
176        }
177
178        @Override
179        protected ExceptionDates _parseJson(JCalValue value, ICalDataType dataType, ICalParameters parameters, ParseContext context) {
180                List<String> valueStrs = value.asMulti();
181
182                ExceptionDates property = new ExceptionDates();
183                for (String valueStr : valueStrs) {
184                        ICalDate date = readValue(property, valueStr, dataType, parameters, context);
185                        property.addValue(date);
186                }
187                return property;
188        }
189}