001 package ezvcard.io.json;
002
003 import java.util.ArrayList;
004 import java.util.Arrays;
005 import java.util.Collections;
006 import java.util.List;
007
008 import ezvcard.property.Categories;
009 import ezvcard.property.Note;
010 import ezvcard.property.StructuredName;
011
012 /*
013 Copyright (c) 2013, Michael Angstadt
014 All rights reserved.
015
016 Redistribution and use in source and binary forms, with or without
017 modification, are permitted provided that the following conditions are met:
018
019 1. Redistributions of source code must retain the above copyright notice, this
020 list of conditions and the following disclaimer.
021 2. Redistributions in binary form must reproduce the above copyright notice,
022 this list of conditions and the following disclaimer in the documentation
023 and/or other materials provided with the distribution.
024
025 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
026 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
027 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
028 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
029 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
030 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
031 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
032 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
033 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
034 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
035
036 The views and conclusions contained in the software and documentation are those
037 of the authors and should not be interpreted as representing official policies,
038 either expressed or implied, of the FreeBSD Project.
039 */
040
041 /**
042 * Holds the data type and value of a jCard property.
043 * @author Michael Angstadt
044 */
045 public class JCardValue {
046 private final List<JsonValue> values;
047
048 /**
049 * Creates a new jCard value.
050 * @param values the values
051 */
052 public JCardValue(List<JsonValue> values) {
053 this.values = Collections.unmodifiableList(values);
054 }
055
056 /**
057 * Creates a new jCard value.
058 * @param values the values
059 */
060 public JCardValue(JsonValue... values) {
061 this.values = Arrays.asList(values); //unmodifiable
062 }
063
064 /**
065 * Creates a single-valued value.
066 * @param value the value
067 * @return the jCard value
068 */
069 public static JCardValue single(Object value) {
070 return new JCardValue(new JsonValue(value));
071 }
072
073 /**
074 * Creates a multi-valued value.
075 * @param values the values
076 * @return the jCard value
077 */
078 public static JCardValue multi(Object... values) {
079 return multi(Arrays.asList(values));
080 }
081
082 /**
083 * Creates a multi-valued value.
084 * @param values the values
085 * @return the jCard value
086 */
087 public static JCardValue multi(List<?> values) {
088 List<JsonValue> multiValues = new ArrayList<JsonValue>(values.size());
089 for (Object value : values) {
090 multiValues.add(new JsonValue(value));
091 }
092 return new JCardValue(multiValues);
093 }
094
095 /**
096 * <p>
097 * Creates a structured value.
098 * </p>
099 * <p>
100 * This method accepts a vararg of {@link Object} instances. {@link List}
101 * objects will be treated as multi-valued components. Null objects will be
102 * treated as empty components.
103 * </p>
104 * @param values the values
105 * @return the jCard value
106 */
107 public static JCardValue structured(Object... values) {
108 List<List<?>> valuesList = new ArrayList<List<?>>(values.length);
109 for (Object value : values) {
110 List<?> list = (value instanceof List) ? (List<?>) value : Arrays.asList(value);
111 valuesList.add(list);
112 }
113 return structured(valuesList);
114 }
115
116 /**
117 * Creates a structured value.
118 * @param values the values
119 * @return the jCard value
120 */
121 public static JCardValue structured(List<List<?>> values) {
122 List<JsonValue> array = new ArrayList<JsonValue>(values.size());
123
124 for (List<?> list : values) {
125 if (list.isEmpty()) {
126 array.add(new JsonValue(""));
127 continue;
128 }
129
130 if (list.size() == 1) {
131 Object value = list.get(0);
132 if (value == null) {
133 value = "";
134 }
135 array.add(new JsonValue(value));
136 continue;
137 }
138
139 List<JsonValue> subArray = new ArrayList<JsonValue>(list.size());
140 for (Object value : list) {
141 if (value == null) {
142 value = "";
143 }
144 subArray.add(new JsonValue(value));
145 }
146 array.add(new JsonValue(subArray));
147 }
148
149 return new JCardValue(new JsonValue(array));
150 }
151
152 /**
153 * Gets all the JSON values.
154 * @return the JSON values
155 */
156 public List<JsonValue> getValues() {
157 return values;
158 }
159
160 /**
161 * Gets the value of a single-valued property (such as {@link Note}).
162 * @return the value or empty string if not found
163 */
164 public String asSingle() {
165 if (values.isEmpty()) {
166 return "";
167 }
168
169 JsonValue first = values.get(0);
170 if (first.isNull()) {
171 return "";
172 }
173
174 Object obj = first.getValue();
175 if (obj != null) {
176 return obj.toString();
177 }
178
179 //get the first element of the array
180 List<JsonValue> array = first.getArray();
181 if (array != null && !array.isEmpty()) {
182 obj = array.get(0).getValue();
183 if (obj != null) {
184 return obj.toString();
185 }
186 }
187
188 return "";
189 }
190
191 /**
192 * Gets the value of a structured property (such as
193 * {@link StructuredName}).
194 * @return the values or empty list if not found
195 */
196 public List<List<String>> asStructured() {
197 if (values.isEmpty()) {
198 return Collections.emptyList();
199 }
200
201 JsonValue first = values.get(0);
202
203 //["gender", {}, "text", ["M", "text"] ]
204 List<JsonValue> array = first.getArray();
205 if (array != null) {
206 List<List<String>> valuesStr = new ArrayList<List<String>>(array.size());
207 for (JsonValue value : array) {
208 if (value.isNull()) {
209 valuesStr.add(Arrays.asList(""));
210 continue;
211 }
212
213 Object obj = value.getValue();
214 if (obj != null) {
215 valuesStr.add(Arrays.asList(obj.toString()));
216 continue;
217 }
218
219 List<JsonValue> subArray = value.getArray();
220 if (subArray != null) {
221 List<String> subValuesStr = new ArrayList<String>(subArray.size());
222 for (JsonValue subArrayValue : subArray) {
223 if (subArrayValue.isNull()) {
224 subValuesStr.add("");
225 continue;
226 }
227
228 obj = subArrayValue.getValue();
229 if (obj != null) {
230 subValuesStr.add(obj.toString());
231 continue;
232 }
233 }
234 valuesStr.add(subValuesStr);
235 }
236 }
237 return valuesStr;
238 }
239
240 //get the first value if it's not enclosed in an array
241 //["gender", {}, "text", "M"]
242 Object obj = first.getValue();
243 if (obj != null) {
244 List<List<String>> values = new ArrayList<List<String>>(1);
245 values.add(Arrays.asList(obj.toString()));
246 return values;
247 }
248
249 //["gender", {}, "text", null]
250 if (first.isNull()) {
251 List<List<String>> values = new ArrayList<List<String>>(1);
252 values.add(Arrays.asList(""));
253 return values;
254 }
255
256 return Collections.emptyList();
257 }
258
259 /**
260 * Gets the value of a multi-valued property (such as {@link Categories}
261 * ).
262 * @return the values or empty list if not found
263 */
264 public List<String> asMulti() {
265 if (values.isEmpty()) {
266 return Collections.emptyList();
267 }
268
269 List<String> multi = new ArrayList<String>(values.size());
270 for (JsonValue value : values) {
271 if (value.isNull()) {
272 multi.add("");
273 continue;
274 }
275
276 Object obj = value.getValue();
277 if (obj != null) {
278 multi.add(obj.toString());
279 continue;
280 }
281 }
282 return multi;
283 }
284 }