jDoc, possible leak on crash, new depth option
[jvcard.git] / src / be / nikiroo / jvcard / Data.java
1 package be.nikiroo.jvcard;
2
3 import java.security.InvalidParameterException;
4 import java.util.LinkedList;
5 import java.util.List;
6
7 /**
8 * A {@link Data} is a piece of information present in a {@link Contact}. It is
9 * basically a key/value pair with optional types and an optional group name.
10 * <p>
11 * A {@link Data} can also be binary encoded: in this case, it has an associated
12 * BKey number to identify it.
13 *
14 * @author niki
15 */
16 public class Data extends BaseClass<TypeInfo> {
17 public enum DataPart {
18 FN_FAMILY, FN_GIVEN, FN_ADDITIONAL, // Name
19 FN_PRE, FN_POST, // Pre/Post
20 BDAY_YYYY, BDAY_MM, BDAY_DD, // BDay
21 // Address:
22 ADR_PBOX, ADR_EXTENDED, ADR_STREET, ADR_CITY, ADR_REGION, ADR_POSTAL_CODE, ADR_COUNTRY
23 }
24
25 private String name;
26 private String value;
27 private String group;
28 private int b64; // -1 = no, 0 = still not ordered, the rest is order
29
30 /**
31 * Create a new {@link Data} with the given values.
32 *
33 * @param types
34 * the types of this {@link Data}
35 * @param name
36 * its name (<b>MUST NOT</b> be NULL)
37 * @param value
38 * its value (<b>MUST NOT</b> be NULL)
39 * @param group
40 * its group if any (or NULL if none)
41 */
42 public Data(List<TypeInfo> types, String name, String value, String group) {
43 super(types);
44
45 this.name = name.toUpperCase();
46 this.value = value.toString(); // crash NOW if null
47 this.group = group;
48
49 b64 = -1;
50 for (TypeInfo type : this) {
51 if (type.getName().equals("ENCODING")
52 && type.getValue().equals("b")) {
53 b64 = 0;
54 break;
55 }
56 }
57 }
58
59 /**
60 * Return the name of this {@link Data}
61 *
62 * @return the name
63 */
64 public String getName() {
65 return name;
66 }
67
68 /**
69 * Return the value of this {@link Data}
70 *
71 * @return the value
72 */
73 public String getValue() {
74 return unescape(value);
75 }
76
77 /**
78 * Change the value of this {@link Data}
79 *
80 * @param value
81 * the new value
82 */
83 public void setValue(String value) {
84 setRawValue(escape(value));
85 }
86
87 /**
88 * Return the raw value of this {@link Data}
89 *
90 * @return the raw value
91 */
92 public String getRawValue() {
93 return value;
94 }
95
96 /**
97 * Change the raw value of this {@link Data}
98 *
99 * @param value
100 * the new raw value
101 */
102 public void setRawValue(String value) {
103 if ((value == null && this.value != null)
104 || (value != null && !value.equals(this.value))) {
105 this.value = value;
106 setDirty();
107 }
108 }
109
110 /**
111 * Return the {@link List} of comma-listed values from this {@link Data}.
112 *
113 * @return the {@link List} of values
114 */
115 public List<String> getValues() {
116 return getList(',');
117 }
118
119 /**
120 * Set the {@link List} of comma-listed values from this {@link Data}.
121 *
122 * @param values
123 * the {@link List} of values
124 */
125 public void setValues(List<String> values) {
126 setList(values, ',');
127 }
128
129 /**
130 * Return the {@link List} of semi-column-listed fields from this
131 * {@link Data}.
132 *
133 * @return the {@link List} of values
134 */
135 public List<String> getFields() {
136 return getList(';');
137 }
138
139 /**
140 * Set the {@link List} of comma-listed values from this {@link Data}.
141 *
142 * @param values
143 * the {@link List} of values
144 */
145 public void setFields(List<String> values) {
146 setList(values, ';');
147 }
148
149 /**
150 * Return the group of this {@link Data}
151 *
152 * @return the group
153 */
154 public String getGroup() {
155 return group;
156 }
157
158 /**
159 * Change the group of this {@link Data}
160 *
161 * @param group
162 * the new group
163 */
164 public void setGroup(String group) {
165 if ((group == null && this.group != null)
166 || (group != null && !group.equals(this.group))) {
167 this.group = group;
168 setDirty();
169 }
170 }
171
172 /**
173 * Return the bkey number of this {@link Data} or -1 if it is not binary.
174 * <p>
175 * For binary data, as long as the BKey is not processed, it will be 0.
176 *
177 * @return the bkey, 0 or -1
178 */
179 public int getB64Key() {
180 return b64;
181 }
182
183 /**
184 * Check if this {@link Data} is binary (in this case, the BKey will be
185 * present).
186 *
187 * @return TRUE if it is
188 */
189 public boolean isBinary() {
190 return b64 >= 0;
191 }
192
193 /**
194 * Return the preferred value of this {@link Data}, or
195 * {@link Integer#MAX_VALUE} if none.
196 *
197 * @return the preferred value
198 */
199 public int getPreferred() {
200 for (TypeInfo type : this) {
201 if (type.getName().equals("PRE")) {
202 try {
203 return Integer.parseInt(type.getValue());
204 } catch (NumberFormatException e) {
205 e.printStackTrace();
206 }
207 }
208 }
209
210 return Integer.MAX_VALUE;
211 }
212
213 /**
214 * Change the bkey of this {@link Data}
215 *
216 * @param i
217 * the new bkey
218 *
219 * @throw InvalidParameterException if the {@link Data} is not binary or if
220 * it is but you try to set a negative bkey
221 */
222 void resetB64Key(int i) {
223 if (!isBinary())
224 throw new InvalidParameterException(
225 "Cannot add a BKey on a non-binary object");
226 if (i < 0)
227 throw new InvalidParameterException(
228 "Cannot remove the BKey on a binary object");
229
230 b64 = i;
231 }
232
233 /**
234 * Return the {@link List} of sep-listed values from this {@link String}
235 * data.
236 * <p>
237 * Will take the backslash character into account (i.e., a backslash can
238 * escape the given separator).
239 *
240 * @param value
241 * the data
242 *
243 * @param the
244 * separator
245 *
246 * @return the {@link List} of values
247 */
248 private List<String> getList(char sep) {
249 List<String> rep = new LinkedList<String>();
250
251 if (value != null && value.length() > 0) {
252 int last = 0;
253 for (int i = 0; i < value.length(); i++) {
254 if (value.charAt(i) == sep
255 && (i == 0 || value.charAt(i - 1) != '\\')) {
256 rep.add(value.substring(last, i));
257 last = i + 1;
258 }
259 }
260
261 if (last < value.length())
262 rep.add(value.substring(last));
263 }
264
265 return rep;
266 }
267
268 /**
269 * Create the {@link String}-encoded {@link List} of sep-listed values from
270 * the given values.
271 *
272 * @param values
273 * the {@link List} of values
274 *
275 * @param sep
276 * the separator
277 *
278 * @return the {@link String}
279 */
280 private void setList(List<String> values, char sep) {
281 StringBuilder builder = new StringBuilder();
282 boolean first = true;
283 for (String value : values) {
284 if (!first)
285 builder.append(sep);
286
287 builder.append(escape(value));
288
289 first = false;
290 }
291
292 value = builder.toString();
293 }
294
295 @Override
296 public String getId() {
297 return "" + name;
298 }
299
300 @Override
301 public String getState() {
302 return ("" + name + value + group).replace(' ', '_');
303 }
304
305 @Override
306 public String toString() {
307 String out = name + ": " + value;
308 if (group != null && !group.isEmpty()) {
309 out += " (" + group + ")";
310 }
311 if (b64 >= 0) {
312 out += " [" + b64 + "]";
313 }
314
315 return out;
316 }
317 }