001package ezvcard.property;
002
003import java.util.LinkedHashMap;
004import java.util.List;
005import java.util.Map;
006import java.util.Objects;
007
008import ezvcard.VCard;
009import ezvcard.VCardVersion;
010import ezvcard.ValidationWarning;
011import ezvcard.parameter.Pid;
012import ezvcard.util.GeoUri;
013
014/*
015 Copyright (c) 2012-2026, Michael Angstadt
016 All rights reserved.
017
018 Redistribution and use in source and binary forms, with or without
019 modification, are permitted provided that the following conditions are met: 
020
021 1. Redistributions of source code must retain the above copyright notice, this
022 list of conditions and the following disclaimer. 
023 2. Redistributions in binary form must reproduce the above copyright notice,
024 this list of conditions and the following disclaimer in the documentation
025 and/or other materials provided with the distribution. 
026
027 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
028 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
029 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
030 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
031 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
032 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
033 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
034 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
035 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
036 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
037
038 The views and conclusions contained in the software and documentation are those
039 of the authors and should not be interpreted as representing official policies, 
040 either expressed or implied, of the FreeBSD Project.
041 */
042
043/**
044 * <p>
045 * Defines a set of latitude/longitude coordinates. There is no rule as to what
046 * these coordinates represent, but their meaning could vary depending on the
047 * value of the vCard's {@link Kind} property:
048 * </p>
049 * 
050 * <table class="simpleTable">
051 * <caption>{@link Geo} meanings by {@link Kind} value</caption>
052 * <tr>
053 * <th>{@link Kind} value</th>
054 * <th>{@link Geo} meaning</th>
055 * </tr>
056 * <tr>
057 * <td>"individual"</td>
058 * <td>The location of the person's home or workplace.</td>
059 * </tr>
060 * <tr>
061 * <td>"group"</td>
062 * <td>The location of the group's meeting place.</td>
063 * </tr>
064 * <tr>
065 * <td>"org"</td>
066 * <td>The coordinates of the organization's headquarters.</td>
067 * </tr>
068 * <tr>
069 * <td>"location"</td>
070 * <td>The coordinates of the location itself.</td>
071 * </tr>
072 * </table>
073 * 
074 * <p>
075 * <b>Code sample</b>
076 * </p>
077 * 
078 * <pre class="brush:java">
079 * VCard vcard = new VCard();
080 * 
081 * Geo geo = new Geo(40.7127, -74.0059);
082 * vcard.setGeo(geo);
083 * </pre>
084 * 
085 * <p>
086 * <b>Property name:</b> {@code GEO}
087 * </p>
088 * <p>
089 * <b>Supported versions:</b> {@code 2.1, 3.0, 4.0}
090 * </p>
091 * @author Michael Angstadt
092 * @see <a href="http://tools.ietf.org/html/rfc6350#page-38">RFC 6350 p.38</a>
093 * @see <a href="http://tools.ietf.org/html/rfc2426#page-16">RFC 2426 p.16</a>
094 * @see <a href="http://www.imc.org/pdi/vcard-21.doc">vCard 2.1 p.16</a>
095 */
096public class Geo extends VCardProperty implements HasAltId {
097        private GeoUri uri;
098
099        /**
100         * Creates a geo property.
101         * @param latitude the latitude
102         * @param longitude the longitude
103         */
104        public Geo(Double latitude, Double longitude) {
105                this(new GeoUri.Builder(latitude, longitude).build());
106        }
107
108        /**
109         * Creates a geo property.
110         * @param uri the geo URI
111         */
112        public Geo(GeoUri uri) {
113                this.uri = uri;
114        }
115
116        /**
117         * Copy constructor.
118         * @param original the property to make a copy of
119         */
120        public Geo(Geo original) {
121                super(original);
122                uri = original.uri;
123        }
124
125        /**
126         * Gets the latitude.
127         * @return the latitude
128         */
129        public Double getLatitude() {
130                return (uri == null) ? null : uri.getCoordA();
131        }
132
133        /**
134         * Sets the latitude.
135         * @param latitude the latitude
136         */
137        public void setLatitude(Double latitude) {
138                if (uri == null) {
139                        uri = new GeoUri.Builder(latitude, null).build();
140                } else {
141                        uri = new GeoUri.Builder(uri).coordA(latitude).build();
142                }
143        }
144
145        /**
146         * Gets the longitude.
147         * @return the longitude
148         */
149        public Double getLongitude() {
150                return (uri == null) ? null : uri.getCoordB();
151        }
152
153        /**
154         * Sets the longitude.
155         * @param longitude the longitude
156         */
157        public void setLongitude(Double longitude) {
158                if (uri == null) {
159                        uri = new GeoUri.Builder(null, longitude).build();
160                } else {
161                        uri = new GeoUri.Builder(uri).coordB(longitude).build();
162                }
163        }
164
165        /**
166         * Gets the raw object used for storing the GEO information. This can be
167         * used to supplement the GEO value with additional information (such as
168         * altitude or level of accuracy). Geo URIs are only supported by vCard
169         * version 4.0. Only latitude and longitude values are used when marshalling
170         * to earlier vCard versions.
171         * @return the geo URI object or null if not set
172         * @see <a href="http://tools.ietf.org/html/rfc5870">RFC 5870</a>
173         */
174        public GeoUri getGeoUri() {
175                return uri;
176        }
177
178        /**
179         * Sets the raw object used for storing the GEO information. This can be
180         * used to supplement the GEO value with additional information (such as
181         * altitude or level of accuracy). Geo URIs are only supported by vCard
182         * version 4.0. Only latitude and longitude values are used when marshalling
183         * to earlier vCard versions.
184         * @param uri the geo URI object
185         * @see <a href="http://tools.ietf.org/html/rfc5870">RFC 5870</a>
186         */
187        public void setGeoUri(GeoUri uri) {
188                this.uri = uri;
189        }
190
191        /**
192         * Gets the TYPE parameter.
193         * <p>
194         * <b>Supported versions:</b> {@code 4.0}
195         * </p>
196         * @return the TYPE value (typically, this will be either "work" or "home")
197         * or null if it doesn't exist
198         */
199        public String getType() {
200                return parameters.getType();
201        }
202
203        /**
204         * Sets the TYPE parameter.
205         * <p>
206         * <b>Supported versions:</b> {@code 4.0}
207         * </p>
208         * @param type the TYPE value (this should be either "work" or "home") or
209         * null to remove
210         */
211        public void setType(String type) {
212                parameters.setType(type);
213        }
214
215        /**
216         * Gets the MEDIATYPE parameter.
217         * <p>
218         * <b>Supported versions:</b> {@code 4.0}
219         * </p>
220         * @return the media type or null if not set
221         */
222        public String getMediaType() {
223                return parameters.getMediaType();
224        }
225
226        /**
227         * Sets the MEDIATYPE parameter.
228         * <p>
229         * <b>Supported versions:</b> {@code 4.0}
230         * </p>
231         * @param mediaType the media type or null to remove
232         */
233        public void setMediaType(String mediaType) {
234                parameters.setMediaType(mediaType);
235        }
236
237        @Override
238        public List<Pid> getPids() {
239                return super.getPids();
240        }
241
242        @Override
243        public Integer getPref() {
244                return super.getPref();
245        }
246
247        @Override
248        public void setPref(Integer pref) {
249                super.setPref(pref);
250        }
251
252        //@Override
253        public String getAltId() {
254                return parameters.getAltId();
255        }
256
257        //@Override
258        public void setAltId(String altId) {
259                parameters.setAltId(altId);
260        }
261
262        @Override
263        protected void _validate(List<ValidationWarning> warnings, VCardVersion version, VCard vcard) {
264                if (getLatitude() == null) {
265                        warnings.add(new ValidationWarning(13));
266                }
267                if (getLongitude() == null) {
268                        warnings.add(new ValidationWarning(14));
269                }
270        }
271
272        @Override
273        protected Map<String, Object> toStringValues() {
274                Map<String, Object> values = new LinkedHashMap<>();
275                values.put("uri", uri);
276                return values;
277        }
278
279        @Override
280        public Geo copy() {
281                return new Geo(this);
282        }
283
284        @Override
285        public int hashCode() {
286                final int prime = 31;
287                int result = super.hashCode();
288                result = prime * result + Objects.hash(uri);
289                return result;
290        }
291
292        @Override
293        public boolean equals(Object obj) {
294                if (this == obj) return true;
295                if (!super.equals(obj)) return false;
296                if (getClass() != obj.getClass()) return false;
297                Geo other = (Geo) obj;
298                return Objects.equals(uri, other.uri);
299        }
300}