001 package ezvcard.io.scribe;
002
003 import java.util.List;
004
005 import ezvcard.VCardDataType;
006 import ezvcard.VCardVersion;
007 import ezvcard.io.CannotParseException;
008 import ezvcard.io.html.HCardElement;
009 import ezvcard.io.json.JCardValue;
010 import ezvcard.io.xml.XCardElement;
011 import ezvcard.parameter.VCardParameters;
012 import ezvcard.property.Geo;
013 import ezvcard.util.GeoUri;
014 import ezvcard.util.VCardFloatFormatter;
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 Geo} properties.
043 * @author Michael Angstadt
044 */
045 public class GeoScribe extends VCardPropertyScribe<Geo> {
046 public GeoScribe() {
047 super(Geo.class, "GEO");
048 }
049
050 @Override
051 protected VCardDataType _defaultDataType(VCardVersion version) {
052 switch (version) {
053 case V2_1:
054 case V3_0:
055 return null;
056 case V4_0:
057 return VCardDataType.URI;
058 }
059 return null;
060 }
061
062 @Override
063 protected String _writeText(Geo property, VCardVersion version) {
064 return write(property, version);
065 }
066
067 @Override
068 protected Geo _parseText(String value, VCardDataType dataType, VCardVersion version, VCardParameters parameters, List<String> warnings) {
069 value = unescape(value);
070 return parse(value, version, warnings);
071 }
072
073 @Override
074 protected void _writeXml(Geo property, XCardElement parent) {
075 parent.append(VCardDataType.URI, write(property, parent.version()));
076 }
077
078 @Override
079 protected Geo _parseXml(XCardElement element, VCardParameters parameters, List<String> warnings) {
080 String value = element.first(VCardDataType.URI);
081 if (value != null) {
082 return parse(value, element.version(), warnings);
083 }
084
085 throw missingXmlElements(VCardDataType.URI);
086 }
087
088 @Override
089 protected Geo _parseHtml(HCardElement element, List<String> warnings) {
090 String latitudeStr = element.firstValue("latitude");
091 if (latitudeStr == null) {
092 throw new CannotParseException(7);
093 }
094
095 Double latitude;
096 try {
097 latitude = Double.parseDouble(latitudeStr);
098 } catch (NumberFormatException e) {
099 throw new CannotParseException(8, latitudeStr);
100 }
101
102 String longitudeStr = element.firstValue("longitude");
103 if (longitudeStr == null) {
104 throw new CannotParseException(9);
105 }
106
107 Double longitude;
108 try {
109 longitude = Double.parseDouble(longitudeStr);
110 } catch (NumberFormatException e) {
111 throw new CannotParseException(10, longitudeStr);
112 }
113
114 return new Geo(latitude, longitude);
115 }
116
117 @Override
118 protected JCardValue _writeJson(Geo property) {
119 return JCardValue.single(write(property, VCardVersion.V4_0));
120 }
121
122 @Override
123 protected Geo _parseJson(JCardValue value, VCardDataType dataType, VCardParameters parameters, List<String> warnings) {
124 return parse(value.asSingle(), VCardVersion.V4_0, warnings);
125 }
126
127 private Geo parse(String value, VCardVersion version, List<String> warnings) {
128 if (value == null || value.length() == 0) {
129 return new Geo(null);
130 }
131
132 switch (version) {
133 case V2_1:
134 case V3_0:
135 SemiStructuredIterator it = semistructured(value);
136 String latitudeStr = it.next();
137 String longitudeStr = it.next();
138 if (latitudeStr == null || longitudeStr == null) {
139 throw new CannotParseException(11);
140 }
141
142 Double latitude;
143 try {
144 latitude = Double.valueOf(latitudeStr);
145 } catch (NumberFormatException e) {
146 throw new CannotParseException(8, latitudeStr);
147 }
148
149 Double longitude;
150 try {
151 longitude = Double.valueOf(longitudeStr);
152 } catch (NumberFormatException e) {
153 throw new CannotParseException(10, longitudeStr);
154 }
155
156 return new Geo(latitude, longitude);
157 case V4_0:
158 try {
159 return new Geo(GeoUri.parse(value));
160 } catch (IllegalArgumentException e) {
161 throw new CannotParseException(12);
162 }
163 }
164 return null;
165 }
166
167 private String write(Geo property, VCardVersion version) {
168 if (property.getGeoUri() == null) {
169 return "";
170 }
171
172 switch (version) {
173 case V2_1:
174 case V3_0:
175 VCardFloatFormatter formatter = new VCardFloatFormatter(6);
176 return structured(formatter.format(property.getLatitude()), formatter.format(property.getLongitude()));
177 case V4_0:
178 return property.getGeoUri().toString(6);
179 }
180 return null;
181 }
182 }