001    package biweekly.property.marshaller;
002    
003    import java.util.Date;
004    import java.util.List;
005    
006    import biweekly.io.xml.XCalElement;
007    import biweekly.parameter.ICalParameters;
008    import biweekly.parameter.Value;
009    import biweekly.property.FreeBusy;
010    import biweekly.util.Duration;
011    import biweekly.util.Period;
012    import biweekly.util.StringUtils;
013    import biweekly.util.StringUtils.JoinCallback;
014    
015    /*
016     Copyright (c) 2013, Michael Angstadt
017     All rights reserved.
018    
019     Redistribution and use in source and binary forms, with or without
020     modification, are permitted provided that the following conditions are met: 
021    
022     1. Redistributions of source code must retain the above copyright notice, this
023     list of conditions and the following disclaimer. 
024     2. Redistributions in binary form must reproduce the above copyright notice,
025     this list of conditions and the following disclaimer in the documentation
026     and/or other materials provided with the distribution. 
027    
028     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
029     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
030     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
031     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
032     ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
033     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
034     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
035     ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
036     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
037     SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
038     */
039    
040    /**
041     * Marshals {@link FreeBusy} properties.
042     * @author Michael Angstadt
043     */
044    public class FreeBusyMarshaller extends ICalPropertyMarshaller<FreeBusy> {
045            public FreeBusyMarshaller() {
046                    super(FreeBusy.class, "FREEBUSY");
047            }
048    
049            @Override
050            protected String _writeText(FreeBusy property) {
051                    List<Period> values = property.getValues();
052                    if (values.isEmpty()) {
053                            return "";
054                    }
055    
056                    return StringUtils.join(values, ",", new JoinCallback<Period>() {
057                            public void handle(StringBuilder sb, Period period) {
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                    });
073            }
074    
075            @Override
076            protected FreeBusy _parseText(String value, ICalParameters parameters, List<String> warnings) {
077                    FreeBusy freebusy = new FreeBusy();
078    
079                    String periodStrs[] = parseList(value);
080                    for (String periodStr : periodStrs) {
081                            String periodStrSplit[] = periodStr.split("/");
082    
083                            if (periodStrSplit.length < 2) {
084                                    warnings.add("No end date or duration found, skipping time period: " + periodStr);
085                                    continue;
086                            }
087    
088                            String startStr = periodStrSplit[0];
089                            Date start = null;
090                            try {
091                                    start = date(startStr).tzid(parameters.getTimezoneId(), warnings).parse();
092                            } catch (IllegalArgumentException e) {
093                                    warnings.add("Could not parse start date, skipping time period: " + periodStr);
094                                    continue;
095                            }
096    
097                            String endStr = periodStrSplit[1];
098                            try {
099                                    Date end = date(endStr).tzid(parameters.getTimezoneId(), warnings).parse();
100                                    freebusy.addValue(start, end);
101                            } catch (IllegalArgumentException e) {
102                                    //must be a duration
103                                    try {
104                                            Duration duration = Duration.parse(endStr);
105                                            freebusy.addValue(start, duration);
106                                    } catch (IllegalArgumentException e2) {
107                                            warnings.add("Could not parse end date or duration value, skipping time period: " + periodStr);
108                                            continue;
109                                    }
110                            }
111                    }
112    
113                    return freebusy;
114            }
115    
116            @Override
117            protected void _writeXml(FreeBusy property, XCalElement element) {
118                    for (Period period : property.getValues()) {
119                            XCalElement periodElement = element.append(Value.PERIOD);
120    
121                            Date start = period.getStartDate();
122                            if (start != null) {
123                                    periodElement.append("start", date(start).extended(true).write());
124                            }
125    
126                            Date end = period.getEndDate();
127                            if (end != null) {
128                                    periodElement.append("end", date(end).extended(true).write());
129                            }
130    
131                            Duration duration = period.getDuration();
132                            if (duration != null) {
133                                    periodElement.append("duration", duration.toString());
134                            }
135                    }
136            }
137    
138            @Override
139            protected FreeBusy _parseXml(XCalElement element, ICalParameters parameters, List<String> warnings) {
140                    FreeBusy prop = new FreeBusy();
141    
142                    List<XCalElement> periodElements = element.children(Value.PERIOD);
143                    for (XCalElement periodElement : periodElements) {
144                            Date start = null;
145                            String startStr = periodElement.first("start");
146                            if (startStr != null) {
147                                    try {
148                                            start = date(startStr).tzid(parameters.getTimezoneId(), warnings).parse();
149                                    } catch (IllegalArgumentException e) {
150                                            warnings.add("Could not parse start date, skipping time period: " + startStr);
151                                            continue;
152                                    }
153                            }
154    
155                            String endStr = periodElement.first("end");
156                            if (endStr != null) {
157                                    try {
158                                            Date end = date(endStr).tzid(parameters.getTimezoneId(), warnings).parse();
159                                            prop.addValue(start, end);
160                                    } catch (IllegalArgumentException e) {
161                                            warnings.add("Could not parse end date, skipping time period: " + endStr);
162                                    }
163                                    continue;
164                            }
165    
166                            String durationStr = periodElement.first("duration");
167                            if (durationStr != null) {
168                                    try {
169                                            Duration duration = Duration.parse(durationStr);
170                                            prop.addValue(start, duration);
171                                    } catch (IllegalArgumentException e) {
172                                            warnings.add("Could not parse duration, skipping time period: " + durationStr);
173                                    }
174                                    continue;
175                            }
176                    }
177    
178                    return prop;
179            }
180    }