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