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 public String getValue(final String name) {
37 final var field = getFieldByName(name);
38 return field == null ? null : field.getValue();
39 }
40
41 private void addField(final String name, final Object value) {
42 addField(name, value, null);
43 }
44
45 private void addField(final String name, final Object value, final String type) {
46 if (value == null) {
47 throw new IllegalArgumentException("Null values are not supported on data fields");
48 }
49 final var field = this.addExtension(new Field());
50 field.setFieldName(name);
51 if (type != null) {
52 field.setType(type);
53 }
54 if (value instanceof Collection) {
55 for (final Object subValue : (Collection<?>) value) {
56 if (subValue instanceof String) {
57 final var valueExtension = field.addExtension(new Value());
58 valueExtension.setContent((String) subValue);
59 } else {
60 throw new IllegalArgumentException(
61 String.format(
62 "%s is not a supported field value",
63 subValue.getClass().getSimpleName()));
64 }
65 }
66 } else {
67 final var valueExtension = field.addExtension(new Value());
68 if (value instanceof String) {
69 valueExtension.setContent((String) value);
70 } else if (value instanceof Integer) {
71 valueExtension.setContent(String.valueOf(value));
72 } else if (value instanceof Boolean) {
73 valueExtension.setContent(Boolean.TRUE.equals(value) ? "1" : "0");
74 } else {
75 throw new IllegalArgumentException(
76 String.format(
77 "%s is not a supported field value",
78 value.getClass().getSimpleName()));
79 }
80 }
81 }
82
83 private void setFormType(final String formType) {
84 this.addField(FORM_TYPE, formType, FIELD_TYPE_HIDDEN);
85 }
86
87 public static Data of(final String formType, final Map<String, Object> values) {
88 final var data = new Data();
89 data.setType(FORM_TYPE_SUBMIT);
90 data.setFormType(formType);
91 for (final Map.Entry<String, Object> entry : values.entrySet()) {
92 data.addField(entry.getKey(), entry.getValue());
93 }
94 return data;
95 }
96
97 public Data submit(final Map<String, Object> values) {
98 final String formType = this.getFormType();
99 final var submit = new Data();
100 submit.setType(FORM_TYPE_SUBMIT);
101 if (formType != null) {
102 submit.setFormType(formType);
103 }
104 for (final Field existingField : this.getFields()) {
105 final var fieldName = existingField.getFieldName();
106 final Object submittedValue = values.get(fieldName);
107 if (submittedValue != null) {
108 submit.addField(fieldName, submittedValue);
109 } else {
110 submit.addField(fieldName, existingField.getValues());
111 }
112 }
113 return submit;
114 }
115
116 private void setType(final String type) {
117 this.setAttribute("type", type);
118 }
119}