Minor UI change.
[pithos-macos] / pithos-macos / PithosActivityFacility.m
1 //
2 //  PithosActivityFacility.m
3 //  pithos-macos
4 //
5 // Copyright 2011-2012 GRNET S.A. All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or
8 // without modification, are permitted provided that the following
9 // conditions are met:
10 // 
11 //   1. Redistributions of source code must retain the above
12 //      copyright notice, this list of conditions and the following
13 //      disclaimer.
14 // 
15 //   2. Redistributions in binary form must reproduce the above
16 //      copyright notice, this list of conditions and the following
17 //      disclaimer in the documentation and/or other materials
18 //      provided with the distribution.
19 // 
20 // THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
21 // OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
24 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
27 // USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 // AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 // POSSIBILITY OF SUCH DAMAGE.
32 // 
33 // The views and conclusions contained in the software and
34 // documentation are those of the authors and should not be
35 // interpreted as representing official policies, either expressed
36 // or implied, of GRNET S.A.
37
38 #import "PithosActivityFacility.h"
39 #import "PithosAccount.h"
40 #import "pithos_macosAppDelegate.h"
41
42 static PithosActivityFacility *defaultPithosActivityFacility = nil;
43
44 @implementation PithosActivityFacility
45 @synthesize delegate;
46
47 #pragma mark -
48 #pragma mark - Singleton
49
50 + (id)defaultPithosActivityFacility {
51         @synchronized(self) {
52                 if (!defaultPithosActivityFacility)
53                         [[self alloc] init]; // Assignment not done here
54         }
55         return defaultPithosActivityFacility;
56 }
57
58 + (id)allocWithZone:(NSZone *)zone {
59     @synchronized(self) {
60         if (!defaultPithosActivityFacility) {
61             defaultPithosActivityFacility = [super allocWithZone:zone];
62             return defaultPithosActivityFacility;
63         }
64     }
65     return nil;
66 }
67
68 - (id)copyWithZone:(NSZone *)zone {
69     return self;
70 }
71
72 - (id)retain {
73     return self;
74 }
75
76 - (NSUInteger)retainCount {
77     return UINT_MAX; // Can not be released
78 }
79
80 - (void)release {
81     // Do nothing
82 }
83
84 - (id)autorelease {
85     return self;
86 }
87
88 #pragma mark -
89 #pragma mark Object Lifecycle
90
91 - (id)init {
92     if ((self = [super init])) {
93         [self reset];
94     }
95     return self;
96 }
97
98 - (void)dealloc {
99     [timer invalidate];
100     [timer release];
101     [runningActivities release];
102     [endingActivities release];
103     [super dealloc];
104 }
105
106 - (void)reset {
107     @synchronized(self) {
108         [timer invalidate];
109         [timer release];
110         
111         [runningActivities release];
112         runningActivities = [[NSMutableArray alloc] init];
113         [endingActivities release];
114         endingActivities = [[NSMutableArray alloc] init];
115         totalUploadBytes = 0;
116         currentUploadBytes = 0;
117         totalDownloadBytes = 0;
118         currentDownloadBytes = 0;
119         
120         pickedRunning = NO;
121         
122         timer = [[NSTimer scheduledTimerWithTimeInterval:[(pithos_macosAppDelegate *)[[NSApplication sharedApplication] delegate] activityFacilityTimeInterval] 
123                                                   target:self 
124                                                 selector:@selector(update:) 
125                                                 userInfo:nil 
126                                                  repeats:YES] retain];
127     }
128 }
129
130 - (NSString *)description {
131     return [NSString stringWithFormat:@"running activities: %lu, ending activities: %lu, totalUploadBytes: %lu, currentUploadBytes: %lu, totalDownloadBytes: %lu, currentDownloadBytes: %lu", 
132             [runningActivities count], [endingActivities count], totalUploadBytes, currentUploadBytes, totalDownloadBytes, currentDownloadBytes];
133 }
134
135 #pragma mark -
136 #pragma mark Timer
137
138 - (void)update:(NSTimer *)aTimer {
139     NSMutableDictionary *info = [NSMutableDictionary dictionary];
140     @synchronized(self) {
141         PithosActivity *activity = nil;
142         NSUInteger endingActivitiesCount = [endingActivities count];
143         NSUInteger runningActivitiesCount = [runningActivities count];
144         if ((pickedRunning || !runningActivitiesCount) && endingActivitiesCount) {
145             NSUInteger index;
146             for (index = 0 ; index < endingActivitiesCount; index++) {
147                 activity = [endingActivities objectAtIndex:index];
148                 switch (activity.type) {
149                     case PithosActivityUpload:
150                         totalUploadBytes -= activity.totalBytes;
151                         currentUploadBytes -= activity.currentBytes;
152                         break;
153                     case PithosActivityDownload:
154                         totalDownloadBytes -= activity.totalBytes;
155                         currentDownloadBytes -= activity.currentBytes;
156                         break;
157                     default:
158                         break;
159                 }
160                 if (activity.message)
161                     break;
162             }
163             [activity retain];
164             [endingActivities removeObjectsInRange:NSMakeRange(0, (index + 1))];
165             pickedRunning = NO;
166         } else if (runningActivitiesCount) {
167             NSUInteger count;
168             for (count = 0 ; count < runningActivitiesCount; count++) {
169                 activity = [[runningActivities objectAtIndex:0] retain];
170                 [runningActivities removeObjectAtIndex:0];
171                 [runningActivities addObject:activity];
172                 if (activity.message) {
173                     break;
174                 } else {
175                     [activity release];
176                     activity = nil;
177                 }
178             }
179             pickedRunning = YES;
180         }
181         if (activity && activity.message) {
182             if (activity.pithosAccount)
183                 [info setObject:[NSString stringWithFormat:@"[%@] %@", activity.pithosAccount.name, activity.message] forKey:@"message"];
184             else
185                 [info setObject:activity.message forKey:@"message"];
186         }
187         [info setObject:[NSNumber numberWithUnsignedInteger:[runningActivities count]] forKey:@"runningActivitiesCount"];
188         [info setObject:[NSNumber numberWithUnsignedInteger:[endingActivities count]] forKey:@"endingActivitiesCount"];
189         [info setObject:[NSNumber numberWithUnsignedInteger:totalUploadBytes] forKey:@"totalUploadBytes"];
190         [info setObject:[NSNumber numberWithUnsignedInteger:currentUploadBytes] forKey:@"currentUploadBytes"];
191         [info setObject:[NSNumber numberWithUnsignedInteger:totalDownloadBytes] forKey:@"totalDownloadBytes"];
192         [info setObject:[NSNumber numberWithUnsignedInteger:currentDownloadBytes] forKey:@"currentDownloadBytes"];
193         [activity release];
194     }
195     if (delegate) {
196         [delegate activityUpdate:info];
197     }
198 }
199
200 #pragma mark -
201 #pragma mark Activity Actions
202
203 - (PithosActivity *)startActivityWithType:(PithosActivityType)type 
204                                   message:(NSString *)message 
205                                totalBytes:(NSUInteger)totalBytes 
206                              currentBytes:(NSUInteger)currentBytes 
207                             pithosAccount:(PithosAccount *)pithosAccount {
208     PithosActivity *activity = [[[PithosActivity alloc] initWithType:type pithosAccount:pithosAccount] autorelease];
209     activity.message = message;
210     activity.totalBytes = totalBytes;
211     activity.currentBytes = currentBytes;
212     NSLog(@"PithosActivityFacility startedActivity %@", activity);
213     
214     switch (type) {
215         case PithosActivityUpload:
216             @synchronized(self) {
217                 totalUploadBytes += totalBytes;
218                 currentUploadBytes += currentBytes;
219             }
220             break;
221         case PithosActivityDownload:
222             @synchronized(self) {
223                 totalDownloadBytes += totalBytes;
224                 currentDownloadBytes += currentBytes;
225             }
226             break;
227         default:
228             break;
229     }
230     
231     @synchronized(self) {
232         [runningActivities addObject:activity];
233     }
234     NSLog(@"PithosActivityFacility %@", self);
235     
236     return activity;
237 }
238
239 - (PithosActivity *)startActivityWithType:(PithosActivityType)type 
240                                   message:(NSString *)message 
241                                totalBytes:(NSUInteger)totalBytes 
242                              currentBytes:(NSUInteger)currentBytes {
243     return [self startActivityWithType:type message:message totalBytes:totalBytes currentBytes:currentBytes pithosAccount:nil];
244 }
245
246 - (PithosActivity *)startActivityWithType:(PithosActivityType)type 
247                                   message:(NSString *)message 
248                             pithosAccount:(PithosAccount *)pithosAccount {
249     return [self startActivityWithType:type message:message totalBytes:0 currentBytes:0 pithosAccount:pithosAccount];
250 }
251
252 - (PithosActivity *)startActivityWithType:(PithosActivityType)type 
253                                   message:(NSString *)message {
254     return [self startActivityWithType:type message:message pithosAccount:nil];
255 }
256
257 - (PithosActivity *)startAndEndActivityWithType:(PithosActivityType)type 
258                                         message:(NSString *)message 
259                                   pithosAccount:(PithosAccount *)pithosAccount {
260     PithosActivity *activity = [[[PithosActivity alloc] initWithType:type pithosAccount:pithosAccount] autorelease];
261     activity.message = message;
262     activity.totalBytes = 0;
263     activity.currentBytes = 0;
264     @synchronized(self) {
265         [endingActivities addObject:activity];
266     }
267     NSLog(@"PithosActivityFacility startedAndEndedActivity %@", activity);
268     
269     return activity;
270 }
271
272 - (PithosActivity *)startAndEndActivityWithType:(PithosActivityType)type message:(NSString *)message {
273     return [self startAndEndActivityWithType:type message:message pithosAccount:nil];
274 }
275
276 - (void)updateActivity:(PithosActivity *)activity 
277            withMessage:(NSString *)message 
278             totalBytes:(NSUInteger)totalBytes 
279           currentBytes:(NSUInteger)currentBytes {
280     if (!activity)
281         return;
282     NSLog(@"PithosActivityFacility updatedActivity %@", activity);
283     @synchronized(self) {
284         activity.message = message;
285         switch (activity.type) {
286             case PithosActivityUpload:
287                 totalUploadBytes += totalBytes - activity.totalBytes;
288                 activity.totalBytes = totalBytes;
289                 currentUploadBytes += currentBytes - activity.currentBytes;
290                 activity.currentBytes = currentBytes;
291                 break;
292             case PithosActivityDownload:
293                 totalDownloadBytes += totalBytes - activity.totalBytes;
294                 activity.totalBytes = totalBytes;
295                 currentDownloadBytes += currentBytes - activity.currentBytes;
296                 activity.currentBytes = currentBytes;
297                 break;
298             default:
299                 break;
300         }
301     }
302     NSLog(@"PithosActivityFacility %@", self);
303 }
304
305 - (void)updateActivity:(PithosActivity *)activity 
306            withMessage:(NSString *)message {
307     [self updateActivity:activity withMessage:message totalBytes:activity.totalBytes currentBytes:activity.currentBytes];
308 }
309
310 - (void)endActivity:(PithosActivity *)activity 
311         withMessage:(NSString *)message 
312          totalBytes:(NSUInteger)totalBytes 
313        currentBytes:(NSUInteger)currentBytes {
314     if (!activity)
315         return;
316     @synchronized(self) {
317         [runningActivities removeObject:activity];
318         activity.message = message;
319         switch (activity.type) {
320             case PithosActivityUpload:
321                 totalUploadBytes += totalBytes - activity.totalBytes;
322                 activity.totalBytes = totalBytes;
323                 currentUploadBytes += currentBytes - activity.currentBytes;
324                 activity.currentBytes = currentBytes;
325                 break;
326             case PithosActivityDownload:
327                 totalDownloadBytes += totalBytes - activity.totalBytes;
328                 activity.totalBytes = totalBytes;
329                 currentDownloadBytes += currentBytes - activity.currentBytes;
330                 activity.currentBytes = currentBytes;
331                 break;
332             default:
333                 break;
334         }
335         [endingActivities addObject:activity];
336     }
337     NSLog(@"PithosActivityFacility endedActivity %@", activity);
338     NSLog(@"PithosActivityFacility %@", self);
339 }
340
341 - (void)endActivity:(PithosActivity *)activity 
342         withMessage:(NSString *)message {
343     [self endActivity:activity withMessage:message totalBytes:activity.totalBytes currentBytes:activity.currentBytes];
344 }
345
346 @end