Update years in copyright line
[Sone.git] / src / main / java / net / pterodactylus / sone / data / Album.java
1 /*
2  * Sone - Album.java - Copyright © 2011–2015 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          * Returns the nested albums.
120          *
121          * @return The nested albums
122          */
123         List<Album> getAlbums();
124
125         /**
126          * Adds an album to this album.
127          *
128          * @param album
129          *              The album to add
130          */
131         void addAlbum(Album album);
132
133         /**
134          * Removes an album from this album.
135          *
136          * @param album
137          *              The album to remove
138          */
139         void removeAlbum(Album album);
140
141         /**
142          * Moves the given album up in this album’s albums. If the album is already the
143          * first album, nothing happens.
144          *
145          * @param album
146          *              The album to move up
147          * @return The album that the given album swapped the place with, or
148          *         <code>null</code> if the album did not change its place
149          */
150         Album moveAlbumUp(Album album);
151
152         /**
153          * Moves the given album down in this album’s albums. If the album is already
154          * the last album, nothing happens.
155          *
156          * @param album
157          *              The album to move down
158          * @return The album that the given album swapped the place with, or
159          *         <code>null</code> if the album did not change its place
160          */
161         Album moveAlbumDown(Album album);
162
163         /**
164          * Returns the images in this album.
165          *
166          * @return The images in this album
167          */
168         List<Image> getImages();
169
170         /**
171          * Adds the given image to this album.
172          *
173          * @param image
174          *              The image to add
175          */
176         void addImage(Image image);
177
178         /**
179          * Removes the given image from this album.
180          *
181          * @param image
182          *              The image to remove
183          */
184         void removeImage(Image image);
185
186         /**
187          * Moves the given image up in this album’s images. If the image is already the
188          * first image, nothing happens.
189          *
190          * @param image
191          *              The image to move up
192          * @return The image that the given image swapped the place with, or
193          *         <code>null</code> if the image did not change its place
194          */
195         Image moveImageUp(Image image);
196
197         /**
198          * Moves the given image down in this album’s images. If the image is already
199          * the last image, nothing happens.
200          *
201          * @param image
202          *              The image to move down
203          * @return The image that the given image swapped the place with, or
204          *         <code>null</code> if the image did not change its place
205          */
206         Image moveImageDown(Image image);
207
208         /**
209          * Returns the album image of this album, or {@code null} if no album image has
210          * been set.
211          *
212          * @return The image to show when this album is listed
213          */
214         Image getAlbumImage();
215
216         /**
217          * Returns whether this album contains any other albums or images.
218          *
219          * @return {@code true} if this album is empty, {@code false} otherwise
220          */
221         boolean isEmpty();
222
223         /**
224          * Returns whether this album is an identitiy’s root album.
225          *
226          * @return {@code true} if this album is an identity’s root album, {@code
227          *         false} otherwise
228          */
229         boolean isRoot();
230
231         /**
232          * Returns the parent album of this album.
233          *
234          * @return The parent album of this album, or {@code null} if this album does
235          *         not have a parent
236          */
237         Album getParent();
238
239         /**
240          * Sets the parent album of this album.
241          *
242          * @param parent
243          *              The new parent album of this album
244          * @return This album
245          */
246         Album setParent(Album parent);
247
248         /**
249          * Removes the parent album of this album.
250          *
251          * @return This album
252          */
253         Album removeParent();
254
255         /**
256          * Returns the title of this album.
257          *
258          * @return The title of this album
259          */
260         String getTitle();
261
262         /**
263          * Returns the description of this album.
264          *
265          * @return The description of this album
266          */
267         String getDescription();
268
269         /**
270          * Returns a modifier for this album.
271          *
272          * @return A modifier for this album
273          * @throws IllegalStateException
274          *              if this album can not be modified
275          */
276         Modifier modify() throws IllegalStateException;
277
278         /**
279          * Allows modifying an album. Modifications are only performed once {@link
280          * #update()} has succesfully returned a new album with the modifications
281          * made.
282          *
283          * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
284          */
285         interface Modifier {
286
287                 Modifier setTitle(String title);
288
289                 Modifier setDescription(String description);
290
291                 Modifier setAlbumImage(String imageId);
292
293                 Album update() throws IllegalStateException;
294
295                 class AlbumTitleMustNotBeEmpty extends IllegalStateException { }
296
297         }
298
299 }