1/******************************************************************************
2 * $Id: TrackerNode.m 13251 2012-03-13 02:52:11Z livings124 $
3 *
4 * Copyright (c) 2009-2012 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#import "TrackerNode.h"
26#import "NSStringAdditions.h"
27
28@implementation TrackerNode
29
30#warning remove ivars in header when 64-bit only (or it compiles in 32-bit mode)
31@synthesize torrent = fTorrent;
32
33- (id) initWithTrackerStat: (tr_tracker_stat *) stat torrent: (Torrent *) torrent
34{
35    if ((self = [super init]))
36    {
37        fStat = *stat;
38        fTorrent = torrent; //weak reference
39    }
40    
41    return self;
42}
43
44- (NSString *) description
45{
46    return [@"Tracker: " stringByAppendingString: [self fullAnnounceAddress]];
47}
48
49- (id) copyWithZone: (NSZone *) zone
50{
51    //this object is essentially immutable after initial setup
52    return [self retain];
53}
54
55- (BOOL) isEqual: (id) object
56{
57    if (self == object)
58        return YES;
59    
60    if (![object isKindOfClass: [self class]])
61        return NO;
62    
63    if ([self torrent] != [object torrent])
64        return NO;
65    
66    return [self tier] == [object tier] && [[self fullAnnounceAddress] isEqualToString: [object fullAnnounceAddress]];
67}
68
69- (NSString *) host
70{
71    return [NSString stringWithUTF8String: fStat.host];
72}
73
74- (NSString *) fullAnnounceAddress
75{
76    return [NSString stringWithUTF8String: fStat.announce];
77}
78
79- (NSInteger) tier
80{
81    return fStat.tier;
82}
83
84- (NSUInteger) identifier
85{
86    return fStat.id;
87}
88
89- (NSInteger) totalSeeders
90{
91    return fStat.seederCount;
92}
93
94- (NSInteger) totalLeechers
95{
96    return fStat.leecherCount;
97}
98
99- (NSInteger) totalDownloaded
100{
101    return fStat.downloadCount;
102}
103
104- (NSString *) lastAnnounceStatusString
105{
106    NSString * dateString;
107    if (fStat.hasAnnounced)
108    {
109        NSDateFormatter * dateFormatter = [[NSDateFormatter alloc] init];
110        [dateFormatter setDateStyle: NSDateFormatterFullStyle];
111        [dateFormatter setTimeStyle: NSDateFormatterShortStyle];
112        [dateFormatter setDoesRelativeDateFormatting: YES];
113        
114        dateString = [dateFormatter stringFromDate: [NSDate dateWithTimeIntervalSince1970: fStat.lastAnnounceTime]];
115        [dateFormatter release];
116    }
117    else
118        dateString = NSLocalizedString(@"N/A", "Tracker last announce");
119    
120    NSString * baseString;
121    if (fStat.hasAnnounced && fStat.lastAnnounceTimedOut)
122        baseString = [NSLocalizedString(@"Announce timed out", "Tracker last announce") stringByAppendingFormat: @": %@", dateString];
123    else if (fStat.hasAnnounced && !fStat.lastAnnounceSucceeded)
124    {
125        baseString = NSLocalizedString(@"Announce error", "Tracker last announce");
126        
127        NSString * errorString = [NSString stringWithUTF8String: fStat.lastAnnounceResult];
128        if ([errorString isEqualToString: @""])
129            baseString = [baseString stringByAppendingFormat: @": %@", dateString];
130        else
131            baseString = [baseString stringByAppendingFormat: @": %@ - %@", errorString, dateString];
132    }
133    else
134    {
135        baseString = [NSLocalizedString(@"Last Announce", "Tracker last announce") stringByAppendingFormat: @": %@", dateString];
136        if (fStat.hasAnnounced && fStat.lastAnnounceSucceeded && fStat.lastAnnouncePeerCount > 0)
137        {
138            NSString * peerString;
139            if (fStat.lastAnnouncePeerCount == 1)
140                peerString = NSLocalizedString(@"got 1 peer", "Tracker last announce");
141            else
142                peerString = [NSString stringWithFormat: NSLocalizedString(@"got %d peers", "Tracker last announce"),
143                                        fStat.lastAnnouncePeerCount];
144            baseString = [baseString stringByAppendingFormat: @" (%@)", peerString];
145        }
146    }
147    
148    return baseString;
149}
150
151- (NSString *) nextAnnounceStatusString
152{
153    switch (fStat.announceState)
154    {
155        case TR_TRACKER_ACTIVE:
156            return [NSLocalizedString(@"Announce in progress", "Tracker next announce") stringByAppendingEllipsis];
157        
158        case TR_TRACKER_WAITING:
159            return [NSString stringWithFormat: NSLocalizedString(@"Next announce in %@", "Tracker next announce"),
160                    [NSString timeString: fStat.nextAnnounceTime - [[NSDate date] timeIntervalSince1970] showSeconds: YES]];
161        
162        case TR_TRACKER_QUEUED:
163            return [NSLocalizedString(@"Announce is queued", "Tracker next announce") stringByAppendingEllipsis];
164        
165        case TR_TRACKER_INACTIVE:
166            return fStat.isBackup ? NSLocalizedString(@"Tracker will be used as a backup", "Tracker next announce")
167                                    : NSLocalizedString(@"Announce not scheduled", "Tracker next announce");
168        
169        default:
170            NSAssert1(NO, @"unknown announce state: %d", fStat.announceState);
171            return nil;
172    }
173}
174
175- (NSString *) lastScrapeStatusString
176{
177    NSString * dateString;
178    if (fStat.hasScraped)
179    {
180        NSDateFormatter * dateFormatter = [[NSDateFormatter alloc] init];
181        [dateFormatter setDateStyle: NSDateFormatterFullStyle];
182        [dateFormatter setTimeStyle: NSDateFormatterShortStyle];
183        [dateFormatter setDoesRelativeDateFormatting: YES];
184        
185        dateString = [dateFormatter stringFromDate: [NSDate dateWithTimeIntervalSince1970: fStat.lastScrapeTime]];
186        [dateFormatter release];
187    }
188    else
189        dateString = NSLocalizedString(@"N/A", "Tracker last scrape");
190    
191    NSString * baseString;
192    if (fStat.hasScraped && fStat.lastScrapeTimedOut)
193        baseString = [NSLocalizedString(@"Scrape timed out", "Tracker last scrape") stringByAppendingFormat: @": %@", dateString];
194    else if (fStat.hasScraped && !fStat.lastScrapeSucceeded)
195    {
196        baseString = NSLocalizedString(@"Scrape error", "Tracker last scrape");
197        
198        NSString * errorString = [NSString stringWithUTF8String: fStat.lastScrapeResult];
199        if ([errorString isEqualToString: @""])
200            baseString = [baseString stringByAppendingFormat: @": %@", dateString];
201        else
202            baseString = [baseString stringByAppendingFormat: @": %@ - %@", errorString, dateString];
203    }
204    else
205        baseString = [NSLocalizedString(@"Last Scrape", "Tracker last scrape") stringByAppendingFormat: @": %@", dateString];
206    
207    return baseString;
208}
209
210@end
211