001 package ezvcard.types;
002
003 import java.util.List;
004 import java.util.regex.Matcher;
005 import java.util.regex.Pattern;
006
007 import ezvcard.VCard;
008 import ezvcard.VCardSubTypes;
009 import ezvcard.VCardVersion;
010 import ezvcard.io.CompatibilityMode;
011 import ezvcard.parameters.TelephoneTypeParameter;
012 import ezvcard.parameters.ValueParameter;
013 import ezvcard.util.HCardElement;
014 import ezvcard.util.VCardStringUtils;
015 import ezvcard.util.XCardElement;
016
017 /*
018 Copyright (c) 2012, Michael Angstadt
019 All rights reserved.
020
021 Redistribution and use in source and binary forms, with or without
022 modification, are permitted provided that the following conditions are met:
023
024 1. Redistributions of source code must retain the above copyright notice, this
025 list of conditions and the following disclaimer.
026 2. Redistributions in binary form must reproduce the above copyright notice,
027 this list of conditions and the following disclaimer in the documentation
028 and/or other materials provided with the distribution.
029
030 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
031 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
032 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
033 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
034 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
035 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
036 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
037 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
038 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
039 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
040
041 The views and conclusions contained in the software and documentation are those
042 of the authors and should not be interpreted as representing official policies,
043 either expressed or implied, of the FreeBSD Project.
044 */
045
046 /**
047 * A telephone number.
048 *
049 * <pre>
050 * VCard vcard = new VCard();
051 * TelephoneType tel = new TelephoneType("+1 123-555-6789");
052 * tel.addType(TelephoneTypeParameter.HOME);
053 * tel.setPref(2); //the second-most preferred
054 * vcard.addTelephoneNumber(tel);
055 * tel = new TelephoneType("+1 800-555-9876;ext=111");
056 * tel.addType(TelephoneTypeParameter.WORK);
057 * tel.setPref(1); //the most preferred
058 * vcard.addTelephoneNumber(tel);
059 * </pre>
060 *
061 * <p>
062 * vCard property name: TEL
063 * </p>
064 * <p>
065 * vCard versions: 2.1, 3.0, 4.0
066 * </p>
067 * @author Michael Angstadt
068 */
069 public class TelephoneType extends MultiValuedTypeParameterType<TelephoneTypeParameter> {
070 public static final String NAME = "TEL";
071
072 private String value;
073
074 public TelephoneType() {
075 this(null);
076 }
077
078 /**
079 * @param telNumber the telephone number
080 */
081 public TelephoneType(String telNumber) {
082 super(NAME);
083 this.value = telNumber;
084 }
085
086 /**
087 * Gets the telephone number.
088 * @return the telephone number
089 */
090 public String getValue() {
091 return value;
092 }
093
094 /**
095 * Sets the telephone number.
096 * @param value the telephone number
097 */
098 public void setValue(String value) {
099 this.value = value;
100 }
101
102 /**
103 * Gets all PID parameter values.
104 * <p>
105 * vCard versions: 4.0
106 * </p>
107 * @return the PID values or empty set if there are none
108 * @see VCardSubTypes#getPids
109 */
110 public List<Integer[]> getPids() {
111 return subTypes.getPids();
112 }
113
114 /**
115 * Adds a PID value.
116 * <p>
117 * vCard versions: 4.0
118 * </p>
119 * @param localId the local ID
120 * @param clientPidMapRef the ID used to reference the property's globally
121 * unique identifier in the CLIENTPIDMAP property.
122 * @see VCardSubTypes#addPid(int, int)
123 */
124 public void addPid(int localId, int clientPidMapRef) {
125 subTypes.addPid(localId, clientPidMapRef);
126 }
127
128 /**
129 * Removes all PID values.
130 * <p>
131 * vCard versions: 4.0
132 * </p>
133 * @see VCardSubTypes#removePids
134 */
135 public void removePids() {
136 subTypes.removePids();
137 }
138
139 /**
140 * Gets the preference value.
141 * <p>
142 * vCard versions: 4.0
143 * </p>
144 * @return the preference value or null if it doesn't exist
145 * @see VCardSubTypes#getPref
146 */
147 public Integer getPref() {
148 return subTypes.getPref();
149 }
150
151 /**
152 * Sets the preference value.
153 * <p>
154 * vCard versions: 4.0
155 * </p>
156 * @param pref the preference value or null to remove
157 * @see VCardSubTypes#setPref
158 */
159 public void setPref(Integer pref) {
160 subTypes.setPref(pref);
161 }
162
163 /**
164 * Gets the ALTID.
165 * <p>
166 * vCard versions: 4.0
167 * </p>
168 * @return the ALTID or null if it doesn't exist
169 * @see VCardSubTypes#getAltId
170 */
171 public String getAltId() {
172 return subTypes.getAltId();
173 }
174
175 /**
176 * Sets the ALTID.
177 * <p>
178 * vCard versions: 4.0
179 * </p>
180 * @param altId the ALTID or null to remove
181 * @see VCardSubTypes#setAltId
182 */
183 public void setAltId(String altId) {
184 subTypes.setAltId(altId);
185 }
186
187 @Override
188 protected TelephoneTypeParameter buildTypeObj(String type) {
189 TelephoneTypeParameter param = TelephoneTypeParameter.valueOf(type);
190 if (param == null) {
191 param = new TelephoneTypeParameter(type);
192 }
193 return param;
194 }
195
196 @Override
197 protected void doMarshalSubTypes(VCardSubTypes copy, VCardVersion version, List<String> warnings, CompatibilityMode compatibilityMode, VCard vcard) {
198 if (version == VCardVersion.V4_0) {
199 copy.setValue(ValueParameter.URI);
200 } else {
201 copy.setValue(null);
202 }
203
204 //replace "TYPE=pref" with "PREF=1"
205 if (version == VCardVersion.V4_0) {
206 if (getTypes().contains(TelephoneTypeParameter.PREF)) {
207 copy.removeType(TelephoneTypeParameter.PREF.getValue());
208 copy.setPref(1);
209 }
210 } else {
211 copy.setPref(null);
212
213 //find the TEL with the lowest PREF value in the vCard
214 TelephoneType mostPreferred = null;
215 for (TelephoneType tel : vcard.getTelephoneNumbers()) {
216 Integer pref = tel.getPref();
217 if (pref != null) {
218 if (mostPreferred == null || pref < mostPreferred.getPref()) {
219 mostPreferred = tel;
220 }
221 }
222 }
223 if (this == mostPreferred) {
224 copy.addType(TelephoneTypeParameter.PREF.getValue());
225 }
226 }
227 }
228
229 @Override
230 protected void doMarshalText(StringBuilder sb, VCardVersion version, List<String> warnings, CompatibilityMode compatibilityMode) {
231 String value = writeValue(version);
232 sb.append(VCardStringUtils.escape(value));
233 }
234
235 @Override
236 protected void doUnmarshalText(String value, VCardVersion version, List<String> warnings, CompatibilityMode compatibilityMode) {
237 value = VCardStringUtils.unescape(value.trim());
238 parseValue(value);
239 }
240
241 @Override
242 protected void doMarshalXml(XCardElement parent, List<String> warnings, CompatibilityMode compatibilityMode) {
243 String value = writeValue(parent.version());
244 parent.uri(value);
245 }
246
247 @Override
248 protected void doUnmarshalXml(XCardElement element, List<String> warnings, CompatibilityMode compatibilityMode) {
249 String value = element.get("text", "uri");
250 if (value != null) {
251 parseValue(value);
252 }
253 }
254
255 @Override
256 protected void doUnmarshalHtml(HCardElement element, List<String> warnings) {
257 List<String> types = element.types();
258 for (String type : types) {
259 subTypes.addType(type);
260 }
261
262 String tel = null;
263 String href = element.attr("href");
264 if (href.length() > 0) {
265 Pattern p = Pattern.compile("^tel:(.*?)$", Pattern.CASE_INSENSITIVE);
266 Matcher m = p.matcher(href);
267 if (m.find()) {
268 tel = m.group(1);
269 }
270 }
271 if (tel == null) {
272 tel = element.value();
273 }
274 setValue(tel);
275 }
276
277 private void parseValue(String value) {
278 if (value.matches("(?i)tel:.*")) {
279 //remove "tel:"
280 value = (value.length() > 4) ? value.substring(4) : "";
281 }
282 setValue(value);
283 }
284
285 private String writeValue(VCardVersion version) {
286 String value = this.value;
287 if (version == VCardVersion.V4_0) {
288 value = "tel:" + value;
289 }
290 return value;
291 }
292 }