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