Add equals() method that ignores the comment of the content metadata.
[sonitus.git] / src / main / java / net / pterodactylus / sonitus / data / ContentMetadata.java
1 /*
2  * Sonitus - ContentMetadata.java - Copyright © 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.sonitus.data;
19
20 import java.util.Arrays;
21
22 import com.google.common.base.Joiner;
23 import com.google.common.base.Optional;
24 import com.google.common.base.Preconditions;
25
26 /**
27  * The part of the {@link Metadata} that contains information about the content
28  * of a {@link Source}, such as the name of the track, the artist, or other
29  * information.
30  * <p/>
31  * Content metadata also contains a “title” which is an amalgamation of all
32  * information in the content metadata. If not given, it will be automatically
33  * constructed from all other information. If can also be specified manually to
34  * override the default.
35  *
36  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
37  */
38 public class ContentMetadata {
39
40         /** The artist. */
41         private final Optional<String> artist;
42
43         /** The name. */
44         private final Optional<String> name;
45
46         /** The all-in-one title. */
47         private final String title;
48
49         /** The comment. */
50         private final Optional<String> comment;
51
52         /** Creates empty content metadata. */
53         public ContentMetadata() {
54                 this("");
55         }
56
57         /**
58          * Creates content metadata containing the given title.
59          *
60          * @param title
61          *              The title of the metadata
62          * @throws NullPointerException
63          *              if {@code title} is {@code null}
64          */
65         public ContentMetadata(String title) throws NullPointerException {
66                 this(null, null, title, null);
67         }
68
69         /**
70          * Creates content metadata.
71          *
72          * @param artist
73          *              The artist of the track
74          * @param name
75          *              The name of the track
76          */
77         public ContentMetadata(String artist, String name) {
78                 this(artist, name, joinStrings(artist, name), null);
79         }
80
81         /**
82          * Creates content metadata.
83          *
84          * @param artist
85          *              The artist of the track (may be null)
86          * @param name
87          *              The name of the track (may be null)
88          * @param title
89          *              The title of the track
90          * @param comment
91          *              The comment of the track
92          * @throws NullPointerException
93          *              if {@code title} is {@code null}
94          */
95         private ContentMetadata(String artist, String name, String title, String comment) throws NullPointerException {
96                 this.artist = Optional.fromNullable(artist);
97                 this.name = Optional.fromNullable(name);
98                 this.title = Preconditions.checkNotNull(title, "title must not be null");
99                 this.comment = Optional.fromNullable(comment);
100         }
101
102         //
103         // ACCESSORS
104         //
105
106         /**
107          * Returns the artist of the track, if it has been set.
108          *
109          * @return The artist of the track
110          */
111         public Optional<String> artist() {
112                 return artist;
113         }
114
115         /**
116          * Returns the name of the track, if it has been set.
117          *
118          * @return The name of the track
119          */
120         public Optional<String> name() {
121                 return name;
122         }
123
124         /**
125          * Returns the title of the track.
126          *
127          * @return The title of the track
128          */
129         public String title() {
130                 return title;
131         }
132
133         /**
134          * Returns the comment of the track, if it has been set.
135          *
136          * @return The comment of the track
137          */
138         public Optional<String> comment() {
139                 return comment;
140         }
141
142         //
143         // ACTIONS
144         //
145
146         /**
147          * Creates new content metadata that is a copy of this content metadata but
148          * with the artist changed. The title will be reconstructed from the new artist
149          * and the existing name.
150          *
151          * @param artist
152          *              The new artist
153          * @return The new content metadata
154          */
155         public ContentMetadata artist(String artist) {
156                 return new ContentMetadata(artist, name().orNull(), joinStrings(artist, name().orNull()), comment.orNull());
157         }
158
159         /**
160          * Creates new content metadata that is a copy of this content metadata but
161          * with the name changed. The title will be reconstructed from the existing
162          * artist and the new name.
163          *
164          * @param name
165          *              The new name
166          * @return The new content metadata
167          */
168         public ContentMetadata name(String name) {
169                 return new ContentMetadata(artist().orNull(), name, joinStrings(artist().orNull(), name), comment.orNull());
170         }
171
172         /**
173          * Creates new content metadata that is a copy of this content metadata but
174          * with the title changed.
175          *
176          * @param title
177          *              The new title
178          * @return The new content metadata
179          */
180         public ContentMetadata title(String title) {
181                 return new ContentMetadata(artist().orNull(), name().orNull(), title, comment.orNull());
182         }
183
184         /**
185          * Creates new content metadata that is a copy of this content metadata but
186          * with the comment changed.
187          *
188          * @param comment
189          *              The comment
190          * @return The new content metadata
191          */
192         public ContentMetadata comment(String comment) {
193                 return new ContentMetadata(artist().orNull(), name().orNull(), title(), comment);
194         }
195
196         /**
197          * Returns whether this content metadata object equals the given object if the
198          * comments of this and the given object are ignored.
199          *
200          * @param object
201          *              The object to compare to this one
202          * @return {@code true} if the given object and this object are equal if the
203          *         comments are ignored, {@code false} otherwise
204          */
205         public boolean equalsIgnoreComment(Object object) {
206                 if (!(object instanceof ContentMetadata)) {
207                         return false;
208                 }
209                 ContentMetadata contentMetadata = (ContentMetadata) object;
210                 return artist().equals(contentMetadata.artist()) && name().equals(contentMetadata.name()) && title().equals(contentMetadata.title());
211         }
212
213         //
214         // OBJECT METHODS
215         //
216
217         @Override
218         public int hashCode() {
219                 return artist().hashCode() ^ name().hashCode() ^ title().hashCode() ^ comment().hashCode();
220         }
221
222         @Override
223         public boolean equals(Object object) {
224                 if (!(object instanceof ContentMetadata)) {
225                         return false;
226                 }
227                 ContentMetadata contentMetadata = (ContentMetadata) object;
228                 return artist().equals(contentMetadata.artist()) && name().equals(contentMetadata.name()) && title().equals(contentMetadata.title()) && comment().equals(contentMetadata.comment());
229         }
230
231         @Override
232         public String toString() {
233                 return String.format("%s%s", title(), comment().isPresent() ? String.format(" (%s)", comment().get()) : "");
234         }
235
236         //
237         // STATIC METHODS
238         //
239
240         /**
241          * Joins the given strings, concatenating them with “ - ” and ignoring {@code
242          * null} values.
243          *
244          * @param strings
245          *              The strings to join
246          * @return The joined strings
247          */
248         private static String joinStrings(String... strings) {
249                 return Joiner.on(" - ").skipNulls().join(Arrays.asList(strings));
250         }
251
252 }