Store album image ID in fingerprint.
[Sone.git] / src / main / java / net / pterodactylus / sone / data / Album.java
1 /*
2  * Sone - Album.java - Copyright © 2011 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 java.util.ArrayList;
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.UUID;
25
26 import net.pterodactylus.util.collection.Mapper;
27 import net.pterodactylus.util.collection.Mappers;
28 import net.pterodactylus.util.object.Default;
29 import net.pterodactylus.util.validation.Validation;
30
31 /**
32  * Container for images that can also contain nested {@link Album}s.
33  *
34  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
35  */
36 public class Album implements Fingerprintable {
37
38         /** The ID of this album. */
39         private final String id;
40
41         /** The Sone this album belongs to. */
42         private Sone sone;
43
44         /** Nested albums. */
45         private final List<Album> albums = new ArrayList<Album>();
46
47         /** The image IDs in order. */
48         private final List<String> imageIds = new ArrayList<String>();
49
50         /** The images in this album. */
51         private final Map<String, Image> images = new HashMap<String, Image>();
52
53         /** The parent album. */
54         private Album parent;
55
56         /** The title of this album. */
57         private String title;
58
59         /** The description of this album. */
60         private String description;
61
62         /** The ID of the album picture. */
63         private String albumImage;
64
65         /**
66          * Creates a new album with a random ID.
67          */
68         public Album() {
69                 this(UUID.randomUUID().toString());
70         }
71
72         /**
73          * Creates a new album with the given ID.
74          *
75          * @param id
76          *            The ID of the album
77          */
78         public Album(String id) {
79                 Validation.begin().isNotNull("Album ID", id).check();
80                 this.id = id;
81         }
82
83         //
84         // ACCESSORS
85         //
86
87         /**
88          * Returns the ID of this album.
89          *
90          * @return The ID of this album
91          */
92         public String getId() {
93                 return id;
94         }
95
96         /**
97          * Returns the Sone this album belongs to.
98          *
99          * @return The Sone this album belongs to
100          */
101         public Sone getSone() {
102                 return sone;
103         }
104
105         /**
106          * Sets the owner of the album. The owner can only be set as long as the
107          * current owner is {@code null}.
108          *
109          * @param sone
110          *            The album owner
111          * @return This album
112          */
113         public Album setSone(Sone sone) {
114                 Validation.begin().isNotNull("New Album Owner", sone).isEither("Old Album Owner", this.sone, null, sone).check();
115                 this.sone = sone;
116                 return this;
117         }
118
119         /**
120          * Returns the nested albums.
121          *
122          * @return The nested albums
123          */
124         public List<Album> getAlbums() {
125                 return new ArrayList<Album>(albums);
126         }
127
128         /**
129          * Adds an album to this album.
130          *
131          * @param album
132          *            The album to add
133          */
134         public void addAlbum(Album album) {
135                 Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.sone, sone).isEither("Old Album Parent", this.parent, null, album.parent).check();
136                 album.setParent(this);
137                 if (!albums.contains(album)) {
138                         albums.add(album);
139                 }
140         }
141
142         /**
143          * Removes an album from this album.
144          *
145          * @param album
146          *            The album to remove
147          */
148         public void removeAlbum(Album album) {
149                 Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.sone, sone).isEqual("Album Parent", album.parent, this).check();
150                 albums.remove(album);
151                 album.removeParent();
152         }
153
154         /**
155          * Returns the images in this album.
156          *
157          * @return The images in this album
158          */
159         public List<Image> getImages() {
160                 return Mappers.mappedList(imageIds, new Mapper<String, Image>() {
161
162                         @Override
163                         @SuppressWarnings("synthetic-access")
164                         public Image map(String imageId) {
165                                 return images.get(imageId);
166                         }
167
168                 });
169         }
170
171         /**
172          * Adds the given image to this album.
173          *
174          * @param image
175          *            The image to add
176          */
177         public void addImage(Image image) {
178                 Validation.begin().isNotNull("Image", image).check().isNotNull("Image Owner", image.getSone()).check().isEqual("Image Owner", image.getSone(), sone).check();
179                 if (image.getAlbum() != null) {
180                         image.getAlbum().removeImage(image);
181                 }
182                 image.setAlbum(this);
183                 if (imageIds.isEmpty()) {
184                         albumImage = image.getId();
185                 }
186                 if (!imageIds.contains(image.getId())) {
187                         imageIds.add(image.getId());
188                         images.put(image.getId(), image);
189                 }
190         }
191
192         /**
193          * Removes the given image from this album.
194          *
195          * @param image
196          *            The image to remove
197          */
198         public void removeImage(Image image) {
199                 Validation.begin().isNotNull("Image", image).check().isEqual("Image Owner", image.getSone(), sone).check();
200                 imageIds.remove(image.getId());
201                 images.remove(image.getId());
202                 if (image.getId().equals(albumImage)) {
203                         if (images.isEmpty()) {
204                                 albumImage = null;
205                         } else {
206                                 albumImage = images.values().iterator().next().getId();
207                         }
208                 }
209         }
210
211         /**
212          * Moves the given image up in this album’s images. If the image is already
213          * the first image, nothing happens.
214          *
215          * @param image
216          *            The image to move up
217          */
218         public void moveImageUp(Image image) {
219                 Validation.begin().isNotNull("Image", image).check().isEqual("Image Album", image.getAlbum(), this).isEqual("Album Owner", image.getAlbum().getSone(), sone).check();
220                 int oldIndex = imageIds.indexOf(image.getId());
221                 if (oldIndex <= 0) {
222                         return;
223                 }
224                 imageIds.remove(image.getId());
225                 imageIds.add(oldIndex - 1, image.getId());
226         }
227
228         /**
229          * Move the given image down in this album’s images. If the image is already
230          * the last image, nothing happens.
231          *
232          * @param image
233          *            The image to move down
234          */
235         public void moveImageDown(Image image) {
236                 Validation.begin().isNotNull("Image", image).check().isEqual("Image Album", image.getAlbum(), this).isEqual("Album Owner", image.getAlbum().getSone(), sone).check();
237                 int oldIndex = imageIds.indexOf(image.getId());
238                 if ((oldIndex == -1) || (oldIndex >= (imageIds.size() - 1))) {
239                         return;
240                 }
241                 imageIds.remove(image.getId());
242                 imageIds.add(oldIndex + 1, image.getId());
243         }
244
245         /**
246          * Returns the album image of this album, or {@code null} if no album image
247          * has been set.
248          *
249          * @return The image to show when this album is listed
250          */
251         public Image getAlbumImage() {
252                 if (albumImage == null) {
253                         return null;
254                 }
255                 return Default.forNull(images.get(albumImage), images.values().iterator().next());
256         }
257
258         /**
259          * Sets the ID of the album image.
260          *
261          * @param id
262          *            The ID of the album image
263          * @return This album
264          */
265         public Album setAlbumImage(String id) {
266                 this.albumImage = id;
267                 return this;
268         }
269
270         /**
271          * Returns whether this album contains any other albums or images.
272          *
273          * @return {@code true} if this album is empty, {@code false} otherwise
274          */
275         public boolean isEmpty() {
276                 return albums.isEmpty() && images.isEmpty();
277         }
278
279         /**
280          * Returns the parent album of this album.
281          *
282          * @return The parent album of this album, or {@code null} if this album
283          *         does not have a parent
284          */
285         public Album getParent() {
286                 return parent;
287         }
288
289         /**
290          * Sets the parent album of this album.
291          *
292          * @param parent
293          *            The new parent album of this album
294          * @return This album
295          */
296         protected Album setParent(Album parent) {
297                 Validation.begin().isNotNull("Album Parent", parent).check();
298                 this.parent = parent;
299                 return this;
300         }
301
302         /**
303          * Removes the parent album of this album.
304          *
305          * @return This album
306          */
307         protected Album removeParent() {
308                 this.parent = null;
309                 return this;
310         }
311
312         /**
313          * Returns the title of this album.
314          *
315          * @return The title of this album
316          */
317         public String getTitle() {
318                 return title;
319         }
320
321         /**
322          * Sets the title of this album.
323          *
324          * @param title
325          *            The title of this album
326          * @return This album
327          */
328         public Album setTitle(String title) {
329                 Validation.begin().isNotNull("Album Title", title).check();
330                 this.title = title;
331                 return this;
332         }
333
334         /**
335          * Returns the description of this album.
336          *
337          * @return The description of this album
338          */
339         public String getDescription() {
340                 return description;
341         }
342
343         /**
344          * Sets the description of this album.
345          *
346          * @param description
347          *            The description of this album
348          * @return This album
349          */
350         public Album setDescription(String description) {
351                 Validation.begin().isNotNull("Album Description", description).check();
352                 this.description = description;
353                 return this;
354         }
355
356         //
357         // FINGERPRINTABLE METHODS
358         //
359
360         /**
361          * {@inheritDoc}
362          */
363         @Override
364         public String getFingerprint() {
365                 StringBuilder fingerprint = new StringBuilder();
366                 fingerprint.append("Album(");
367                 fingerprint.append("ID(").append(id).append(')');
368                 fingerprint.append("Title(").append(title).append(')');
369                 fingerprint.append("Description(").append(description).append(')');
370                 if (albumImage != null) {
371                         fingerprint.append("AlbumImage(").append(albumImage).append(')');
372                 }
373
374                 /* add nested albums. */
375                 fingerprint.append("Albums(");
376                 for (Album album : albums) {
377                         fingerprint.append(album.getFingerprint());
378                 }
379                 fingerprint.append(')');
380
381                 /* add images. */
382                 fingerprint.append("Images(");
383                 for (Image image : images.values()) {
384                         if (image.isInserted()) {
385                                 fingerprint.append(image.getFingerprint());
386                         }
387                 }
388                 fingerprint.append(')');
389
390                 fingerprint.append(')');
391                 return fingerprint.toString();
392         }
393
394         //
395         // OBJECT METHODS
396         //
397
398         /**
399          * {@inheritDoc}
400          */
401         @Override
402         public int hashCode() {
403                 return id.hashCode();
404         }
405
406         /**
407          * {@inheritDoc}
408          */
409         @Override
410         public boolean equals(Object object) {
411                 if (!(object instanceof Album)) {
412                         return false;
413                 }
414                 Album album = (Album) object;
415                 return id.equals(album.id);
416         }
417
418 }