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