Fix javadoc.
[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          * Moves the given album up in this album’s albums. If the album is already
156          * the first album, nothing happens.
157          *
158          * @param album
159          *            The album to move up
160          * @return The album that the given album swapped the place with, or
161          *         <code>null</code> if the album did not change its place
162          */
163         public Album moveAlbumUp(Album album) {
164                 Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.sone, sone).isEqual("Album Parent", album.parent, this).check();
165                 int oldIndex = albums.indexOf(album);
166                 if (oldIndex <= 0) {
167                         return null;
168                 }
169                 albums.remove(oldIndex);
170                 albums.add(oldIndex - 1, album);
171                 return albums.get(oldIndex);
172         }
173
174         /**
175          * Moves the given album down in this album’s albums. If the album is
176          * already the last album, nothing happens.
177          *
178          * @param album
179          *            The album to move down
180          * @return The album that the given album swapped the place with, or
181          *         <code>null</code> if the album did not change its place
182          */
183         public Album moveAlbumDown(Album album) {
184                 Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.sone, sone).isEqual("Album Parent", album.parent, this).check();
185                 int oldIndex = albums.indexOf(album);
186                 if ((oldIndex < 0) || (oldIndex >= (albums.size() - 1))) {
187                         return null;
188                 }
189                 albums.remove(oldIndex);
190                 albums.add(oldIndex + 1, album);
191                 return albums.get(oldIndex);
192         }
193
194         /**
195          * Returns the images in this album.
196          *
197          * @return The images in this album
198          */
199         public List<Image> getImages() {
200                 return Mappers.mappedList(imageIds, new Mapper<String, Image>() {
201
202                         @Override
203                         @SuppressWarnings("synthetic-access")
204                         public Image map(String imageId) {
205                                 return images.get(imageId);
206                         }
207
208                 });
209         }
210
211         /**
212          * Adds the given image to this album.
213          *
214          * @param image
215          *            The image to add
216          */
217         public void addImage(Image image) {
218                 Validation.begin().isNotNull("Image", image).check().isNotNull("Image Owner", image.getSone()).check().isEqual("Image Owner", image.getSone(), sone).check();
219                 if (image.getAlbum() != null) {
220                         image.getAlbum().removeImage(image);
221                 }
222                 image.setAlbum(this);
223                 if (imageIds.isEmpty() && (albumImage == null)) {
224                         albumImage = image.getId();
225                 }
226                 if (!imageIds.contains(image.getId())) {
227                         imageIds.add(image.getId());
228                         images.put(image.getId(), image);
229                 }
230         }
231
232         /**
233          * Removes the given image from this album.
234          *
235          * @param image
236          *            The image to remove
237          */
238         public void removeImage(Image image) {
239                 Validation.begin().isNotNull("Image", image).check().isEqual("Image Owner", image.getSone(), sone).check();
240                 imageIds.remove(image.getId());
241                 images.remove(image.getId());
242                 if (image.getId().equals(albumImage)) {
243                         if (images.isEmpty()) {
244                                 albumImage = null;
245                         } else {
246                                 albumImage = images.values().iterator().next().getId();
247                         }
248                 }
249         }
250
251         /**
252          * Moves the given image up in this album’s images. If the image is already
253          * the first image, nothing happens.
254          *
255          * @param image
256          *            The image to move up
257          * @return The image that the given image swapped the place with, or
258          *         <code>null</code> if the image did not change its place
259          */
260         public Image moveImageUp(Image image) {
261                 Validation.begin().isNotNull("Image", image).check().isEqual("Image Album", image.getAlbum(), this).isEqual("Album Owner", image.getAlbum().getSone(), sone).check();
262                 int oldIndex = imageIds.indexOf(image.getId());
263                 if (oldIndex <= 0) {
264                         return null;
265                 }
266                 imageIds.remove(image.getId());
267                 imageIds.add(oldIndex - 1, image.getId());
268                 return images.get(imageIds.get(oldIndex));
269         }
270
271         /**
272          * Moves the given image down in this album’s images. If the image is
273          * already the last image, nothing happens.
274          *
275          * @param image
276          *            The image to move down
277          * @return The image that the given image swapped the place with, or
278          *         <code>null</code> if the image did not change its place
279          */
280         public Image moveImageDown(Image image) {
281                 Validation.begin().isNotNull("Image", image).check().isEqual("Image Album", image.getAlbum(), this).isEqual("Album Owner", image.getAlbum().getSone(), sone).check();
282                 int oldIndex = imageIds.indexOf(image.getId());
283                 if ((oldIndex == -1) || (oldIndex >= (imageIds.size() - 1))) {
284                         return null;
285                 }
286                 imageIds.remove(image.getId());
287                 imageIds.add(oldIndex + 1, image.getId());
288                 return images.get(imageIds.get(oldIndex));
289         }
290
291         /**
292          * Returns the album image of this album, or {@code null} if no album image
293          * has been set.
294          *
295          * @return The image to show when this album is listed
296          */
297         public Image getAlbumImage() {
298                 if (albumImage == null) {
299                         return null;
300                 }
301                 return Default.forNull(images.get(albumImage), images.values().iterator().next());
302         }
303
304         /**
305          * Sets the ID of the album image.
306          *
307          * @param id
308          *            The ID of the album image
309          * @return This album
310          */
311         public Album setAlbumImage(String id) {
312                 this.albumImage = id;
313                 return this;
314         }
315
316         /**
317          * Returns whether this album contains any other albums or images.
318          *
319          * @return {@code true} if this album is empty, {@code false} otherwise
320          */
321         public boolean isEmpty() {
322                 return albums.isEmpty() && images.isEmpty();
323         }
324
325         /**
326          * Returns the parent album of this album.
327          *
328          * @return The parent album of this album, or {@code null} if this album
329          *         does not have a parent
330          */
331         public Album getParent() {
332                 return parent;
333         }
334
335         /**
336          * Sets the parent album of this album.
337          *
338          * @param parent
339          *            The new parent album of this album
340          * @return This album
341          */
342         protected Album setParent(Album parent) {
343                 Validation.begin().isNotNull("Album Parent", parent).check();
344                 this.parent = parent;
345                 return this;
346         }
347
348         /**
349          * Removes the parent album of this album.
350          *
351          * @return This album
352          */
353         protected Album removeParent() {
354                 this.parent = null;
355                 return this;
356         }
357
358         /**
359          * Returns the title of this album.
360          *
361          * @return The title of this album
362          */
363         public String getTitle() {
364                 return title;
365         }
366
367         /**
368          * Sets the title of this album.
369          *
370          * @param title
371          *            The title of this album
372          * @return This album
373          */
374         public Album setTitle(String title) {
375                 Validation.begin().isNotNull("Album Title", title).check();
376                 this.title = title;
377                 return this;
378         }
379
380         /**
381          * Returns the description of this album.
382          *
383          * @return The description of this album
384          */
385         public String getDescription() {
386                 return description;
387         }
388
389         /**
390          * Sets the description of this album.
391          *
392          * @param description
393          *            The description of this album
394          * @return This album
395          */
396         public Album setDescription(String description) {
397                 Validation.begin().isNotNull("Album Description", description).check();
398                 this.description = description;
399                 return this;
400         }
401
402         //
403         // FINGERPRINTABLE METHODS
404         //
405
406         /**
407          * {@inheritDoc}
408          */
409         @Override
410         public String getFingerprint() {
411                 StringBuilder fingerprint = new StringBuilder();
412                 fingerprint.append("Album(");
413                 fingerprint.append("ID(").append(id).append(')');
414                 fingerprint.append("Title(").append(title).append(')');
415                 fingerprint.append("Description(").append(description).append(')');
416                 if (albumImage != null) {
417                         fingerprint.append("AlbumImage(").append(albumImage).append(')');
418                 }
419
420                 /* add nested albums. */
421                 fingerprint.append("Albums(");
422                 for (Album album : albums) {
423                         fingerprint.append(album.getFingerprint());
424                 }
425                 fingerprint.append(')');
426
427                 /* add images. */
428                 fingerprint.append("Images(");
429                 for (Image image : getImages()) {
430                         if (image.isInserted()) {
431                                 fingerprint.append(image.getFingerprint());
432                         }
433                 }
434                 fingerprint.append(')');
435
436                 fingerprint.append(')');
437                 return fingerprint.toString();
438         }
439
440         //
441         // OBJECT METHODS
442         //
443
444         /**
445          * {@inheritDoc}
446          */
447         @Override
448         public int hashCode() {
449                 return id.hashCode();
450         }
451
452         /**
453          * {@inheritDoc}
454          */
455         @Override
456         public boolean equals(Object object) {
457                 if (!(object instanceof Album)) {
458                         return false;
459                 }
460                 Album album = (Album) object;
461                 return id.equals(album.id);
462         }
463
464 }