f4f0eded3bf125847e0cb77412f5991fa2695551
[sonitus.git] / src / main / java / net / pterodactylus / sonitus / data / Metadata.java
1 /*
2  * Sonitus - Metainfo.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 com.google.common.base.Optional;
21
22 /**
23  * Metadata contains information about a source, e.g. the number of channels,
24  * the frequency, the encoding, the name of the content, the artist performing
25  * it, dates, comments, URLs, etc.
26  * <p/>
27  * Metadata, once created, is immutable.
28  *
29  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
30  */
31 public class Metadata {
32
33         /** Constant for an unknown number of channels. */
34         public static final int UNKNOWN_CHANNELS = -1;
35
36         /** Constant for an unknown frequency. */
37         public static final int UNKNOWN_FREQUENCY = -1;
38
39         /** Constant for an unknown metadata. */
40         public static final String UNKNOWN_ENCODING = "UNKNOWN";
41
42         /** The number of channels of this metadata. */
43         private final int channels;
44
45         /** The sampling frequency of this metadata. */
46         private final int frequency;
47
48         /** The encoding of this metadata. */
49         private final String encoding;
50
51         /** The artist performing the content. */
52         private final Optional<String> artist;
53
54         /** The name of the content. */
55         private final Optional<String> name;
56
57         /** Creates empty metadata. */
58         public Metadata(int channels, int frequency, String encoding) {
59                 this(channels, frequency, encoding, null, null);
60         }
61
62         /**
63          * Creates metadata with the given attributes.
64          *
65          * @param artist
66          *              The artist performing the content (may be {@code null})
67          * @param name
68          *              The name of the content (may be {@code null})
69          */
70         private Metadata(int channels, int frequency, String encoding, String artist, String name) {
71                 this.channels = channels;
72                 this.frequency = frequency;
73                 this.encoding = encoding;
74                 this.artist = Optional.fromNullable(artist);
75                 this.name = Optional.fromNullable(name);
76         }
77
78         //
79         // ACCESSORS
80         //
81
82         /**
83          * Returns the number of channels of this metadata.
84          *
85          * @return The number of channels of this metadata
86          */
87         public int channels() {
88                 return channels;
89         }
90
91         /**
92          * Returns a metadata with the same parameters as this metadata and the given
93          * number of channels.
94          *
95          * @param channels
96          *              The new number of channels
97          * @return A new metadata with the given number of channels
98          */
99         public Metadata channels(int channels) {
100                 return new Metadata(channels, frequency, encoding, artist.orNull(), name.orNull());
101         }
102
103         /**
104          * Returns the sampling frequency of this metadata.
105          *
106          * @return The sampling frequency of this metadata
107          */
108         public int frequency() {
109                 return frequency;
110         }
111
112         /**
113          * Returns a new metadata with the same parameters as this metadata and the
114          * given frequency.
115          *
116          * @param frequency
117          *              The new frequency
118          * @return A new metadata with the given frequency
119          */
120         public Metadata frequency(int frequency) {
121                 return new Metadata(channels, frequency, encoding, artist.orNull(), name.orNull());
122         }
123
124         /**
125          * Returns the encoding of this metadata
126          *
127          * @return The encoding of this metadata
128          */
129         public String encoding() {
130                 return encoding;
131         }
132
133         /**
134          * Returns a new metadata with the same parameters as this metadata and the
135          * given encoding.
136          *
137          * @param encoding
138          *              The new encoding
139          * @return A new metadata with the given encoding
140          */
141         public Metadata encoding(String encoding) {
142                 return new Metadata(channels, frequency, encoding, artist.orNull(), name.orNull());
143         }
144
145         /**
146          * Returns the artist, if any.
147          *
148          * @return The artist, or {@link Optional#absent()}
149          */
150         public Optional<String> artist() {
151                 return artist;
152         }
153
154         /**
155          * Returns new metadata with the same attributes as this metadata, except for
156          * the artist.
157          *
158          * @param artist
159          *              The new artist
160          * @return New metadata with a changed artist
161          */
162         public Metadata artist(String artist) {
163                 return new Metadata(channels, frequency, encoding, artist, name.orNull());
164         }
165
166         /**
167          * Returns the name of the content, if any.
168          *
169          * @return The name, or {@link Optional#absent()}
170          */
171         public Optional<String> name() {
172                 return name;
173         }
174
175         /**
176          * Returns new metadata with the same attributes as this metadata, except for
177          * the name.
178          *
179          * @param name
180          *              The new name
181          * @return New metadata with a changed name
182          */
183         public Metadata name(String name) {
184                 return new Metadata(channels, frequency, encoding, artist.orNull(), name);
185         }
186
187         //
188         // OBJECT METHODS
189         //
190
191         @Override
192         public int hashCode() {
193                 int hashCode = (channels << 16) ^ frequency ^ encoding.toUpperCase().hashCode();
194                 if (artist.isPresent()) {
195                         hashCode ^= artist.get().hashCode();
196                 }
197                 if (name.isPresent()) {
198                         hashCode ^= name.get().hashCode();
199                 }
200                 return hashCode;
201         }
202
203         @Override
204         public boolean equals(Object object) {
205                 if ((object == null) || (getClass() != object.getClass())) {
206                         return false;
207                 }
208                 Metadata metadata = (Metadata) object;
209                 if ((metadata.channels != channels) || (metadata.frequency != frequency) || !metadata.encoding.equalsIgnoreCase(encoding())) {
210                         return false;
211                 }
212                 if (artist.equals(metadata.artist)) {
213                         return false;
214                 }
215                 if (name.equals(metadata.name)) {
216                         return false;
217                 }
218                 return true;
219         }
220
221         @Override
222         public String toString() {
223                 StringBuilder string = new StringBuilder();
224                 string.append(String.format("%d Channel%s, %d Hz, %s:", channels, channels != 1 ? "s" : "", frequency, encoding));
225                 if (artist.isPresent()) {
226                         string.append(" Artist(").append(artist.get()).append(")");
227                 }
228                 if (name.isPresent()) {
229                         string.append(" Name(").append(name.get()).append(")");
230                 }
231                 return string.toString();
232         }
233
234 }