+ /**
+ * 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
+ */
+ public Options getOptions() {
+ return options;
+ }
+
+ //
+ // FINGERPRINTABLE METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public synchronized String getFingerprint() {
+ StringBuilder fingerprint = new StringBuilder();
+ fingerprint.append(profile.getFingerprint());
+
+ fingerprint.append("Posts(");
+ for (Post post : getPosts()) {
+ fingerprint.append("Post(").append(post.getId()).append(')');
+ }
+ fingerprint.append(")");
+
+ @SuppressWarnings("hiding")
+ List<Reply> replies = new ArrayList<Reply>(getReplies());
+ Collections.sort(replies, Reply.TIME_COMPARATOR);
+ fingerprint.append("Replies(");
+ for (Reply reply : replies) {
+ fingerprint.append("Reply(").append(reply.getId()).append(')');
+ }
+ fingerprint.append(')');
+
+ @SuppressWarnings("hiding")
+ List<String> likedPostIds = new ArrayList<String>(getLikedPostIds());
+ Collections.sort(likedPostIds);
+ fingerprint.append("LikedPosts(");
+ for (String likedPostId : likedPostIds) {
+ fingerprint.append("Post(").append(likedPostId).append(')');
+ }
+ fingerprint.append(')');
+
+ @SuppressWarnings("hiding")
+ List<String> likedReplyIds = new ArrayList<String>(getLikedReplyIds());
+ Collections.sort(likedReplyIds);
+ fingerprint.append("LikedReplies(");
+ for (String likedReplyId : likedReplyIds) {
+ fingerprint.append("Reply(").append(likedReplyId).append(')');
+ }
+ 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>
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int compareTo(Sone sone) {
+ return NICE_NAME_COMPARATOR.compare(this, sone);
+ }
+