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