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 }