1package im.conversations.android.xmpp.model.data;
2
3import com.google.common.collect.Collections2;
4import com.google.common.collect.Iterables;
5import im.conversations.android.annotation.XmlElement;
6import im.conversations.android.xmpp.model.Extension;
7import java.util.Collection;
8import java.util.Map;
9
10@XmlElement(name = "x")
11public class Data extends Extension {
12
13 private static final String FORM_TYPE = "FORM_TYPE";
14 private static final String FIELD_TYPE_HIDDEN = "hidden";
15 private static final String FORM_TYPE_SUBMIT = "submit";
16
17 public Data() {
18 super(Data.class);
19 }
20
21 public String getFormType() {
22 final var fields = this.getExtensions(Field.class);
23 final var formTypeField = Iterables.find(fields, f -> FORM_TYPE.equals(f.getFieldName()));
24 return Iterables.getFirst(formTypeField.getValues(), null);
25 }
26
27 public Collection<Field> getFields() {
28 return Collections2.filter(
29 this.getExtensions(Field.class), f -> !FORM_TYPE.equals(f.getFieldName()));
30 }
31
32 public Field getFieldByName(final String name) {
33 return Iterables.find(getFields(), f -> name.equals(f.getFieldName()), null);
34 }
35
36 private void addField(final String name, final Object value) {
37 addField(name, value, null);
38 }
39
40 private void addField(final String name, final Object value, final String type) {
41 if (value == null) {
42 throw new IllegalArgumentException("Null values are not supported on data fields");
43 }
44 final var field = this.addExtension(new Field());
45 field.setFieldName(name);
46 if (type != null) {
47 field.setType(type);
48 }
49 if (value instanceof Collection) {
50 for (final Object subValue : (Collection<?>) value) {
51 if (subValue instanceof String) {
52 final var valueExtension = field.addExtension(new Value());
53 valueExtension.setContent((String) subValue);
54 } else {
55 throw new IllegalArgumentException(
56 String.format(
57 "%s is not a supported field value",
58 subValue.getClass().getSimpleName()));
59 }
60 }
61 } else {
62 final var valueExtension = field.addExtension(new Value());
63 if (value instanceof String) {
64 valueExtension.setContent((String) value);
65 } else if (value instanceof Integer) {
66 valueExtension.setContent(String.valueOf(value));
67 } else if (value instanceof Boolean) {
68 valueExtension.setContent(Boolean.TRUE.equals(value) ? "1" : "0");
69 } else {
70 throw new IllegalArgumentException(
71 String.format(
72 "%s is not a supported field value",
73 value.getClass().getSimpleName()));
74 }
75 }
76 }
77
78 private void setFormType(final String formType) {
79 this.addField(FORM_TYPE, formType, FIELD_TYPE_HIDDEN);
80 }
81
82 public static Data of(final String formType, final Map<String, Object> values) {
83 final var data = new Data();
84 data.setType(FORM_TYPE_SUBMIT);
85 data.setFormType(formType);
86 for (final Map.Entry<String, Object> entry : values.entrySet()) {
87 data.addField(entry.getKey(), entry.getValue());
88 }
89 return data;
90 }
91
92 public Data submit(final Map<String, Object> values) {
93 final String formType = this.getFormType();
94 final var submit = new Data();
95 submit.setType(FORM_TYPE_SUBMIT);
96 if (formType != null) {
97 submit.setFormType(formType);
98 }
99 for (final Field existingField : this.getFields()) {
100 final var fieldName = existingField.getFieldName();
101 final Object submittedValue = values.get(fieldName);
102 if (submittedValue != null) {
103 submit.addField(fieldName, submittedValue);
104 } else {
105 submit.addField(fieldName, existingField.getValues());
106 }
107 }
108 return submit;
109 }
110
111 private void setType(final String type) {
112 this.setAttribute("type", type);
113 }
114}