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