Merge branch 'next' into dev/image
[Sone.git] / src / main / java / net / pterodactylus / sone / data / Sone.java
index 715d95b..b8db269 100644 (file)
@@ -27,11 +27,14 @@ import java.util.Set;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import net.pterodactylus.sone.core.Core;
 import net.pterodactylus.sone.core.Options;
 import net.pterodactylus.sone.freenet.wot.Identity;
+import net.pterodactylus.sone.freenet.wot.OwnIdentity;
 import net.pterodactylus.sone.template.SoneAccessor;
 import net.pterodactylus.util.filter.Filter;
 import net.pterodactylus.util.logging.Logging;
+import net.pterodactylus.util.validation.Validation;
 import freenet.keys.FreenetURI;
 
 /**
@@ -58,6 +61,29 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
 
        };
 
+       /**
+        * Comparator that sorts Sones by last activity (least recent active first).
+        */
+       public static final Comparator<Sone> LAST_ACTIVITY_COMPARATOR = new Comparator<Sone>() {
+
+               @Override
+               public int compare(Sone firstSone, Sone secondSone) {
+                       return (int) Math.min(Integer.MAX_VALUE, Math.max(Integer.MIN_VALUE, secondSone.getTime() - firstSone.getTime()));
+               }
+       };
+
+       /** Comparator that sorts Sones by numbers of posts (descending). */
+       public static final Comparator<Sone> POST_COUNT_COMPARATOR = new Comparator<Sone>() {
+
+               /**
+                * {@inheritDoc}
+                */
+               @Override
+               public int compare(Sone leftSone, Sone rightSone) {
+                       return (leftSone.getPosts().size() != rightSone.getPosts().size()) ? (rightSone.getPosts().size() - leftSone.getPosts().size()) : (rightSone.getReplies().size() - leftSone.getReplies().size());
+               }
+       };
+
        /** Filter to remove Sones that have not been downloaded. */
        public static final Filter<Sone> EMPTY_SONE_FILTER = new Filter<Sone>() {
 
@@ -67,6 +93,16 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
                }
        };
 
+       /** Filter that matches all {@link Core#isLocalSone(Sone) local Sones}. */
+       public static final Filter<Sone> LOCAL_SONE_FILTER = new Filter<Sone>() {
+
+               @Override
+               public boolean filterObject(Sone sone) {
+                       return sone.getIdentity() instanceof OwnIdentity;
+               }
+
+       };
+
        /** The logger. */
        private static final Logger logger = Logging.getLogger(Sone.class);
 
@@ -110,6 +146,9 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
        /** The IDs of all liked replies. */
        private final Set<String> likedReplyIds = Collections.synchronizedSet(new HashSet<String>());
 
+       /** The albums of this Sone. */
+       private final List<Album> albums = Collections.synchronizedList(new ArrayList<Album>());
+
        /** Sone-specific options. */
        private final Options options = new Options();
 
@@ -247,7 +286,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
         */
        public void setLatestEdition(long latestEdition) {
                if (!(latestEdition > this.latestEdition)) {
-                       logger.log(Level.INFO, "New latest edition %d is not greater than current latest edition %d!", new Object[] { latestEdition, this.latestEdition });
+                       logger.log(Level.FINE, "New latest edition %d is not greater than current latest edition %d!", new Object[] { latestEdition, this.latestEdition });
                        return;
                }
                this.latestEdition = latestEdition;
@@ -597,6 +636,51 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
        }
 
        /**
+        * Returns the albums of this Sone.
+        *
+        * @return The albums of this Sone
+        */
+       public List<Album> getAlbums() {
+               return Collections.unmodifiableList(albums);
+       }
+
+       /**
+        * Adds an album to this Sone.
+        *
+        * @param album
+        *            The album to add
+        */
+       public synchronized void addAlbum(Album album) {
+               Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.getSone(), this).check();
+               albums.add(album);
+       }
+
+       /**
+        * Sets the albums of this Sone.
+        *
+        * @param albums
+        *            The albums of this Sone
+        */
+       public synchronized void setAlbums(Collection<? extends Album> albums) {
+               Validation.begin().isNotNull("Albums", albums).check();
+               this.albums.clear();
+               for (Album album : albums) {
+                       addAlbum(album);
+               }
+       }
+
+       /**
+        * Removes an album from this Sone.
+        *
+        * @param album
+        *            The album to remove
+        */
+       public synchronized void removeAlbum(Album album) {
+               Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.getSone(), this).check();
+               albums.remove(album);
+       }
+
+       /**
         * Returns Sone-specific options.
         *
         * @return The options of this Sone
@@ -623,6 +707,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
                }
                fingerprint.append(")");
 
+               @SuppressWarnings("hiding")
                List<Reply> replies = new ArrayList<Reply>(getReplies());
                Collections.sort(replies, Reply.TIME_COMPARATOR);
                fingerprint.append("Replies(");
@@ -631,6 +716,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
                }
                fingerprint.append(')');
 
+               @SuppressWarnings("hiding")
                List<String> likedPostIds = new ArrayList<String>(getLikedPostIds());
                Collections.sort(likedPostIds);
                fingerprint.append("LikedPosts(");
@@ -639,6 +725,7 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
                }
                fingerprint.append(')');
 
+               @SuppressWarnings("hiding")
                List<String> likedReplyIds = new ArrayList<String>(getLikedReplyIds());
                Collections.sort(likedReplyIds);
                fingerprint.append("LikedReplies(");
@@ -647,10 +734,43 @@ public class Sone implements Fingerprintable, Comparable<Sone> {
                }
                fingerprint.append(')');
 
+               fingerprint.append("Albums(");
+               for (Album album : albums) {
+                       fingerprint.append(album.getFingerprint());
+               }
+               fingerprint.append(')');
+
                return fingerprint.toString();
        }
 
        //
+       // STATIC METHODS
+       //
+
+       /**
+        * Flattens the given top-level albums so that the resulting list contains
+        * parent albums before child albums and the resulting list can be parsed in
+        * a single pass.
+        *
+        * @param albums
+        *            The albums to flatten
+        * @return The flattened albums
+        */
+       public static List<Album> flattenAlbums(Collection<? extends Album> albums) {
+               List<Album> flatAlbums = new ArrayList<Album>();
+               flatAlbums.addAll(albums);
+               int lastAlbumIndex = 0;
+               while (lastAlbumIndex < flatAlbums.size()) {
+                       int previousAlbumCount = flatAlbums.size();
+                       for (Album album : new ArrayList<Album>(flatAlbums.subList(lastAlbumIndex, flatAlbums.size()))) {
+                               flatAlbums.addAll(album.getAlbums());
+                       }
+                       lastAlbumIndex = previousAlbumCount;
+               }
+               return flatAlbums;
+       }
+
+       //
        // INTERFACE Comparable<Sone>
        //