48ac228bb2bb7d4fe18ebf6a8f66b04cc12f174d
[rhynodge.git] / src / main / java / net / pterodactylus / rhynodge / states / TorrentState.java
1 /*
2  * Rhynodge - TorrentState.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.rhynodge.states;
19
20 import java.nio.charset.Charset;
21 import java.util.Collection;
22 import java.util.Collections;
23 import java.util.Iterator;
24 import java.util.List;
25
26 import net.pterodactylus.rhynodge.State;
27 import net.pterodactylus.rhynodge.states.TorrentState.TorrentFile;
28
29 import org.apache.http.NameValuePair;
30 import org.apache.http.client.utils.URLEncodedUtils;
31
32 import com.fasterxml.jackson.annotation.JsonProperty;
33 import com.google.common.collect.Lists;
34
35 /**
36  * {@link State} that contains information about an arbitrary number of torrent
37  * files.
38  *
39  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
40  */
41 public class TorrentState extends AbstractState implements Iterable<TorrentFile> {
42
43         /** The torrent files. */
44         @JsonProperty
45         private List<TorrentFile> files = Lists.newArrayList();
46
47         /**
48          * Creates a new torrent state without torrent files.
49          */
50         public TorrentState() {
51                 this(Collections.<TorrentFile> emptySet());
52         }
53
54         /**
55          * Creates a new torrent state containing the given torrent files.
56          *
57          * @param torrentFiles
58          *            The torrent files
59          */
60         public TorrentState(Collection<TorrentFile> torrentFiles) {
61                 files.addAll(torrentFiles);
62         }
63
64         //
65         // ACCESSORS
66         //
67
68         @Override
69         public boolean isEmpty() {
70                 return files.isEmpty();
71         }
72
73         /**
74          * Returns all torrent files of this state.
75          *
76          * @return All torrent files of this state
77          */
78         public Collection<TorrentFile> torrentFiles() {
79                 return Collections.unmodifiableList(files);
80         }
81
82         /**
83          * Adds a torrent file to this state.
84          *
85          * @param torrentFile
86          *            The torrent file to add
87          * @return This state
88          */
89         public TorrentState addTorrentFile(TorrentFile torrentFile) {
90                 files.add(torrentFile);
91                 return this;
92         }
93
94         //
95         // ITERABLE METHODS
96         //
97
98         /**
99          * {@inheritDoc}
100          */
101         @Override
102         public Iterator<TorrentFile> iterator() {
103                 return files.iterator();
104         }
105
106         //
107         // OBJECT METHODS
108         //
109
110         /**
111          * {@inheritDoc}
112          */
113         @Override
114         public String toString() {
115                 return String.format("%s[files=%s]", getClass().getSimpleName(), files);
116         }
117
118         /**
119          * Container for torrent file data.
120          *
121          * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
122          */
123         public static class TorrentFile {
124
125                 /** The name of the file. */
126                 @JsonProperty
127                 private final String name;
128
129                 /** The size of the file. */
130                 @JsonProperty
131                 private final String size;
132
133                 /** The magnet URI of the file. */
134                 @JsonProperty
135                 private final String magnetUri;
136
137                 /** The download URI of the file. */
138                 @JsonProperty
139                 private final String downloadUri;
140
141                 /** The number of files in this torrent. */
142                 @JsonProperty
143                 private final int fileCount;
144
145                 /** The number of seeds connected to this torrent. */
146                 @JsonProperty
147                 private final int seedCount;
148
149                 /** The number of leechers connected to this torrent. */
150                 @JsonProperty
151                 private final int leechCount;
152
153                 /**
154                  * No-arg constructor for deserialization.
155                  */
156                 @SuppressWarnings("unused")
157                 private TorrentFile() {
158                         this(null, null, null, null, 0, 0, 0);
159                 }
160
161                 /**
162                  * Creates a new torrent file.
163                  *
164                  * @param name
165                  *            The name of the file
166                  * @param size
167                  *            The size of the file
168                  * @param magnetUri
169                  *            The magnet URI of the file
170                  * @param downloadUri
171                  *            The download URI of the file
172                  * @param fileCount
173                  *            The number of files
174                  * @param seedCount
175                  *            The number of connected seeds
176                  * @param leechCount
177                  *            The number of connected leechers
178                  */
179                 public TorrentFile(String name, String size, String magnetUri, String downloadUri, int fileCount, int seedCount, int leechCount) {
180                         this.name = name;
181                         this.size = size;
182                         this.magnetUri = magnetUri;
183                         this.downloadUri = downloadUri;
184                         this.fileCount = fileCount;
185                         this.seedCount = seedCount;
186                         this.leechCount = leechCount;
187                 }
188
189                 //
190                 // ACCESSORS
191                 //
192
193                 /**
194                  * Returns the name of the file.
195                  *
196                  * @return The name of the file
197                  */
198                 public String name() {
199                         return name;
200                 }
201
202                 /**
203                  * Returns the size of the file. The returned size may included
204                  * non-numeric information, such as units (e. g. “860.46 MB”).
205                  *
206                  * @return The size of the file
207                  */
208                 public String size() {
209                         return size;
210                 }
211
212                 /**
213                  * Returns the magnet URI of the file.
214                  *
215                  * @return The magnet URI of the file, or {@code null} if there is no
216                  *         magnet URI for this torrent file
217                  */
218                 public String magnetUri() {
219                         return magnetUri;
220                 }
221
222                 /**
223                  * Returns the download URI of the file.
224                  *
225                  * @return The download URI of the file, or {@code null} if there is no
226                  *         download URI for this torrent file
227                  */
228                 public String downloadUri() {
229                         return downloadUri;
230                 }
231
232                 /**
233                  * Returns the number of files in this torrent.
234                  *
235                  * @return The number of files in this torrent
236                  */
237                 public int fileCount() {
238                         return fileCount;
239                 }
240
241                 /**
242                  * Returns the number of seeds connected to this torrent.
243                  *
244                  * @return The number of connected seeds
245                  */
246                 public int seedCount() {
247                         return seedCount;
248                 }
249
250                 /**
251                  * Returns the number of leechers connected to this torrent.
252                  *
253                  * @return The number of connected leechers
254                  */
255                 public int leechCount() {
256                         return leechCount;
257                 }
258
259                 //
260                 // PRIVATE METHODS
261                 //
262
263                 /**
264                  * Generates an ID for this file. If a {@link #magnetUri} is set, an ID
265                  * is {@link #extractId(String) extracted} from it. Otherwise the magnet
266                  * URI is used. If the {@link #magnetUri} is not set, the
267                  * {@link #downloadUri} is used. If that is not set either, the name of
268                  * the file is returned.
269                  *
270                  * @return The generated ID
271                  */
272                 private String generateId() {
273                         if (magnetUri != null) {
274                                 String id = extractId(magnetUri);
275                                 if (id != null) {
276                                         return id;
277                                 }
278                                 return magnetUri;
279                         }
280                         return (downloadUri != null) ? downloadUri : name;
281                 }
282
283                 //
284                 // STATIC METHODS
285                 //
286
287                 /**
288                  * Tries to extract the “exact target” of a magnet URI.
289                  *
290                  * @param magnetUri
291                  *            The magnet URI to extract the “xt” from
292                  * @return The extracted ID, or {@code null} if no ID could be found
293                  */
294                 private static String extractId(String magnetUri) {
295                         List<NameValuePair> parameters = URLEncodedUtils.parse(magnetUri.substring("magnet:?".length()), Charset.forName("UTF-8"));
296                         for (NameValuePair parameter : parameters) {
297                                 if (parameter.getName().equals("xt")) {
298                                         return parameter.getValue().toLowerCase();
299                                 }
300                         }
301                         return null;
302                 }
303
304                 //
305                 // OBJECT METHODS
306                 //
307
308                 /**
309                  * {@inheritDoc}
310                  */
311                 @Override
312                 public int hashCode() {
313                         return (generateId() != null) ? generateId().hashCode() : 0;
314                 }
315
316                 /**
317                  * {@inheritDoc}
318                  */
319                 @Override
320                 public boolean equals(Object object) {
321                         if (!(object instanceof TorrentFile)) {
322                                 return false;
323                         }
324                         if (generateId() != null) {
325                                 return generateId().equals(((TorrentFile) object).generateId());
326                         }
327                         return false;
328                 }
329
330                 /**
331                  * {@inheritDoc}
332                  */
333                 @Override
334                 public String toString() {
335                         return String.format("%s(%s,%s,%s)", name(), size(), magnetUri(), downloadUri());
336                 }
337
338         }
339
340 }