8864f135f6cb8112eb2ab926a9b2ebef734c0128
[Sone.git] / src / main / java / net / pterodactylus / sone / data / Album.java
1 /*
2  * Sone - Album.java - Copyright © 2011–2013 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 static java.util.Arrays.asList;
21 import static java.util.Collections.emptyList;
22
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.Comparator;
26 import java.util.List;
27 import javax.annotation.Nonnull;
28
29 import net.pterodactylus.sone.database.ImageBuilder;
30
31 import com.google.common.base.Function;
32 import com.google.common.base.Predicate;
33 import com.google.common.collect.FluentIterable;
34 import com.google.common.collect.ImmutableList;
35
36 /**
37  * Container for images that can also contain nested {@link Album}s.
38  *
39  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
40  */
41 public interface Album extends Identified, Fingerprintable {
42
43         /** Compares two {@link Album}s by {@link #getTitle()}. */
44         Comparator<Album> TITLE_COMPARATOR = new Comparator<Album>() {
45
46                 @Override
47                 public int compare(Album leftAlbum, Album rightAlbum) {
48                         return leftAlbum.getTitle().compareToIgnoreCase(rightAlbum.getTitle());
49                 }
50         };
51
52         /** Function that flattens the given album and all albums beneath it. */
53         Function<Album, List<Album>> FLATTENER = new Function<Album, List<Album>>() {
54
55                 @Override
56                 @Nonnull
57                 public List<Album> apply(Album album) {
58                         if (album == null) {
59                                 return emptyList();
60                         }
61                         List<Album> albums = new ArrayList<Album>();
62                         albums.add(album);
63                         for (Album subAlbum : album.getAlbums()) {
64                                 albums.addAll(FluentIterable.from(ImmutableList.of(subAlbum)).transformAndConcat(FLATTENER).toList());
65                         }
66                         return albums;
67                 }
68         };
69
70         /** Function that transforms an album into the images it contains. */
71         Function<Album, List<Image>> IMAGES = new Function<Album, List<Image>>() {
72
73                 @Override
74                 @Nonnull
75                 public List<Image> apply(Album album) {
76                         return (album != null) ? album.getImages() : Collections.<Image>emptyList();
77                 }
78         };
79
80         /**
81          * Filter that removes all albums that do not have any images in any album
82          * below it.
83          */
84         Predicate<Album> NOT_EMPTY = new Predicate<Album>() {
85
86                 @Override
87                 public boolean apply(Album album) {
88                         /* so, we flatten all albums below the given one and check whether at least one album… */
89                         return FluentIterable.from(asList(album)).transformAndConcat(FLATTENER).anyMatch(new Predicate<Album>() {
90
91                                 @Override
92                                 public boolean apply(Album album) {
93                                         /* …contains any inserted images. */
94                                         return !album.getImages().isEmpty() && FluentIterable.from(album.getImages()).allMatch(new Predicate<Image>() {
95
96                                                 @Override
97                                                 public boolean apply(Image input) {
98                                                         return input.isInserted();
99                                                 }
100                                         });
101                                 }
102                         });
103                 }
104         };
105
106         /**
107          * Returns the ID of this album.
108          *
109          * @return The ID of this album
110          */
111         String getId();
112
113         /**
114          * Returns the Sone this album belongs to.
115          *
116          * @return The Sone this album belongs to
117          */
118         Sone getSone();
119
120         /**
121          * Sets the owner of the album. The owner can only be set as long as the
122          * current owner is {@code null}.
123          *
124          * @param sone
125          *              The album owner
126          * @return This album
127          */
128         Album setSone(Sone sone);
129
130         /**
131          * Returns the nested albums.
132          *
133          * @return The nested albums
134          */
135         List<Album> getAlbums();
136
137         /**
138          * Adds an album to this album.
139          *
140          * @param album
141          *              The album to add
142          */
143         void addAlbum(Album album);
144
145         /**
146          * Removes an album from this album.
147          *
148          * @param album
149          *              The album to remove
150          */
151         void removeAlbum(Album album);
152
153         /**
154          * Moves the given album up in this album’s albums. If the album is already the
155          * first album, nothing happens.
156          *
157          * @param album
158          *              The album to move up
159          * @return The album that the given album swapped the place with, or
160          *         <code>null</code> if the album did not change its place
161          */
162         Album moveAlbumUp(Album album);
163
164         /**
165          * Moves the given album down in this album’s albums. If the album is already
166          * the last album, nothing happens.
167          *
168          * @param album
169          *              The album to move down
170          * @return The album that the given album swapped the place with, or
171          *         <code>null</code> if the album did not change its place
172          */
173         Album moveAlbumDown(Album album);
174
175         /**
176          * Returns the images in this album.
177          *
178          * @return The images in this album
179          */
180         List<Image> getImages();
181
182         /**
183          * Removes the given image from this album.
184          *
185          * @param image
186          *              The image to remove
187          */
188         void removeImage(Image image);
189
190         /**
191          * Moves the given image up in this album’s images. If the image is already the
192          * first image, nothing happens.
193          *
194          * @param image
195          *              The image to move up
196          * @return The image that the given image swapped the place with, or
197          *         <code>null</code> if the image did not change its place
198          */
199         Image moveImageUp(Image image);
200
201         /**
202          * Moves the given image down in this album’s images. If the image is already
203          * the last image, nothing happens.
204          *
205          * @param image
206          *              The image to move down
207          * @return The image that the given image swapped the place with, or
208          *         <code>null</code> if the image did not change its place
209          */
210         Image moveImageDown(Image image);
211
212         /**
213          * Returns the album image of this album, or {@code null} if no album image has
214          * been set.
215          *
216          * @return The image to show when this album is listed
217          */
218         Image getAlbumImage();
219
220         /**
221          * Returns whether this album contains any other albums or images.
222          *
223          * @return {@code true} if this album is empty, {@code false} otherwise
224          */
225         boolean isEmpty();
226
227         /**
228          * Returns whether this album is an identitiy’s root album.
229          *
230          * @return {@code true} if this album is an identity’s root album, {@code
231          *         false} otherwise
232          */
233         boolean isRoot();
234
235         /**
236          * Returns the parent album of this album.
237          *
238          * @return The parent album of this album, or {@code null} if this album does
239          *         not have a parent
240          */
241         Album getParent();
242
243         /**
244          * Sets the parent album of this album.
245          *
246          * @param parent
247          *              The new parent album of this album
248          * @return This album
249          */
250         Album setParent(Album parent);
251
252         /**
253          * Removes the parent album of this album.
254          *
255          * @return This album
256          */
257         Album removeParent();
258
259         /**
260          * Returns the title of this album.
261          *
262          * @return The title of this album
263          */
264         String getTitle();
265
266         /**
267          * Returns the description of this album.
268          *
269          * @return The description of this album
270          */
271         String getDescription();
272
273         ImageBuilder newImageBuilder() throws IllegalStateException;
274
275         /**
276          * Returns a modifier for this album.
277          *
278          * @return A modifier for this album
279          * @throws IllegalStateException
280          *              if this album can not be modified
281          */
282         Modifier modify() throws IllegalStateException;
283
284         /**
285          * Allows modifying an album. Modifications are only performed once {@link
286          * #update()} has succesfully returned a new album with the modifications
287          * made.
288          *
289          * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
290          */
291         interface Modifier {
292
293                 Modifier setTitle(String title);
294
295                 Modifier setDescription(String description);
296
297                 Modifier setAlbumImage(String imageId);
298
299                 Album update() throws IllegalStateException;
300
301         }
302
303 }