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}