001 package ezvcard.types;
002
003 import java.util.ArrayList;
004 import java.util.Arrays;
005 import java.util.List;
006
007 import ezvcard.VCardSubTypes;
008 import ezvcard.VCardVersion;
009 import ezvcard.io.CompatibilityMode;
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 * <p>
045 * Contains the separated components of the person's name.
046 * </p>
047 *
048 * <p>
049 * Multiple instances of this type can be added ONLY if each instance has an
050 * ALTID parameter and the value of the ALTID parameter is the same across all
051 * instances. However, this is a border-case; under most circumstances, you will
052 * only need to add one instance.
053 * </p>
054 *
055 * <pre>
056 * VCard vcard = new VCard();
057 * StructuredNameType n = new StructuredNameType();
058 * n.setFamily("House");
059 * n.setGiven("Gregory");
060 * n.addPrefix("Dr");
061 * n.addSuffix("MD");
062 * vcard.setStructuredName(n);
063 * </pre>
064 *
065 * <p>
066 * vCard property name: N
067 * </p>
068 * <p>
069 * vCard versions: 2.1, 3.0, 4.0
070 * </p>
071 * @author Michael Angstadt
072 */
073 public class StructuredNameType extends VCardType {
074 public static final String NAME = "N";
075
076 private String family;
077 private String given;
078 private List<String> additional = new ArrayList<String>();
079 private List<String> prefixes = new ArrayList<String>();
080 private List<String> suffixes = new ArrayList<String>();
081
082 public StructuredNameType() {
083 super(NAME);
084 }
085
086 /**
087 * Gets the family name (aka "last name").
088 * @return the family name or null if not set
089 */
090 public String getFamily() {
091 return family;
092 }
093
094 /**
095 * Sets the family name (aka "last name").
096 * @param family the family name or null to remove
097 */
098 public void setFamily(String family) {
099 this.family = family;
100 }
101
102 /**
103 * Gets the given name (aka "first name").
104 * @return the given name or null if not set
105 */
106 public String getGiven() {
107 return given;
108 }
109
110 /**
111 * Sets the given name (aka "first name").
112 * @param given the given name or null to remove
113 */
114 public void setGiven(String given) {
115 this.given = given;
116 }
117
118 /**
119 * Gets any additional names the person goes by.
120 * @return the additional names or empty list if there are none
121 */
122 public List<String> getAdditional() {
123 return additional;
124 }
125
126 /**
127 * Adds an additional name the person goes by.
128 * @param additional the additional name to add
129 */
130 public void addAdditional(String additional) {
131 this.additional.add(additional);
132 }
133
134 /**
135 * Gets the prefixes.
136 * @return the prefixes (e.g. "Mr.") or empty list if there are none
137 */
138 public List<String> getPrefixes() {
139 return prefixes;
140 }
141
142 /**
143 * Adds a prefix.
144 * @param prefix the prefix to add (e.g. "Mr.")
145 */
146 public void addPrefix(String prefix) {
147 this.prefixes.add(prefix);
148 }
149
150 /**
151 * Gets the suffixes.
152 * @return the suffixes (e.g. "Jr.") or empty list if there are none
153 */
154 public List<String> getSuffixes() {
155 return suffixes;
156 }
157
158 /**
159 * Adds a suffix.
160 * @param suffix the suffix to add (e.g. "Jr.")
161 */
162 public void addSuffix(String suffix) {
163 this.suffixes.add(suffix);
164 }
165
166 /**
167 * Gets the string(s) that define how to sort the vCard.
168 * <p>
169 * 2.1 and 3.0 vCards should use the {@link SortStringType SORT-STRING}
170 * property instead.
171 * </p>
172 * <p>
173 * vCard versions: 4.0
174 * </p>
175 * @return the sort string(s) (e.g. ["Aboville", "Christine"] if the family
176 * name is "d'Aboville" and the given name is "Christine") or empty list if
177 * there are none
178 * @see VCardSubTypes#getSortAs
179 */
180 public List<String> getSortAs() {
181 return subTypes.getSortAs();
182 }
183
184 /**
185 * Sets the string that defines how to sort the vCard.
186 * <p>
187 * 2.1 and 3.0 vCards should use the {@link SortStringType SORT-STRING}
188 * property instead.
189 * </p>
190 * <p>
191 * vCard versions: 4.0
192 * </p>
193 * @param family the sorttable family name (e.g. "Adboville" if the family
194 * name is "d'Aboville") or null to remove
195 */
196 public void setSortAs(String family) {
197 if (family == null) {
198 subTypes.setSortAs();
199 } else {
200 subTypes.setSortAs(family);
201 }
202 }
203
204 /**
205 * Sets the strings that define how to sort the vCard.
206 * <p>
207 * 2.1 and 3.0 vCards should use the {@link SortStringType SORT-STRING}
208 * property instead.
209 * </p>
210 * <p>
211 * vCard versions: 4.0
212 * </p>
213 * @param family the sortable family name (e.g. "Adboville" if the family
214 * name is "d'Aboville")
215 * @param given the sortable given name
216 */
217 public void setSortAs(String family, String given) {
218 subTypes.setSortAs(family, given);
219 }
220
221 /**
222 * Gets the language the name is written in.
223 * @return the language or null if not set
224 * @see VCardSubTypes#getLanguage
225 */
226 public String getLanguage() {
227 return subTypes.getLanguage();
228 }
229
230 /**
231 * Sets the language the name is written in.
232 * @param language the language or null to remove
233 * @see VCardSubTypes#setLanguage
234 */
235 public void setLanguage(String language) {
236 subTypes.setLanguage(language);
237 }
238
239 /**
240 * Gets the ALTID.
241 * <p>
242 * vCard versions: 4.0
243 * </p>
244 * @return the ALTID or null if it doesn't exist
245 * @see VCardSubTypes#getAltId
246 */
247 public String getAltId() {
248 return subTypes.getAltId();
249 }
250
251 /**
252 * Sets the ALTID.
253 * <p>
254 * vCard versions: 4.0
255 * </p>
256 * @param altId the ALTID or null to remove
257 * @see VCardSubTypes#setAltId
258 */
259 public void setAltId(String altId) {
260 subTypes.setAltId(altId);
261 }
262
263 @Override
264 protected void doMarshalText(StringBuilder value, VCardVersion version, List<String> warnings, CompatibilityMode compatibilityMode) {
265 if (family != null) {
266 value.append(VCardStringUtils.escape(family));
267 }
268
269 value.append(';');
270 if (given != null) {
271 value.append(VCardStringUtils.escape(given));
272 }
273
274 value.append(';');
275 if (!additional.isEmpty()) {
276 for (String s : additional) {
277 value.append(VCardStringUtils.escape(s)).append(',');
278 }
279 value.deleteCharAt(value.length() - 1);
280 }
281
282 value.append(';');
283 if (!prefixes.isEmpty()) {
284 for (String s : prefixes) {
285 value.append(VCardStringUtils.escape(s)).append(',');
286 }
287 value.deleteCharAt(value.length() - 1);
288 }
289
290 value.append(';');
291 if (!suffixes.isEmpty()) {
292 for (String s : suffixes) {
293 value.append(VCardStringUtils.escape(s)).append(',');
294 }
295 value.deleteCharAt(value.length() - 1);
296 }
297 }
298
299 @Override
300 protected void doUnmarshalText(String value, VCardVersion version, List<String> warnings, CompatibilityMode compatibilityMode) {
301 //preserve empty items and don't unescape escaped characters(e.g. "additional" might have escaped commas)
302 String split[] = VCardStringUtils.splitBy(value, ';', false, false);
303
304 int i = 0;
305
306 family = (split.length > i && split[i].length() > 0) ? VCardStringUtils.unescape(split[i]) : null;
307 i++;
308
309 given = (split.length > i && split[i].length() > 0) ? VCardStringUtils.unescape(split[i]) : null;
310 i++;
311
312 if (split.length > i && split[i].length() > 0) {
313 additional = new ArrayList<String>(Arrays.asList(VCardStringUtils.splitBy(split[i], ',', true, true)));
314 } else {
315 additional = new ArrayList<String>();
316 }
317 i++;
318
319 if (split.length > i && split[i].length() > 0) {
320 prefixes = new ArrayList<String>(Arrays.asList(VCardStringUtils.splitBy(split[i], ',', true, true)));
321 } else {
322 prefixes = new ArrayList<String>();
323 }
324 i++;
325
326 if (split.length > i && split[i].length() > 0) {
327 suffixes = new ArrayList<String>(Arrays.asList(VCardStringUtils.splitBy(split[i], ',', true, true)));
328 } else {
329 suffixes = new ArrayList<String>();
330 }
331 i++;
332 }
333
334 @Override
335 protected void doMarshalXml(XCardElement parent, List<String> warnings, CompatibilityMode compatibilityMode) {
336 if (family != null) {
337 parent.append("surname", family);
338 }
339 if (given != null) {
340 parent.append("given", given);
341 }
342 parent.append("additional", additional);
343 parent.append("prefix", prefixes);
344 parent.append("suffix", suffixes);
345 }
346
347 @Override
348 protected void doUnmarshalXml(XCardElement element, List<String> warnings, CompatibilityMode compatibilityMode) {
349 family = element.get("surname");
350 given = element.get("given");
351
352 additional.clear();
353 additional.addAll(element.getAll("additional"));
354
355 prefixes.clear();
356 prefixes.addAll(element.getAll("prefix"));
357
358 suffixes.clear();
359 suffixes.addAll(element.getAll("suffix"));
360 }
361
362 @Override
363 protected void doUnmarshalHtml(HCardElement element, List<String> warnings) {
364 family = element.firstValue("family-name");
365 given = element.firstValue("given-name");
366
367 additional.clear();
368 additional.addAll(element.allValues("additional-name"));
369
370 prefixes.clear();
371 prefixes.addAll(element.allValues("honorific-prefix"));
372
373 suffixes.clear();
374 suffixes.addAll(element.allValues("honorific-suffix"));
375 }
376 }