1package eu.siacs.conversations.entities;
2
3import android.util.Pair;
4
5import java.util.ArrayList;
6import java.util.HashMap;
7import java.util.Hashtable;
8import java.util.List;
9import java.util.Map;
10
11public class Presences {
12 private final Hashtable<String, Presence> presences = new Hashtable<>();
13
14 private static String nameWithoutVersion(String name) {
15 String[] parts = name.split(" ");
16 if (parts.length > 1 && Character.isDigit(parts[parts.length - 1].charAt(0))) {
17 StringBuilder output = new StringBuilder();
18 for (int i = 0; i < parts.length - 1; ++i) {
19 if (output.length() != 0) {
20 output.append(' ');
21 }
22 output.append(parts[i]);
23 }
24 return output.toString();
25 } else {
26 return name;
27 }
28 }
29
30 public List<Presence> getPresences() {
31 synchronized (this.presences) {
32 return new ArrayList<>(this.presences.values());
33 }
34 }
35
36 public Map<String, Presence> getPresencesMap() {
37 synchronized (this.presences) {
38 return new HashMap<>(this.presences);
39 }
40 }
41
42 public Presence get(String resource) {
43 synchronized (this.presences) {
44 return this.presences.get(resource);
45 }
46 }
47
48 public void updatePresence(String resource, Presence presence) {
49 synchronized (this.presences) {
50 this.presences.put(resource, presence);
51 }
52 }
53
54 public void removePresence(String resource) {
55 synchronized (this.presences) {
56 this.presences.remove(resource);
57 }
58 }
59
60 public void clearPresences() {
61 synchronized (this.presences) {
62 this.presences.clear();
63 }
64 }
65
66 public Presence.Status getShownStatus() {
67 Presence.Status status = Presence.Status.OFFLINE;
68 synchronized (this.presences) {
69 for (Presence p : presences.values()) {
70 if (p.getStatus() == Presence.Status.DND) {
71 return p.getStatus();
72 } else if (p.getStatus().compareTo(status) < 0) {
73 status = p.getStatus();
74 }
75 }
76 }
77 return status;
78 }
79
80 public int size() {
81 synchronized (this.presences) {
82 return presences.size();
83 }
84 }
85
86 public String[] toResourceArray() {
87 synchronized (this.presences) {
88 final String[] presencesArray = new String[presences.size()];
89 presences.keySet().toArray(presencesArray);
90 return presencesArray;
91 }
92 }
93
94 public List<PresenceTemplate> asTemplates() {
95 synchronized (this.presences) {
96 ArrayList<PresenceTemplate> templates = new ArrayList<>(presences.size());
97 for (Presence p : presences.values()) {
98 if (p.getMessage() != null && !p.getMessage().trim().isEmpty()) {
99 templates.add(new PresenceTemplate(p.getStatus(), p.getMessage()));
100 }
101 }
102 return templates;
103 }
104 }
105
106 public boolean has(String presence) {
107 synchronized (this.presences) {
108 return presences.containsKey(presence);
109 }
110 }
111
112 public List<String> getStatusMessages() {
113 ArrayList<String> messages = new ArrayList<>();
114 synchronized (this.presences) {
115 for (Presence presence : this.presences.values()) {
116 String message = presence.getMessage() == null ? null : presence.getMessage().trim();
117 if (message != null && !message.isEmpty() && !messages.contains(message)) {
118 messages.add(message);
119 }
120 }
121 }
122 return messages;
123 }
124
125 public boolean allOrNonSupport(String namespace) {
126 synchronized (this.presences) {
127 for (Presence presence : this.presences.values()) {
128 ServiceDiscoveryResult disco = presence.getServiceDiscoveryResult();
129 if (disco == null || !disco.getFeatures().contains(namespace)) {
130 return false;
131 }
132 }
133 }
134 return true;
135 }
136
137 public boolean anySupport(final String namespace) {
138 synchronized (this.presences) {
139 if (this.presences.size() == 0) {
140 return true;
141 }
142 for (Presence presence : this.presences.values()) {
143 ServiceDiscoveryResult disco = presence.getServiceDiscoveryResult();
144 if (disco != null && disco.getFeatures().contains(namespace)) {
145 return true;
146 }
147 }
148 }
149 return false;
150 }
151
152 public String firstWhichSupport(final String namespace) {
153 for (Map.Entry<String, Presence> entry : this.presences.entrySet()) {
154 String resource = entry.getKey();
155 Presence presence = entry.getValue();
156 ServiceDiscoveryResult disco = presence.getServiceDiscoveryResult();
157 if (disco != null && disco.getFeatures().contains(namespace)) {
158 return resource;
159 }
160 }
161
162 return null;
163 }
164
165 public boolean anyIdentity(final String category, final String type) {
166 synchronized (this.presences) {
167 if (this.presences.size() == 0) {
168 // https://github.com/iNPUTmice/Conversations/issues/4230
169 return false;
170 }
171 for (Presence presence : this.presences.values()) {
172 ServiceDiscoveryResult disco = presence.getServiceDiscoveryResult();
173 if (disco != null && disco.hasIdentity(category, type)) {
174 return true;
175 }
176 }
177 }
178 return false;
179 }
180
181 public Pair<Map<String, String>, Map<String, String>> toTypeAndNameMap() {
182 Map<String, String> typeMap = new HashMap<>();
183 Map<String, String> nameMap = new HashMap<>();
184 synchronized (this.presences) {
185 for (Map.Entry<String, Presence> presenceEntry : this.presences.entrySet()) {
186 String resource = presenceEntry.getKey();
187 Presence presence = presenceEntry.getValue();
188 ServiceDiscoveryResult serviceDiscoveryResult = presence == null ? null : presence.getServiceDiscoveryResult();
189 if (serviceDiscoveryResult != null && serviceDiscoveryResult.getIdentities().size() > 0) {
190 ServiceDiscoveryResult.Identity identity = serviceDiscoveryResult.getIdentities().get(0);
191 String type = identity.getType();
192 String name = identity.getName();
193 if (type != null) {
194 typeMap.put(resource, type);
195 }
196 if (name != null) {
197 nameMap.put(resource, nameWithoutVersion(name));
198 }
199 }
200 }
201 }
202 return new Pair<>(typeMap, nameMap);
203 }
204}