001 package biweekly.property.marshaller;
002
003 import java.util.ArrayList;
004 import java.util.Date;
005 import java.util.List;
006
007 import biweekly.ICalDataType;
008 import biweekly.Warning;
009 import biweekly.io.json.JCalValue;
010 import biweekly.io.xml.XCalElement;
011 import biweekly.parameter.ICalParameters;
012 import biweekly.property.FreeBusy;
013 import biweekly.util.Duration;
014 import biweekly.util.Period;
015
016 /*
017 Copyright (c) 2013, Michael Angstadt
018 All rights reserved.
019
020 Redistribution and use in source and binary forms, with or without
021 modification, are permitted provided that the following conditions are met:
022
023 1. Redistributions of source code must retain the above copyright notice, this
024 list of conditions and the following disclaimer.
025 2. Redistributions in binary form must reproduce the above copyright notice,
026 this list of conditions and the following disclaimer in the documentation
027 and/or other materials provided with the distribution.
028
029 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
030 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
031 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
032 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
033 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
034 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
035 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
036 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
037 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
038 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
039 */
040
041 /**
042 * Marshals {@link FreeBusy} properties.
043 * @author Michael Angstadt
044 */
045 public class FreeBusyMarshaller extends ICalPropertyMarshaller<FreeBusy> {
046 public FreeBusyMarshaller() {
047 super(FreeBusy.class, "FREEBUSY", ICalDataType.PERIOD);
048 }
049
050 @Override
051 protected String _writeText(FreeBusy property) {
052 List<Period> values = property.getValues();
053
054 return list(values, new ListCallback<Period>() {
055 public String asString(Period period) {
056 StringBuilder sb = new StringBuilder();
057
058 if (period.getStartDate() != null) {
059 String date = date(period.getStartDate()).write();
060 sb.append(date);
061 }
062
063 sb.append('/');
064
065 if (period.getEndDate() != null) {
066 String date = date(period.getEndDate()).write();
067 sb.append(date);
068 } else if (period.getDuration() != null) {
069 sb.append(period.getDuration());
070 }
071
072 return sb.toString();
073 }
074 });
075 }
076
077 @Override
078 protected FreeBusy _parseText(String value, ICalDataType dataType, ICalParameters parameters, List<Warning> warnings) {
079 return parse(list(value), parameters, warnings);
080 }
081
082 @Override
083 protected void _writeXml(FreeBusy property, XCalElement element) {
084 for (Period period : property.getValues()) {
085 XCalElement periodElement = element.append(ICalDataType.PERIOD);
086
087 Date start = period.getStartDate();
088 if (start != null) {
089 periodElement.append("start", date(start).extended(true).write());
090 }
091
092 Date end = period.getEndDate();
093 if (end != null) {
094 periodElement.append("end", date(end).extended(true).write());
095 }
096
097 Duration duration = period.getDuration();
098 if (duration != null) {
099 periodElement.append("duration", duration.toString());
100 }
101 }
102 }
103
104 @Override
105 protected FreeBusy _parseXml(XCalElement element, ICalParameters parameters, List<Warning> warnings) {
106 List<XCalElement> periodElements = element.children(ICalDataType.PERIOD);
107 if (periodElements.isEmpty()) {
108 throw missingXmlElements(ICalDataType.PERIOD);
109 }
110
111 FreeBusy prop = new FreeBusy();
112 for (XCalElement periodElement : periodElements) {
113 String startStr = periodElement.first("start");
114 if (startStr == null) {
115 warnings.add(Warning.parse(9));
116 continue;
117 }
118
119 Date start = null;
120 try {
121 start = date(startStr).tzid(parameters.getTimezoneId(), warnings).parse();
122 } catch (IllegalArgumentException e) {
123 warnings.add(Warning.parse(10, startStr));
124 continue;
125 }
126
127 String endStr = periodElement.first("end");
128 if (endStr != null) {
129 try {
130 Date end = date(endStr).tzid(parameters.getTimezoneId(), warnings).parse();
131 prop.addValue(start, end);
132 } catch (IllegalArgumentException e) {
133 warnings.add(Warning.parse(11, endStr));
134 }
135 continue;
136 }
137
138 String durationStr = periodElement.first("duration");
139 if (durationStr != null) {
140 try {
141 Duration duration = Duration.parse(durationStr);
142 prop.addValue(start, duration);
143 } catch (IllegalArgumentException e) {
144 warnings.add(Warning.parse(12, durationStr));
145 }
146 continue;
147 }
148
149 warnings.add(Warning.parse(13));
150 }
151 return prop;
152 }
153
154 @Override
155 protected JCalValue _writeJson(FreeBusy property) {
156 List<Period> values = property.getValues();
157 if (values.isEmpty()) {
158 return JCalValue.single("");
159 }
160
161 List<String> valuesStr = new ArrayList<String>();
162 for (Period period : values) {
163 StringBuilder sb = new StringBuilder();
164 if (period.getStartDate() != null) {
165 String date = date(period.getStartDate()).extended(true).write();
166 sb.append(date);
167 }
168
169 sb.append('/');
170
171 if (period.getEndDate() != null) {
172 String date = date(period.getEndDate()).extended(true).write();
173 sb.append(date);
174 } else if (period.getDuration() != null) {
175 sb.append(period.getDuration());
176 }
177
178 valuesStr.add(sb.toString());
179 }
180
181 return JCalValue.multi(valuesStr);
182 }
183
184 @Override
185 protected FreeBusy _parseJson(JCalValue value, ICalDataType dataType, ICalParameters parameters, List<Warning> warnings) {
186 return parse(value.asMulti(), parameters, warnings);
187 }
188
189 private FreeBusy parse(List<String> periods, ICalParameters parameters, List<Warning> warnings) {
190 FreeBusy freebusy = new FreeBusy();
191
192 for (String period : periods) {
193 String periodSplit[] = period.split("/");
194
195 if (periodSplit.length < 2) {
196 warnings.add(Warning.parse(13));
197 continue;
198 }
199
200 String startStr = periodSplit[0];
201 Date start = null;
202 try {
203 start = date(startStr).tzid(parameters.getTimezoneId(), warnings).parse();
204 } catch (IllegalArgumentException e) {
205 warnings.add(Warning.parse(10, startStr));
206 continue;
207 }
208
209 String endStr = periodSplit[1];
210 try {
211 Date end = date(endStr).tzid(parameters.getTimezoneId(), warnings).parse();
212 freebusy.addValue(start, end);
213 } catch (IllegalArgumentException e) {
214 //must be a duration
215 try {
216 Duration duration = Duration.parse(endStr);
217 freebusy.addValue(start, duration);
218 } catch (IllegalArgumentException e2) {
219 warnings.add(Warning.parse(14, endStr));
220 continue;
221 }
222 }
223 }
224
225 return freebusy;
226 }
227 }