Fix ALL the logging!
[Sone.git] / src / main / java / net / pterodactylus / sone / data / Sone.java
index be3a660..e5ebcf1 100644 (file)
@@ -21,9 +21,10 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CopyOnWriteArraySet;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -47,6 +48,50 @@ import freenet.keys.FreenetURI;
  */
 public class Sone implements Fingerprintable, Comparable<Sone> {
 
+       /**
+        * Enumeration for the possible states of a {@link Sone}.
+        *
+        * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+        */
+       public enum SoneStatus {
+
+               /** The Sone is unknown, i.e. not yet downloaded. */
+               unknown,
+
+               /** The Sone is idle, i.e. not being downloaded or inserted. */
+               idle,
+
+               /** The Sone is currently being inserted. */
+               inserting,
+
+               /** The Sone is currently being downloaded. */
+               downloading,
+       }
+
+       /**
+        * The possible values for the “show custom avatars” option.
+        *
+        * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+        */
+       public static enum ShowCustomAvatars {
+
+               /** Never show custom avatars. */
+               NEVER,
+
+               /** Only show custom avatars of followed Sones. */
+               FOLLOWED,
+
+               /** Only show custom avatars of Sones you manually trust. */
+               MANUALLY_TRUSTED,
+
+               /** Only show custom avatars of automatically trusted Sones. */
+               TRUSTED,
+
+               /** Always show custom avatars. */
+               ALWAYS,
+
+       }
+
        /** comparator that sorts Sones by their nice name. */
        public static final Comparator<Sone> NICE_NAME_COMPARATOR = new Comparator<Sone>() {
 
@@ -84,6 +129,18 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
                }
        };
 
+       /** Comparator that sorts Sones by number of images (descending). */
+       public static final Comparator<Sone> IMAGE_COUNT_COMPARATOR = new Comparator<Sone>() {
+
+               /**
+                * {@inheritDoc}
+                */
+               @Override
+               public int compare(Sone leftSone, Sone rightSone) {
+                       return rightSone.getAllImages().size() - leftSone.getAllImages().size();
+               }
+       };
+
        /** Filter to remove Sones that have not been downloaded. */
        public static final Filter<Sone> EMPTY_SONE_FILTER = new Filter<Sone>() {
 
@@ -103,6 +160,15 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
 
        };
 
+       /** Filter that matches Sones that have at least one album. */
+       public static final Filter<Sone> HAS_ALBUM_FILTER = new Filter<Sone>() {
+
+               @Override
+               public boolean filterObject(Sone sone) {
+                       return !sone.getAlbums().isEmpty();
+               }
+       };
+
        /** The logger. */
        private static final Logger logger = Logging.getLogger(Sone.class);
 
@@ -125,29 +191,35 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
        /** The time of the last inserted update. */
        private volatile long time;
 
+       /** The status of this Sone. */
+       private volatile SoneStatus status = SoneStatus.unknown;
+
        /** The profile of this Sone. */
-       private volatile Profile profile = new Profile();
+       private volatile Profile profile = new Profile(this);
 
        /** The client used by the Sone. */
        private volatile Client client;
 
+       /** Whether this Sone is known. */
+       private volatile boolean known;
+
        /** All friend Sones. */
-       private final Set<String> friendSones = Collections.synchronizedSet(new HashSet<String>());
+       private final Set<String> friendSones = new CopyOnWriteArraySet<String>();
 
        /** All posts. */
-       private final Set<Post> posts = Collections.synchronizedSet(new HashSet<Post>());
+       private final Set<Post> posts = new CopyOnWriteArraySet<Post>();
 
        /** All replies. */
-       private final Set<Reply> replies = Collections.synchronizedSet(new HashSet<Reply>());
+       private final Set<PostReply> replies = new CopyOnWriteArraySet<PostReply>();
 
        /** The IDs of all liked posts. */
-       private final Set<String> likedPostIds = Collections.synchronizedSet(new HashSet<String>());
+       private final Set<String> likedPostIds = new CopyOnWriteArraySet<String>();
 
        /** The IDs of all liked replies. */
-       private final Set<String> likedReplyIds = Collections.synchronizedSet(new HashSet<String>());
+       private final Set<String> likedReplyIds = new CopyOnWriteArraySet<String>();
 
        /** The albums of this Sone. */
-       private final List<Album> albums = Collections.synchronizedList(new ArrayList<Album>());
+       private final List<Album> albums = new CopyOnWriteArrayList<Album>();
 
        /** Sone-specific options. */
        private final Options options = new Options();
@@ -233,7 +305,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
                        return this;
                }
                if (!this.requestUri.equalsKeypair(requestUri)) {
-                       logger.log(Level.WARNING, "Request URI %s tried to overwrite %s!", new Object[] { requestUri, this.requestUri });
+                       logger.log(Level.WARNING, String.format("Request URI %s tried to overwrite %s!", requestUri, this.requestUri));
                        return this;
                }
                return this;
@@ -261,7 +333,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
                        return this;
                }
                if (!this.insertUri.equalsKeypair(insertUri)) {
-                       logger.log(Level.WARNING, "Request URI %s tried to overwrite %s!", new Object[] { insertUri, this.insertUri });
+                       logger.log(Level.WARNING, String.format("Request URI %s tried to overwrite %s!", insertUri, this.insertUri));
                        return this;
                }
                return this;
@@ -286,7 +358,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         */
        public void setLatestEdition(long latestEdition) {
                if (!(latestEdition > this.latestEdition)) {
-                       logger.log(Level.FINE, "New latest edition %d is not greater than current latest edition %d!", new Object[] { latestEdition, this.latestEdition });
+                       logger.log(Level.FINE, String.format("New latest edition %d is not greater than current latest edition %d!", latestEdition, this.latestEdition));
                        return;
                }
                this.latestEdition = latestEdition;
@@ -314,13 +386,37 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
        }
 
        /**
+        * Returns the status of this Sone.
+        *
+        * @return The status of this Sone
+        */
+       public SoneStatus getStatus() {
+               return status;
+       }
+
+       /**
+        * Sets the new status of this Sone.
+        *
+        * @param status
+        *            The new status of this Sone
+        * @return This Sone
+        * @throws IllegalArgumentException
+        *             if {@code status} is {@code null}
+        */
+       public Sone setStatus(SoneStatus status) {
+               Validation.begin().isNotNull("Sone Status", status).check();
+               this.status = status;
+               return this;
+       }
+
+       /**
         * Returns a copy of the profile. If you want to update values in the
         * profile of this Sone, update the values in the returned {@link Profile}
         * and use {@link #setProfile(Profile)} to change the profile in this Sone.
         *
         * @return A copy of the profile
         */
-       public synchronized Profile getProfile() {
+       public Profile getProfile() {
                return new Profile(profile);
        }
 
@@ -332,7 +428,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         * @param profile
         *            The profile to set
         */
-       public synchronized void setProfile(Profile profile) {
+       public void setProfile(Profile profile) {
                this.profile = new Profile(profile);
        }
 
@@ -358,29 +454,37 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
        }
 
        /**
-        * Returns all friend Sones of this Sone.
+        * Returns whether this Sone is known.
         *
-        * @return The friend Sones of this Sone
+        * @return {@code true} if this Sone is known, {@code false} otherwise
         */
-       public List<String> getFriends() {
-               List<String> friends = new ArrayList<String>(friendSones);
-               return friends;
+       public boolean isKnown() {
+               return known;
        }
 
        /**
-        * Sets all friends of this Sone at once.
+        * Sets whether this Sone is known.
         *
-        * @param friends
-        *            The new (and only) friends of this Sone
-        * @return This Sone (for method chaining)
+        * @param known
+        *            {@code true} if this Sone is known, {@code false} otherwise
+        * @return This Sone
         */
-       public Sone setFriends(Collection<String> friends) {
-               friendSones.clear();
-               friendSones.addAll(friends);
+       public Sone setKnown(boolean known) {
+               this.known = known;
                return this;
        }
 
        /**
+        * Returns all friend Sones of this Sone.
+        *
+        * @return The friend Sones of this Sone
+        */
+       public List<String> getFriends() {
+               List<String> friends = new ArrayList<String>(friendSones);
+               return friends;
+       }
+
+       /**
         * Returns whether this Sone has the given Sone as a friend Sone.
         *
         * @param friendSoneId
@@ -439,7 +543,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         *            The new (and only) posts of this Sone
         * @return This Sone (for method chaining)
         */
-       public synchronized Sone setPosts(Collection<Post> posts) {
+       public Sone setPosts(Collection<Post> posts) {
                synchronized (this) {
                        this.posts.clear();
                        this.posts.addAll(posts);
@@ -454,9 +558,9 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         * @param post
         *            The post to add
         */
-       public synchronized void addPost(Post post) {
+       public void addPost(Post post) {
                if (post.getSone().equals(this) && posts.add(post)) {
-                       logger.log(Level.FINEST, "Adding %s to “%s”.", new Object[] { post, getName() });
+                       logger.log(Level.FINEST, String.format("Adding %s to “%s”.", post, getName()));
                }
        }
 
@@ -466,7 +570,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         * @param post
         *            The post to remove
         */
-       public synchronized void removePost(Post post) {
+       public void removePost(Post post) {
                if (post.getSone().equals(this)) {
                        posts.remove(post);
                }
@@ -477,7 +581,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         *
         * @return All replies this Sone made
         */
-       public synchronized Set<Reply> getReplies() {
+       public Set<PostReply> getReplies() {
                return Collections.unmodifiableSet(replies);
        }
 
@@ -488,7 +592,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         *            The new (and only) replies of this Sone
         * @return This Sone (for method chaining)
         */
-       public synchronized Sone setReplies(Collection<Reply> replies) {
+       public Sone setReplies(Collection<PostReply> replies) {
                this.replies.clear();
                this.replies.addAll(replies);
                return this;
@@ -501,7 +605,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         * @param reply
         *            The reply to add
         */
-       public synchronized void addReply(Reply reply) {
+       public void addReply(PostReply reply) {
                if (reply.getSone().equals(this)) {
                        replies.add(reply);
                }
@@ -513,7 +617,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         * @param reply
         *            The reply to remove
         */
-       public synchronized void removeReply(Reply reply) {
+       public void removeReply(PostReply reply) {
                if (reply.getSone().equals(this)) {
                        replies.remove(reply);
                }
@@ -535,7 +639,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         *            All liked posts’ IDs
         * @return This Sone (for method chaining)
         */
-       public synchronized Sone setLikePostIds(Set<String> likedPostIds) {
+       public Sone setLikePostIds(Set<String> likedPostIds) {
                this.likedPostIds.clear();
                this.likedPostIds.addAll(likedPostIds);
                return this;
@@ -560,7 +664,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         *            The ID of the post
         * @return This Sone (for method chaining)
         */
-       public synchronized Sone addLikedPostId(String postId) {
+       public Sone addLikedPostId(String postId) {
                likedPostIds.add(postId);
                return this;
        }
@@ -572,7 +676,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         *            The ID of the post
         * @return This Sone (for method chaining)
         */
-       public synchronized Sone removeLikedPostId(String postId) {
+       public Sone removeLikedPostId(String postId) {
                likedPostIds.remove(postId);
                return this;
        }
@@ -593,7 +697,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         *            All liked replies’ IDs
         * @return This Sone (for method chaining)
         */
-       public synchronized Sone setLikeReplyIds(Set<String> likedReplyIds) {
+       public Sone setLikeReplyIds(Set<String> likedReplyIds) {
                this.likedReplyIds.clear();
                this.likedReplyIds.addAll(likedReplyIds);
                return this;
@@ -618,7 +722,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         *            The ID of the reply
         * @return This Sone (for method chaining)
         */
-       public synchronized Sone addLikedReplyId(String replyId) {
+       public Sone addLikedReplyId(String replyId) {
                likedReplyIds.add(replyId);
                return this;
        }
@@ -630,7 +734,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         *            The ID of the reply
         * @return This Sone (for method chaining)
         */
-       public synchronized Sone removeLikedReplyId(String replyId) {
+       public Sone removeLikedReplyId(String replyId) {
                likedReplyIds.remove(replyId);
                return this;
        }
@@ -685,7 +789,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         * @param album
         *            The album to add
         */
-       public synchronized void addAlbum(Album album) {
+       public void addAlbum(Album album) {
                Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.getSone(), this).check();
                albums.add(album);
        }
@@ -696,7 +800,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         * @param albums
         *            The albums of this Sone
         */
-       public synchronized void setAlbums(Collection<? extends Album> albums) {
+       public void setAlbums(Collection<? extends Album> albums) {
                Validation.begin().isNotNull("Albums", albums).check();
                this.albums.clear();
                for (Album album : albums) {
@@ -710,7 +814,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         * @param album
         *            The album to remove
         */
-       public synchronized void removeAlbum(Album album) {
+       public void removeAlbum(Album album) {
                Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.getSone(), this).check();
                albums.remove(album);
        }
@@ -782,10 +886,10 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
                }
                fingerprint.append(")");
 
-               List<Reply> replies = new ArrayList<Reply>(getReplies());
+               List<PostReply> replies = new ArrayList<PostReply>(getReplies());
                Collections.sort(replies, Reply.TIME_COMPARATOR);
                fingerprint.append("Replies(");
-               for (Reply reply : replies) {
+               for (PostReply reply : replies) {
                        fingerprint.append("Reply(").append(reply.getId()).append(')');
                }
                fingerprint.append(')');