Override Object.toString().
[Sone.git] / src / main / java / net / pterodactylus / sone / data / Sone.java
1 /*
2  * FreenetSone - Sone.java - Copyright © 2010 David Roden
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 package net.pterodactylus.sone.data;
19
20 import java.util.ArrayList;
21 import java.util.Collections;
22 import java.util.Comparator;
23 import java.util.HashSet;
24 import java.util.List;
25 import java.util.Set;
26 import java.util.UUID;
27
28 import freenet.keys.FreenetURI;
29
30 /**
31  * A Sone defines everything about a user: her profile, her status updates, her
32  * replies, her likes and dislikes, etc.
33  * <p>
34  * Operations that modify the Sone need to synchronize on the Sone in question.
35  *
36  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
37  */
38 public class Sone {
39
40         /** A GUID for this Sone. */
41         private final UUID id;
42
43         /** The name of this Sone. */
44         private final String name;
45
46         /** The URI under which the Sone is stored in Freenet. */
47         private FreenetURI requestUri;
48
49         /** The URI used to insert a new version of this Sone. */
50         /* This will be null for remote Sones! */
51         private FreenetURI insertUri;
52
53         /** The profile of this Sone. */
54         private Profile profile;
55
56         /** All friend Sones. */
57         private final Set<Sone> friendSones = new HashSet<Sone>();
58
59         /** All posts. */
60         private final List<Post> posts = new ArrayList<Post>();
61
62         /** All replies. */
63         private final Set<Reply> replies = new HashSet<Reply>();
64
65         /** Modification count. */
66         private volatile long modificationCounter = 0;
67
68         /**
69          * Creates a new Sone.
70          *
71          * @param id
72          *            The ID of this Sone
73          * @param name
74          *            The name of the Sone
75          * @param requestUri
76          *            The request URI of the Sone
77          */
78         public Sone(UUID id, String name, FreenetURI requestUri) {
79                 this(id, name, requestUri, null);
80         }
81
82         /**
83          * Creates a new Sone.
84          *
85          * @param id
86          *            The ID of this Sone
87          * @param name
88          *            The name of the Sone
89          * @param requestUri
90          *            The request URI of the Sone
91          * @param insertUri
92          *            The insert URI of the Sone
93          */
94         public Sone(UUID id, String name, FreenetURI requestUri, FreenetURI insertUri) {
95                 this.id = id;
96                 this.name = name;
97                 this.requestUri = requestUri;
98                 this.insertUri = insertUri;
99         }
100
101         //
102         // ACCESSORS
103         //
104
105         /**
106          * Returns the ID of this Sone.
107          *
108          * @return The ID of this Sone
109          */
110         public String getId() {
111                 return id.toString();
112         }
113
114         /**
115          * Returns the name of this Sone.
116          *
117          * @return The name of this Sone
118          */
119         public String getName() {
120                 return name;
121         }
122
123         /**
124          * Returns the request URI of this Sone.
125          *
126          * @return The request URI of this Sone
127          */
128         public FreenetURI getRequestUri() {
129                 return requestUri;
130         }
131
132         /**
133          * Returns the insert URI of this Sone.
134          *
135          * @return The insert URI of this Sone
136          */
137         public FreenetURI getInsertUri() {
138                 return insertUri;
139         }
140
141         /**
142          * Returns a copy of the profile. If you want to update values in the
143          * profile of this Sone, update the values in the returned {@link Profile}
144          * and use {@link #setProfile(Profile)} to change the profile in this Sone.
145          *
146          * @return A copy of the profile
147          */
148         public Profile getProfile() {
149                 return new Profile(profile);
150         }
151
152         /**
153          * Sets the profile of this Sone. A copy of the given profile is stored so
154          * that subsequent modifications of the given profile are not reflected in
155          * this Sone!
156          *
157          * @param profile
158          *            The profile to set
159          */
160         public synchronized void setProfile(Profile profile) {
161                 this.profile = new Profile(profile);
162                 modificationCounter++;
163         }
164
165         /**
166          * Returns all friend Sones of this Sone.
167          *
168          * @return The friend Sones of this Sone
169          */
170         public Set<Sone> getFriendSones() {
171                 return Collections.unmodifiableSet(friendSones);
172         }
173
174         /**
175          * Returns whether this Sone has the given Sone as a friend Sone.
176          *
177          * @param friendSone
178          *            The friend Sone to check for
179          * @return {@code true} if this Sone has the given Sone as a friend,
180          *         {@code false} otherwise
181          */
182         public boolean hasFriendSone(Sone friendSone) {
183                 return friendSones.contains(friendSone);
184         }
185
186         /**
187          * Adds the given Sone as a friend Sone.
188          *
189          * @param friendSone
190          *            The friend Sone to add
191          * @return This Sone (for method chaining)
192          */
193         public synchronized Sone addFriendSone(Sone friendSone) {
194                 if (friendSones.add(friendSone)) {
195                         modificationCounter++;
196                 }
197                 return this;
198         }
199
200         /**
201          * Removes the given Sone as a friend Sone.
202          *
203          * @param friendSone
204          *            The friend Sone to remove
205          * @return This Sone (for method chaining)
206          */
207         public synchronized Sone removeFriendSone(Sone friendSone) {
208                 if (friendSones.remove(friendSone)) {
209                         modificationCounter++;
210                 }
211                 return this;
212         }
213
214         /**
215          * Returns the list of posts of this Sone, sorted by time, newest first.
216          *
217          * @return All posts of this Sone
218          */
219         public List<Post> getPosts() {
220                 List<Post> sortedPosts = new ArrayList<Post>(posts);
221                 Collections.sort(sortedPosts, new Comparator<Post>() {
222
223                         @Override
224                         public int compare(Post leftPost, Post rightPost) {
225                                 return (int) Math.max(Integer.MIN_VALUE, Math.min(Integer.MAX_VALUE, rightPost.getTime() - leftPost.getTime()));
226                         }
227
228                 });
229                 return sortedPosts;
230         }
231
232         /**
233          * Adds the given post to this Sone. The post will not be added if its
234          * {@link Post#getSone() Sone} is not this Sone.
235          *
236          * @param post
237          *            The post to add
238          */
239         public synchronized void addPost(Post post) {
240                 if (post.getSone().equals(this) && posts.add(post)) {
241                         modificationCounter++;
242                 }
243         }
244
245         /**
246          * Removes the given post from this Sone.
247          *
248          * @param post
249          *            The post to remove
250          */
251         public synchronized void removePost(Post post) {
252                 if (post.getSone().equals(this) && posts.remove(post)) {
253                         modificationCounter++;
254                 }
255         }
256
257         /**
258          * Returns all replies this Sone made.
259          *
260          * @return All replies this Sone made
261          */
262         public Set<Reply> getReplies() {
263                 return Collections.unmodifiableSet(replies);
264         }
265
266         /**
267          * Adds a reply to this Sone. If the given reply was not made by this Sone,
268          * nothing is added to this Sone.
269          *
270          * @param reply
271          *            The reply to add
272          */
273         public synchronized void addReply(Reply reply) {
274                 if (reply.getSone().equals(this) && replies.add(reply)) {
275                         modificationCounter++;
276                 }
277         }
278
279         /**
280          * Removes a reply from this Sone.
281          *
282          * @param reply
283          *            The reply to remove
284          */
285         public synchronized void removeReply(Reply reply) {
286                 if (reply.getSone().equals(this) && replies.remove(reply)) {
287                         modificationCounter++;
288                 }
289         }
290
291         /**
292          * Returns the modification counter.
293          *
294          * @return The modification counter
295          */
296         public synchronized long getModificationCounter() {
297                 return modificationCounter;
298         }
299
300         /**
301          * Sets the modification counter.
302          *
303          * @param modificationCounter
304          *            The new modification counter
305          */
306         public synchronized void setModificationCounter(long modificationCounter) {
307                 this.modificationCounter = modificationCounter;
308         }
309
310         /**
311          * Updates the suggested edition in both the request URI and the insert URI.
312          *
313          * @param requestUri
314          *            The request URI that resulted from an insert
315          */
316         public void updateUris(FreenetURI requestUri) {
317                 /* TODO - check for the correct URI. */
318                 long latestEdition = requestUri.getSuggestedEdition();
319                 this.requestUri = this.requestUri.setSuggestedEdition(latestEdition);
320                 this.insertUri = this.insertUri.setSuggestedEdition(latestEdition);
321         }
322
323         //
324         // OBJECT METHODS
325         //
326
327         /**
328          * {@inheritDoc}
329          */
330         @Override
331         public int hashCode() {
332                 return id.hashCode();
333         }
334
335         /**
336          * {@inheritDoc}
337          */
338         @Override
339         public boolean equals(Object object) {
340                 if (!(object instanceof Sone)) {
341                         return false;
342                 }
343                 return ((Sone) object).id.equals(id);
344         }
345
346         /**
347          * {@inheritDoc}
348          */
349         @Override
350         public String toString() {
351                 return getName() + "[id=" + getId() + ",requestUri=" + getRequestUri() + ",insertUri=" + getInsertUri() + ",posts(" + posts.size() + "),replies(" + replies.size() + ")]";
352         }
353
354 }