001package biweekly.io.scribe.property; 002 003import java.util.ArrayList; 004import java.util.Date; 005import java.util.List; 006 007import biweekly.ICalDataType; 008import biweekly.Warning; 009import biweekly.io.json.JCalValue; 010import biweekly.io.xml.XCalElement; 011import biweekly.parameter.ICalParameters; 012import biweekly.property.FreeBusy; 013import biweekly.util.Duration; 014import 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 */ 045public class FreeBusyScribe extends ICalPropertyScribe<FreeBusy> { 046 public FreeBusyScribe() { 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}