A linked hash map is no longer required, the order is now stored elsewhere.
[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          * Returns the album image of this album, or {@code null} if no album image
212          * has been set.
213          *
214          * @return The image to show when this album is listed
215          */
216         public Image getAlbumImage() {
217                 if (albumImage == null) {
218                         return null;
219                 }
220                 return images.get(albumImage);
221         }
222
223         /**
224          * Sets the ID of the album image.
225          *
226          * @param id
227          *            The ID of the album image
228          * @return This album
229          */
230         public Album setAlbumImage(String id) {
231                 this.albumImage = id;
232                 return this;
233         }
234
235         /**
236          * Returns whether this album contains any other albums or images.
237          *
238          * @return {@code true} if this album is empty, {@code false} otherwise
239          */
240         public boolean isEmpty() {
241                 return albums.isEmpty() && images.isEmpty();
242         }
243
244         /**
245          * Returns the parent album of this album.
246          *
247          * @return The parent album of this album, or {@code null} if this album
248          *         does not have a parent
249          */
250         public Album getParent() {
251                 return parent;
252         }
253
254         /**
255          * Sets the parent album of this album.
256          *
257          * @param parent
258          *            The new parent album of this album
259          * @return This album
260          */
261         protected Album setParent(Album parent) {
262                 Validation.begin().isNotNull("Album Parent", parent).check();
263                 this.parent = parent;
264                 return this;
265         }
266
267         /**
268          * Removes the parent album of this album.
269          *
270          * @return This album
271          */
272         protected Album removeParent() {
273                 this.parent = null;
274                 return this;
275         }
276
277         /**
278          * Returns the title of this album.
279          *
280          * @return The title of this album
281          */
282         public String getTitle() {
283                 return title;
284         }
285
286         /**
287          * Sets the title of this album.
288          *
289          * @param title
290          *            The title of this album
291          * @return This album
292          */
293         public Album setTitle(String title) {
294                 Validation.begin().isNotNull("Album Title", title).check();
295                 this.title = title;
296                 return this;
297         }
298
299         /**
300          * Returns the description of this album.
301          *
302          * @return The description of this album
303          */
304         public String getDescription() {
305                 return description;
306         }
307
308         /**
309          * Sets the description of this album.
310          *
311          * @param description
312          *            The description of this album
313          * @return This album
314          */
315         public Album setDescription(String description) {
316                 Validation.begin().isNotNull("Album Description", description).check();
317                 this.description = description;
318                 return this;
319         }
320
321         //
322         // FINGERPRINTABLE METHODS
323         //
324
325         /**
326          * {@inheritDoc}
327          */
328         @Override
329         public String getFingerprint() {
330                 StringBuilder fingerprint = new StringBuilder();
331                 fingerprint.append("Album(");
332                 fingerprint.append("ID(").append(id).append(')');
333                 fingerprint.append("Title(").append(title).append(')');
334                 fingerprint.append("Description(").append(description).append(')');
335
336                 /* add nested albums. */
337                 fingerprint.append("Albums(");
338                 for (Album album : albums) {
339                         fingerprint.append(album.getFingerprint());
340                 }
341                 fingerprint.append(')');
342
343                 /* add images. */
344                 fingerprint.append("Images(");
345                 for (Image image : images.values()) {
346                         if (image.isInserted()) {
347                                 fingerprint.append(image.getFingerprint());
348                         }
349                 }
350                 fingerprint.append(')');
351
352                 fingerprint.append(')');
353                 return fingerprint.toString();
354         }
355
356         //
357         // OBJECT METHODS
358         //
359
360         /**
361          * {@inheritDoc}
362          */
363         @Override
364         public int hashCode() {
365                 return id.hashCode();
366         }
367
368         /**
369          * {@inheritDoc}
370          */
371         @Override
372         public boolean equals(Object object) {
373                 if (!(object instanceof Album)) {
374                         return false;
375                 }
376                 Album album = (Album) object;
377                 return id.equals(album.id);
378         }
379
380 }