//
//  PithosAccountNode.m
//  pithos-macos
//
// Copyright 2011-2012 GRNET S.A. All rights reserved.
//
// Redistribution and use in source and binary forms, with or
// without modification, are permitted provided that the following
// conditions are met:
// 
//   1. Redistributions of source code must retain the above
//      copyright notice, this list of conditions and the following
//      disclaimer.
// 
//   2. Redistributions in binary form must reproduce the above
//      copyright notice, this list of conditions and the following
//      disclaimer in the documentation and/or other materials
//      provided with the distribution.
// 
// THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
// 
// The views and conclusions contained in the software and
// documentation are those of the authors and should not be
// interpreted as representing official policies, either expressed
// or implied, of GRNET S.A.

#import "PithosSharingAccountsNode.h"
#import "PithosAccountNode.h"
#import "ASIPithosRequest.h"
#import "ASIPithos.h"
#import "ASIPithosAccount.h"
#import "ASIDownloadCache.h"
#import "PithosUtilities.h"
#import "PithosActivityFacility.h"

@implementation PithosSharingAccountsNode
@synthesize pithos;

#pragma mark -
#pragma mark Object Lifecycle

- (id)initWithPithos:(ASIPithos *)aPithos {
    if ((self = [super init])) {
        self.pithos = aPithos;
        self.sharingAccount = @"";
        self.childrenUpdatedNotificationName = [NSString stringWithString:@"PithosSharingAccountsNodeChildrenUpdated"];
    }
    return self;
}

- (void)dealloc {
    [sharingAccountsRequest clearDelegatesAndCancel];
    [sharingAccountsRequest release];
    [sharingAccounts release];
    [pithos release];
    [super dealloc];
}

#pragma mark -
#pragma mark Properties

- (void)setPithos:(ASIPithos *)aPithos {
    if (aPithos && ![aPithos isEqualTo:pithos]) {
        [pithos release];
        pithos = [aPithos retain];
        [url release];
        url = nil;
    }
}

- (NSString *)url {
    if (url == nil) 
        url = [pithos.storageURLPrefix copy];
    return url;
}

- (NSArray *)children {
    @synchronized(self) {
        switch (freshness) {
            case PithosNodeStateFresh:
                break;
            case PithosNodeStateRefreshNeeded:
                freshness = PithosNodeStateRefreshing;
                sharingAccountsRequest = [[ASIPithosRequest listSharingAccountsRequestWithPithos:pithos limit:0 marker:nil] retain];
                sharingAccountsRequest.delegate = self;
                sharingAccountsRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
                sharingAccountsRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
                sharingAccountsRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                                   [NSNumber numberWithInteger:NSOperationQueuePriorityVeryHigh], @"priority", 
                                                   [NSNumber numberWithUnsignedInteger:10], @"retries", 
                                                   NSStringFromSelector(@selector(sharingAccountsRequestFinished:)), @"didFinishSelector", 
                                                   NSStringFromSelector(@selector(sharingAccountsRequestFailed:)), @"didFailSelector", 
                                                   nil];
                if (!forcedRefresh)
                    sharingAccountsRequest.downloadCache = [ASIDownloadCache sharedCache];
                [[PithosUtilities prepareRequest:sharingAccountsRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
                break;
            case PithosNodeStateRefreshing:
                break;
            case PithosNodeStateRefreshFinished:
                if (newChildren) {
                    [children release];
                    children = newChildren;
                    newChildren = nil;
                }
                freshness = PithosNodeStateFresh;
            default:
                break;
        }
        return children;
    }
}

- (NSString *)displayName {
    if (displayName == nil)
        return [NSString stringWithString:@"sharing accounts"];
    return [[displayName copy] autorelease];
}

#pragma mark -
#pragma mark ASIHTTPRequestDelegate

- (void)sharingAccountsRequestFailed:(ASIPithosRequest *)request {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSUInteger retries = [[sharingAccountsRequest.userInfo objectForKey:@"retries"] unsignedIntegerValue];
    if (retries > 0) {
        ASIPithosRequest *newSharingAccountsRequest = (ASIPithosRequest *)[PithosUtilities copyRequest:sharingAccountsRequest];
        [(NSMutableDictionary *)(newSharingAccountsRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"];
        [sharingAccountsRequest release];
        sharingAccountsRequest = newSharingAccountsRequest;
        [[PithosUtilities prepareRequest:sharingAccountsRequest priority:[[sharingAccountsRequest.userInfo objectForKey:@"priority"] integerValue]] startAsynchronous];
    } else {
        NSString *message;
        NSError *error = [sharingAccountsRequest error];
        if (error)
            message = [NSString stringWithFormat:@"Sharing accounts listing failed: %@", error];
        else
            message = [NSString stringWithFormat:@"Sharing accounts listing failed: (%d) %@", 
                       sharingAccountsRequest.responseStatusCode, sharingAccountsRequest.responseStatusMessage];
        dispatch_async(dispatch_get_main_queue(), ^{
            [[PithosActivityFacility defaultPithosActivityFacility] startAndEndActivityWithType:PithosActivityOther message:message];
        });
        [newChildren release];
        newChildren = nil;
        [sharingAccountsRequest release];
        sharingAccountsRequest = nil;
        [sharingAccounts release];
        sharingAccounts = nil;
        forcedRefresh = NO;
        @synchronized(self) {
            freshness = PithosNodeStateRefreshNeeded;
        }
    }
    [pool drain];
}

- (void)sharingAccountsRequestFinished:(ASIPithosRequest *)request {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSLog(@"List sharing accounts finished: %@", [sharingAccountsRequest url]);
    NSLog(@"Cached: %d", [sharingAccountsRequest didUseCachedResponse]);
    if (sharingAccountsRequest.responseStatusCode == 200) {
        NSArray *someSharingAccounts = [sharingAccountsRequest sharingAccounts];
        if (sharingAccounts == nil) {
            sharingAccounts = [[NSMutableArray alloc] initWithArray:someSharingAccounts];
        } else {
            [sharingAccounts addObjectsFromArray:someSharingAccounts];
        }
        if ([someSharingAccounts count] < 10000) {
            if (!sharingAccountsRequest.didUseCachedResponse || ([sharingAccounts count] != [someSharingAccounts count]) || !children) {
                // Save new children
                NSLog(@"using newChildren");
                newChildren = [[NSMutableArray alloc] init];
                NSMutableIndexSet *keptNodes = [NSMutableIndexSet indexSet];
                for (ASIPithosAccount *account in sharingAccounts) {
                    if (![account.name isEqualToString:pithos.authUser]) {
                        PithosAccountNode *node = [[[PithosAccountNode alloc] init] autorelease];
                        node.parent = self;
                        node.shared = shared;
                        node.sharingAccount = account.name;
                        if (children) {
                            NSUInteger oldIndex = [children indexOfObject:node];
                            if (oldIndex != NSNotFound) {
                                // Use the same pointer value, if possible
                                node = [children objectAtIndex:oldIndex];
                                [keptNodes addIndex:oldIndex];
                            }
                        }
                        [newChildren addObject:node];
                    }
                }
                [[children objectsAtIndexes:
                  [[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [children count])] indexesPassingTest:^(NSUInteger idx, BOOL *stop){
                    if ([keptNodes containsIndex:idx])
                        return NO;
                    return YES;
                }]] makeObjectsPerformSelector:@selector(pithosNodeWillBeRemoved)];
            }
            // Else cache was used and all results were fetched during this request, so existing children can be reused
            [sharingAccountsRequest release];
            sharingAccountsRequest = nil;
            [sharingAccounts release];
            sharingAccounts = nil;
            forcedRefresh = NO;
            @synchronized(self) {
                freshness = PithosNodeStateRefreshFinished;
            }
            if (childrenUpdatedNotificationName) {
                // Notify observers that children are updated
                [[NSNotificationCenter defaultCenter] postNotificationName:childrenUpdatedNotificationName object:self];
            }
        } else {
            [sharingAccountsRequest release];
            // Do an additional request to fetch more objects
            sharingAccountsRequest = [[ASIPithosRequest listSharingAccountsRequestWithPithos:pithos 
                                                                                       limit:0 
                                                                                      marker:[[someSharingAccounts lastObject] name]] retain];
            sharingAccountsRequest.delegate = self;
            sharingAccountsRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
            sharingAccountsRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
            sharingAccountsRequest.userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                               [NSNumber numberWithInteger:NSOperationQueuePriorityVeryHigh], @"priority", 
                                               [NSNumber numberWithUnsignedInteger:10], @"retries", 
                                               NSStringFromSelector(@selector(sharingAccountsRequestFinished:)), @"didFinishSelector", 
                                               NSStringFromSelector(@selector(sharingAccountsRequestFailed:)), @"didFailSelector", 
                                               nil];
            if (!forcedRefresh)
                sharingAccountsRequest.downloadCache = [ASIDownloadCache sharedCache];
            [[PithosUtilities prepareRequest:sharingAccountsRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
        }
    } else {
        [self sharingAccountsRequestFailed:sharingAccountsRequest];
    }
    [pool drain];
}

@end
