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}