001package biweekly.io.scribe.property;
002
003import java.util.Iterator;
004
005import biweekly.ICalDataType;
006import biweekly.ICalVersion;
007import biweekly.io.CannotParseException;
008import biweekly.io.ParseContext;
009import biweekly.io.WriteContext;
010import biweekly.io.json.JCalValue;
011import biweekly.io.xml.XCalElement;
012import biweekly.parameter.ICalParameters;
013import biweekly.property.Geo;
014import biweekly.util.ICalFloatFormatter;
015
016/*
017 Copyright (c) 2013-2015, 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 Geo} properties.
043 * @author Michael Angstadt
044 */
045public class GeoScribe extends ICalPropertyScribe<Geo> {
046        public GeoScribe() {
047                super(Geo.class, "GEO");
048        }
049
050        @Override
051        protected ICalDataType _defaultDataType(ICalVersion version) {
052                return ICalDataType.FLOAT;
053        }
054
055        @Override
056        protected String _writeText(Geo property, WriteContext context) {
057                ICalFloatFormatter formatter = new ICalFloatFormatter();
058
059                Double latitude = property.getLatitude();
060                if (latitude == null) {
061                        latitude = 0.0;
062                }
063                String latitudeStr = formatter.format(latitude);
064
065                Double longitude = property.getLongitude();
066                if (longitude == null) {
067                        longitude = 0.0;
068                }
069                String longitudeStr = formatter.format(longitude);
070
071                switch (context.getVersion()) {
072                case V1_0:
073                        return list(latitudeStr, longitudeStr);
074                default:
075                        return structured(latitudeStr, longitudeStr);
076                }
077        }
078
079        @Override
080        protected Geo _parseText(String value, ICalDataType dataType, ICalParameters parameters, ParseContext context) {
081                String latitudeStr, longitudeStr;
082                switch (context.getVersion()) {
083                case V1_0:
084                        Iterator<String> it1 = list(value).iterator();
085                        latitudeStr = it1.hasNext() ? it1.next() : null;
086                        longitudeStr = it1.hasNext() ? it1.next() : null;
087                        break;
088
089                default:
090                        SemiStructuredIterator it2 = semistructured(value, true);
091                        latitudeStr = it2.next();
092                        longitudeStr = it2.next();
093                        break;
094                }
095
096                if (latitudeStr == null || longitudeStr == null) {
097                        throw new CannotParseException(20);
098                }
099
100                return parse(latitudeStr, longitudeStr);
101        }
102
103        @Override
104        protected void _writeXml(Geo property, XCalElement element, WriteContext context) {
105                ICalFloatFormatter formatter = new ICalFloatFormatter();
106
107                Double latitude = property.getLatitude();
108                if (latitude == null) {
109                        latitude = 0.0;
110                }
111                element.append("latitude", formatter.format(latitude));
112
113                Double longitude = property.getLongitude();
114                if (longitude == null) {
115                        longitude = 0.0;
116                }
117                element.append("longitude", formatter.format(longitude));
118        }
119
120        @Override
121        protected Geo _parseXml(XCalElement element, ICalParameters parameters, ParseContext context) {
122                String latitudeStr = element.first("latitude");
123                String longitudeStr = element.first("longitude");
124                if (latitudeStr == null && longitudeStr == null) {
125                        throw missingXmlElements("latitude", "longitude");
126                }
127                if (latitudeStr == null) {
128                        throw missingXmlElements("latitude");
129                }
130                if (longitudeStr == null) {
131                        throw missingXmlElements("longitude");
132                }
133
134                return parse(latitudeStr, longitudeStr);
135        }
136
137        @Override
138        protected JCalValue _writeJson(Geo property, WriteContext context) {
139                Double latitude = property.getLatitude();
140                if (latitude == null) {
141                        latitude = 0.0;
142                }
143
144                Double longitude = property.getLongitude();
145                if (longitude == null) {
146                        longitude = 0.0;
147                }
148
149                return JCalValue.structured(latitude, longitude);
150        }
151
152        @Override
153        protected Geo _parseJson(JCalValue value, ICalDataType dataType, ICalParameters parameters, ParseContext context) {
154                StructuredIterator it = structured(value);
155                String latitudeStr = it.nextString();
156                String longitudeStr = it.nextString();
157                return parse(latitudeStr, longitudeStr);
158        }
159
160        private Geo parse(String latitudeStr, String longitudeStr) {
161                Double latitude = null;
162                if (latitudeStr != null) {
163                        try {
164                                latitude = Double.valueOf(latitudeStr);
165                        } catch (NumberFormatException e) {
166                                throw new CannotParseException(21, latitudeStr);
167                        }
168                }
169
170                Double longitude = null;
171                if (longitudeStr != null) {
172                        try {
173                                longitude = Double.valueOf(longitudeStr);
174                        } catch (NumberFormatException e) {
175                                throw new CannotParseException(22, longitudeStr);
176                        }
177                }
178
179                return new Geo(latitude, longitude);
180        }
181}