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