001 package ezvcard.types;
002
003 import java.util.List;
004
005 import ezvcard.VCard;
006 import ezvcard.VCardSubTypes;
007 import ezvcard.VCardVersion;
008 import ezvcard.io.CompatibilityMode;
009 import ezvcard.parameters.AddressTypeParameter;
010 import ezvcard.util.HCardElement;
011 import ezvcard.util.VCardStringUtils;
012 import ezvcard.util.XCardElement;
013
014 /*
015 Copyright (c) 2012, 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 * A mailing address.
045 *
046 * <p>
047 * <b>Adding an address</b>
048 * </p>
049 *
050 * <pre>
051 * VCard vcard = new VCard();
052 * AddressType adr = new AddressType();
053 * adr.setStreetAddress("123 Main St.");
054 * adr.setLocality("Austin");
055 * adr.setRegion("TX");
056 * adr.setPostalCode("12345");
057 * adr.setCountry("USA");
058 * adr.addType(AddressTypeParameter.WORK);
059 * adr.addType(AddressTypeParameter.DOM);
060 *
061 * //optionally, provide the exact text to print out on the mailing label
062 * adr.setLabel("123 Main St.\nAustin, Tx 12345\nUSA");
063 *
064 * vcard.addAddress(adr);
065 * </pre>
066 *
067 * <p>
068 * <b>Getting the addresses</b>
069 * </p>
070 *
071 * <pre>
072 * VCard vcard = ...
073 * for (AddressType adr : vcard.getAddresses()){
074 * ...
075 * }
076 * </pre>
077 *
078 * <p>
079 * vCard property name: ADR
080 * </p>
081 * <p>
082 * vCard versions: 2.1, 3.0, 4.0
083 * </p>
084 * @author Michael Angstadt
085 */
086 public class AddressType extends MultiValuedTypeParameterType<AddressTypeParameter> {
087 public static final String NAME = "ADR";
088
089 private String poBox;
090 private String extendedAddress;
091 private String streetAddress;
092 private String locality;
093 private String region;
094 private String postalCode;
095 private String country;
096
097 public AddressType() {
098 super(NAME);
099 }
100
101 @Override
102 protected AddressTypeParameter buildTypeObj(String type) {
103 AddressTypeParameter param = AddressTypeParameter.valueOf(type);
104 if (param == null) {
105 param = new AddressTypeParameter(type);
106 }
107 return param;
108 }
109
110 /**
111 * Gets the P.O. (post office) box.
112 * @return the P.O. box or null if not set
113 */
114 public String getPoBox() {
115 return poBox;
116 }
117
118 /**
119 * Sets the P.O. (post office) box.
120 * @param poBox the P.O. box or null to remove
121 */
122 public void setPoBox(String poBox) {
123 this.poBox = poBox;
124 }
125
126 /**
127 * Gets the extended address.
128 * @return the extended address (e.g. "Suite 200") or null if not set
129 */
130 public String getExtendedAddress() {
131 return extendedAddress;
132 }
133
134 /**
135 * Sets the extended address.
136 * @param extendedAddress the extended address (e.g. "Suite 200") or null to
137 * remove
138 */
139 public void setExtendedAddress(String extendedAddress) {
140 this.extendedAddress = extendedAddress;
141 }
142
143 /**
144 * Gets the street address
145 * @return the street address (e.g. "123 Main St")
146 */
147 public String getStreetAddress() {
148 return streetAddress;
149 }
150
151 /**
152 * Sets the street address.
153 * @param streetAddress the street address (e.g. "123 Main St") or null to
154 * remove
155 */
156 public void setStreetAddress(String streetAddress) {
157 this.streetAddress = streetAddress;
158 }
159
160 /**
161 * Gets the locality (city)
162 * @return the locality (e.g. "Boston") or null if not set
163 */
164 public String getLocality() {
165 return locality;
166 }
167
168 /**
169 * Sets the locality (city).
170 * @param locality the locality or null to remove
171 */
172 public void setLocality(String locality) {
173 this.locality = locality;
174 }
175
176 /**
177 * Gets the region.
178 * @return the region (e.g. "Texas") or null if not set
179 */
180 public String getRegion() {
181 return region;
182 }
183
184 /**
185 * Sets the region.
186 * @param region the region (e.g. "Texas") or null to remove
187 */
188 public void setRegion(String region) {
189 this.region = region;
190 }
191
192 /**
193 * Gets the postal code.
194 * @return the postal code (e.g. "90210") or null if not set
195 */
196 public String getPostalCode() {
197 return postalCode;
198 }
199
200 /**
201 * Sets the postal code.
202 * @param postalCode the postal code (e.g. "90210") or null to remove
203 */
204 public void setPostalCode(String postalCode) {
205 this.postalCode = postalCode;
206 }
207
208 /**
209 * Gets the country.
210 * @return the country (e.g. "USA") or null if not set
211 */
212 public String getCountry() {
213 return country;
214 }
215
216 /**
217 * Sets the country.
218 * @param country the country (e.g. "USA") or null to remove
219 */
220 public void setCountry(String country) {
221 this.country = country;
222 }
223
224 /**
225 * Gets the language that the address is written in.
226 * @return the language or null if not set
227 * @see VCardSubTypes#getLanguage
228 */
229 public String getLanguage() {
230 return subTypes.getLanguage();
231 }
232
233 /**
234 * Sets the language that the address is written in.
235 * @param language the language or null to remove
236 * @see VCardSubTypes#setLanguage
237 */
238 public void setLanguage(String language) {
239 subTypes.setLanguage(language);
240 }
241
242 /**
243 * Gets the label of the address.
244 * @return the label or null if it doesn't have one
245 */
246 public String getLabel() {
247 return subTypes.getFirst("LABEL");
248 }
249
250 /**
251 * Sets the label of the address.
252 * @param label the label or null to remove
253 */
254 public void setLabel(String label) {
255 subTypes.replace("LABEL", label);
256 }
257
258 /**
259 * Gets the global positioning coordinates that are associated with this
260 * address.
261 * <p>
262 * vCard versions: 4.0
263 * </p>
264 * @return the latitude (index 0) and longitude (index 1) or null if not set
265 * or null if the parameter value was in an incorrect format
266 * @see VCardSubTypes#getGeo
267 */
268 public double[] getGeo() {
269 return subTypes.getGeo();
270 }
271
272 /**
273 * Sets the global positioning coordinates that are associated with this
274 * address.
275 * <p>
276 * vCard versions: 4.0
277 * </p>
278 * @param latitude the latitude
279 * @param longitude the longitude
280 * @see VCardSubTypes#setGeo
281 */
282 public void setGeo(double latitude, double longitude) {
283 subTypes.setGeo(latitude, longitude);
284 }
285
286 /**
287 * Gets all PID parameter values.
288 * <p>
289 * vCard versions: 4.0
290 * </p>
291 * @return the PID values or empty set if there are none
292 * @see VCardSubTypes#getPids
293 */
294 public List<Integer[]> getPids() {
295 return subTypes.getPids();
296 }
297
298 /**
299 * Adds a PID value.
300 * <p>
301 * vCard versions: 4.0
302 * </p>
303 * @param localId the local ID
304 * @param clientPidMapRef the ID used to reference the property's globally
305 * unique identifier in the CLIENTPIDMAP property.
306 * @see VCardSubTypes#addPid(int, int)
307 */
308 public void addPid(int localId, int clientPidMapRef) {
309 subTypes.addPid(localId, clientPidMapRef);
310 }
311
312 /**
313 * Removes all PID values.
314 * <p>
315 * vCard versions: 4.0
316 * </p>
317 * @see VCardSubTypes#removePids
318 */
319 public void removePids() {
320 subTypes.removePids();
321 }
322
323 /**
324 * Gets the preference value.
325 * <p>
326 * vCard versions: 4.0
327 * </p>
328 * @return the preference value or null if it doesn't exist
329 * @see VCardSubTypes#getPref
330 */
331 public Integer getPref() {
332 return subTypes.getPref();
333 }
334
335 /**
336 * Sets the preference value.
337 * <p>
338 * vCard versions: 4.0
339 * </p>
340 * @param pref the preference value or null to remove
341 * @see VCardSubTypes#setPref
342 */
343 public void setPref(Integer pref) {
344 subTypes.setPref(pref);
345 }
346
347 /**
348 * Gets the ALTID.
349 * <p>
350 * vCard versions: 4.0
351 * </p>
352 * @return the ALTID or null if it doesn't exist
353 * @see VCardSubTypes#getAltId
354 */
355 public String getAltId() {
356 return subTypes.getAltId();
357 }
358
359 /**
360 * Sets the ALTID.
361 * <p>
362 * vCard versions: 4.0
363 * </p>
364 * @param altId the ALTID or null to remove
365 * @see VCardSubTypes#setAltId
366 */
367 public void setAltId(String altId) {
368 subTypes.setAltId(altId);
369 }
370
371 /**
372 * Gets the timezone that's associated with this address.
373 * <p>
374 * vCard versions: 4.0
375 * </p>
376 * @return the timezone (e.g. "America/New_York") or null if it doesn't
377 * exist
378 */
379 public String getTimezone() {
380 String value = subTypes.getFirst("TZ");
381 if (value.matches("(?i)tz:.*")) {
382 //remove the "tz:"
383 value = (value.length() > 3) ? value.substring(3) : "";
384 }
385 return value;
386 }
387
388 /**
389 * Sets the timezone that's associated with this address.
390 * <p>
391 * vCard versions: 4.0
392 * </p>
393 * @param timezone the timezone (e.g. "America/New_York") or null to remove
394 */
395 public void setTimezone(String timezone) {
396 subTypes.replace("TZ", "tz:" + timezone);
397 }
398
399 @Override
400 protected void doMarshalSubTypes(VCardSubTypes copy, VCardVersion version, List<String> warnings, CompatibilityMode compatibilityMode, VCard vcard) {
401 //replace "TYPE=pref" with "PREF=1"
402 if (version == VCardVersion.V4_0) {
403 if (getTypes().contains(AddressTypeParameter.PREF)) {
404 copy.removeType(AddressTypeParameter.PREF.getValue());
405 copy.setPref(1);
406 }
407 } else {
408 copy.setPref(null);
409
410 //find the ADR with the lowest PREF value in the vCard
411 AddressType mostPreferred = null;
412 for (AddressType adr : vcard.getAddresses()) {
413 Integer pref = adr.getPref();
414 if (pref != null) {
415 if (mostPreferred == null || pref < mostPreferred.getPref()) {
416 mostPreferred = adr;
417 }
418 }
419 }
420 if (this == mostPreferred) {
421 copy.addType(AddressTypeParameter.PREF.getValue());
422 }
423 }
424
425 //remove the LABEL parameter
426 if (version != VCardVersion.V4_0) {
427 copy.removeAll("LABEL");
428 }
429 }
430
431 @Override
432 protected void doMarshalText(StringBuilder sb, VCardVersion version, List<String> warnings, CompatibilityMode compatibilityMode) {
433 if (poBox != null) {
434 sb.append(VCardStringUtils.escape(poBox));
435 }
436 sb.append(';');
437
438 if (extendedAddress != null) {
439 sb.append(VCardStringUtils.escape(extendedAddress));
440 }
441 sb.append(';');
442
443 if (streetAddress != null) {
444 sb.append(VCardStringUtils.escape(streetAddress));
445 }
446 sb.append(';');
447
448 if (locality != null) {
449 sb.append(VCardStringUtils.escape(locality));
450 }
451 sb.append(';');
452
453 if (region != null) {
454 sb.append(VCardStringUtils.escape(region));
455 }
456 sb.append(';');
457
458 if (postalCode != null) {
459 sb.append(VCardStringUtils.escape(postalCode));
460 }
461 sb.append(';');
462
463 if (country != null) {
464 sb.append(VCardStringUtils.escape(country));
465 }
466 }
467
468 @Override
469 protected void doUnmarshalText(String value, VCardVersion version, List<String> warnings, CompatibilityMode compatibilityMode) {
470 String split[] = VCardStringUtils.splitBy(value, ';', false, true);
471
472 int i = 0;
473
474 poBox = (split.length > i && split[i].length() > 0) ? split[i] : null;
475 i++;
476
477 extendedAddress = (split.length > i && split[i].length() > 0) ? split[i] : null;
478 i++;
479
480 streetAddress = (split.length > i && split[i].length() > 0) ? split[i] : null;
481 i++;
482
483 locality = (split.length > i && split[i].length() > 0) ? split[i] : null;
484 i++;
485
486 region = (split.length > i && split[i].length() > 0) ? split[i] : null;
487 i++;
488
489 postalCode = (split.length > i && split[i].length() > 0) ? split[i] : null;
490 i++;
491
492 country = (split.length > i && split[i].length() > 0) ? split[i] : null;
493 }
494
495 @Override
496 protected void doMarshalXml(XCardElement parent, List<String> warnings, CompatibilityMode compatibilityMode) {
497 if (poBox != null) {
498 parent.append("pobox", poBox);
499 }
500 if (extendedAddress != null) {
501 parent.append("ext", extendedAddress);
502 }
503 if (streetAddress != null) {
504 parent.append("street", streetAddress);
505 }
506 if (locality != null) {
507 parent.append("locality", locality);
508 }
509 if (region != null) {
510 parent.append("region", region);
511 }
512 if (postalCode != null) {
513 parent.append("code", postalCode);
514 }
515 if (country != null) {
516 parent.append("country", country);
517 }
518 }
519
520 @Override
521 protected void doUnmarshalXml(XCardElement element, List<String> warnings, CompatibilityMode compatibilityMode) {
522 poBox = element.get("pobox");
523 extendedAddress = element.get("ext");
524 streetAddress = element.get("street");
525 locality = element.get("locality");
526 region = element.get("region");
527 postalCode = element.get("code");
528 country = element.get("country");
529 }
530
531 @Override
532 protected void doUnmarshalHtml(HCardElement element, List<String> warnings) {
533 poBox = element.firstValue("post-office-box");
534 extendedAddress = element.firstValue("extended-address");
535 streetAddress = element.firstValue("street-address");
536 locality = element.firstValue("locality");
537 region = element.firstValue("region");
538 postalCode = element.firstValue("postal-code");
539 country = element.firstValue("country-name");
540 List<String> types = element.types();
541 for (String type : types) {
542 subTypes.addType(type);
543 }
544 }
545 }