/*
SRDownloadManager.m

Author: Makoto Kinoshita

Copyright 2004-2006 The Shiira Project. 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 THE SHIIRA PROJECT ``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 THE SHIIRA PROJECT 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.
*/

#import <Growl/Growl.h>

#import "SRDownloader.h"

#import "SRDownloadController.h"
#import "SRDownloadManager.h"

#import "SRPrefDefaultKeys.h"

// Notificatioin names
NSString*    SRDownloadAddedNotification = @"SRDownloadAddedNotification";
NSString*    SRDownloadRemovedNotification = @"SRDownloadRemovedNotification";
NSString*    SRDownloadStatusChangedNotification = @"SRDownloadStatusChangedNotification";

@implementation SRDownloadManager

//--------------------------------------------------------------//
#pragma mark -- Initialize --
//--------------------------------------------------------------//

+ (id)sharedInstance
{
    static SRDownloadManager*   _sharedInstance = nil;
    if (!_sharedInstance) {
        _sharedInstance = [[SRDownloadManager alloc] init];
    }
    
    return _sharedInstance;
}

- (id)init
{
    self = [super init];
    if (!self) {
        return nil;
    }
    
	// Initialize instance variables
	_downloaders = [[NSMutableArray array] retain];
    
	_statusChangedItems = [[NSMutableArray array] retain];
	
    return self;
}

- (void)dealloc
{
	[_downloaders release], _downloaders = nil;
	[_statusChangedItems release];
	
    [super dealloc];
}

- (void)_scheduleUpdateTimer
{
#if 0
    static const NSTimeInterval   _updatePeriod = 0.5;
    [_updateTimer invalidate];
    
    // Start the new timer
    // The timer is retained by the runloop, no need to retain it here.
    _updateTimer = [NSTimer scheduledTimerWithTimeInterval:_updatePeriod 
        target:self 
        selector:@selector(updateTimerExpired:) 
        userInfo:nil 
        repeats:YES];
#endif
}

- (void)updateTimerExpired:(id)userInfo
{
    // For status changing active item
    if ([_statusChangedItems count] > 0) {
        // Notify status changed
        [[NSNotificationCenter defaultCenter] 
                postNotificationName:SRDownloadStatusChangedNotification 
                object:_statusChangedItems];
        
        [_statusChangedItems removeAllObjects];
    }
}

//--------------------------------------------------------------//
#pragma mark -- Notifications --
//--------------------------------------------------------------//

- (void)_notifyAddition:(SRDownloadHistoryItem*)historyItem
{
	// Notify addition
	[[NSNotificationCenter defaultCenter] 
			postNotificationName:SRDownloadAddedNotification 
			object:[NSArray arrayWithObject:historyItem]];
}

- (void)_notifyRemoval:(SRDownloadHistoryItem*)historyItem
{
	// Notify removal
	[[NSNotificationCenter defaultCenter] 
			postNotificationName:SRDownloadRemovedNotification 
			object:[NSArray arrayWithObject:historyItem]];
}

//--------------------------------------------------------------//
#pragma mark -- Download items --
//--------------------------------------------------------------//

- (NSArray*)downloaders
{
	return _downloaders;
}

- (SRDownloader*)downladerForDownlaod:(NSURLDownload*)download
{
    NSEnumerator*   enumerator;
    SRDownloader*   downloader;
    enumerator = [_downloaders objectEnumerator];
    while (downloader = [enumerator nextObject]) {
        if ([downloader download] == download) {
            return downloader;
        }
    }
    
    return nil;
}

//--------------------------------------------------------------//
#pragma mark -- Download management --
//--------------------------------------------------------------//

- (void)pauseDownloadForItem:(SRDownloadHistoryItem*)item
{
#if 0
    // Get download for item
    NSURLDownload*          download;
    SRDownloadItemStatus    status;
    download = [item download];
    if (!download) {
        return;
    }
    status = [item status];
    
    // Check download status
    if (status != SRDownloadStatusActive) {
        return;
    }
    
    // Pause download
    [download _setDeletesFileAfterFailure:NO];
    [download cancel];
    
    // Make status paused
    [item setStatus:SRDownloadStatusPaused];
    
    // Set resume info
    id  resumeInfo;
    resumeInfo = [download _resumeInformation];
    [item setResumeInfo:resumeInfo];
#endif
}

- (void)resumeDownloadForItem:(SRDownloadHistoryItem*)item
{
#if 0
    // Check download status
    SRDownloadItemStatus    status;
    status = [item status];
    if (status != SRDownloadStatusPaused) {
        return;
    }
    
    // Get resume info
    NSDictionary*   resumeInfo;
    resumeInfo = [item resumeInfo];
    if (!resumeInfo) {
        return;
    }
    
    // Resume download
    NSURLDownload*  resumeDownload;
    resumeDownload = [[NSURLDownload alloc] 
            _initWithResumeInformation:resumeInfo 
            delegate:self 
            path:[item downloadedFilePath]];
    [item setDownload:resumeDownload];
    [resumeDownload autorelease];
    
    // Make status active
    [item setStatus:SRDownloadStatusActive];
    
    // Remove resume info
    [item setResumeInfo:nil];
#endif
}

- (void)retryDownloadForItem:(SRDownloadHistoryItem*)item
{
#if 0
    // Get download for item
    NSURLDownload*          download;
    SRDownloadItemStatus    status;
    download = [item download];
    status = [item status];
    if (download) {
        // Cancel current download
        [download _setDeletesFileAfterFailure:YES];
        [download cancel];
    }
    
    // Delete previous file
    NSString*   downloadedFilePath;
    downloadedFilePath = [item downloadedFilePath];
    if (downloadedFilePath) {
        NSFileManager*  fileMgr;
        fileMgr = [NSFileManager defaultManager];
        if ([fileMgr fileExistsAtPath:downloadedFilePath] && 
            [fileMgr isDeletableFileAtPath:downloadedFilePath])
        {
            [fileMgr removeFileAtPath:downloadedFilePath handler:nil];
        }
    }
    
    // Start new download
    NSURLRequest*   request;
    NSURLDownload*  newDownload;
    request = [NSURLRequest requestWithURL:[NSURL URLWithString:[item URLString]]];
    newDownload = [[NSURLDownload alloc] 
            initWithRequest:request delegate:self];
    [newDownload autorelease];
    
    // Add download
    [item setDownload:newDownload];
    
    // Make status active, and reset length
    [item setStatus:SRDownloadStatusActive];
    [item resetLength];
#endif
}

- (void)removeDownloadForItem:(SRDownloadHistoryItem*)item
{
#if 0
    // Get download for item
    NSURLDownload*          download;
    SRDownloadItemStatus    status;
    download = [item download];
    status = [item status];
    if (download) {
        // Cancel download
        [download _setDeletesFileAfterFailure:NO];
        [download cancel];
    }
    
    // Remove download item
    [_downloadItems removeObject:item];
    
    // Notify removal
    [self _notifyRemoval:item];
#endif
}

- (void)removeAllCompletedActiveItems
{
#if 0
    // Enumerate active items
    NSEnumerator*           enumerator;
    SRDownloadHistoryItem*  historyItem;
    NSMutableArray*         removeItems;
    removeItems = [NSMutableArray array];
    enumerator = [_downloadItems objectEnumerator];
    while (historyItem = [enumerator nextObject]) {
        // Check item status
        if ([historyItem status] == SRDownloadStatusCompleted) {
            [removeItems addObject:historyItem];
        }
    }
    
    // Remove completed item
    [_downloadItems removeObjectsInArray:removeItems];
    
    // Notify removal
	[[NSNotificationCenter defaultCenter] 
			postNotificationName:SRDownloadRemovedNotification 
			object:removeItems];
#endif
}

- (void)pauseAllActiveDownloads
{
}

- (void)_showFindAlertForPath:(NSString*)path
{
    // Show alert
    NSAlert*    alert;
    alert = [[NSAlert alloc] init];
    [alert autorelease];
    [alert setAlertStyle:NSWarningAlertStyle];
    [alert setMessageText:[NSString stringWithFormat:NSLocalizedString(UTF8STR("Shiira canft show the file g%@h in the Finder."), UTF8STR("Shiira canft show the file g%@h in the Finder.")), [path lastPathComponent]]];
    [alert addButtonWithTitle:NSLocalizedString(@"OK", @"OK")];
    
    int result;
    result = [alert runModal];
}

- (void)findItem:(SRDownloadHistoryItem*)item
{
#if 0
    // Get download path and its parent
    NSString*   filePath;
    NSString*   parent;
    filePath = [item downloadedFilePath];
    if (!filePath) {
        return;
    }
    parent = [filePath stringByDeletingLastPathComponent];
    
    // For download file wrapper
    if ([[parent pathExtension] isEqualToString:@"download"]) {
        filePath = parent;
    }
    
    // Check file existense
    if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
        // Show alert
        [self _showFindAlertForPath:filePath];
        return;
    }
    
    // Find file by Finder
    if (![[NSWorkspace sharedWorkspace] selectFile:filePath inFileViewerRootedAtPath:@""]) {
        // Show alert
        [self _showFindAlertForPath:filePath];
        return;
    }
#endif
}

//--------------------------------------------------------------//
#pragma mark -- NSURLDownload delegate --
//--------------------------------------------------------------//

- (void)downloadDidBegin:(NSURLDownload*)download
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Show download panel
    switch ([defaults integerForKey:SRDownloadNotification]) {
    case SRDownloadNotificationShowPanel: {
        // Show download panel
        [[SRDownloadController sharedInstance] showWindow:self];
        break;
    }
    }
    
    // Create downloader
    SRDownloader*   downloader;
    downloader = [self downladerForDownlaod:download];
    if (!downloader) {
        // Create downloader
        downloader = [[SRDownloader alloc] init];
        [downloader setDownload:download];
        
        // Add downloader
        [_downloaders addObject:downloader];
        [downloader release];
    }
    
    // Notify to downloader
    [downloader downloadDidBegin:download];
    
    // Notify status changed
    [[NSNotificationCenter defaultCenter] 
            postNotificationName:SRDownloadStatusChangedNotification 
            object:downloader];
}

- (NSURLRequest*)download:(NSURLDownload*)download 
        willSendRequest:(NSURLRequest*)request 
        redirectResponse:(NSURLResponse*)redirectResponse
{
    // Notify to downloader
    SRDownloader*   downloader;
    downloader = [self downladerForDownlaod:download];
    return [downloader download:download willSendRequest:request redirectResponse:redirectResponse];
}

- (void)download:(NSURLDownload*)download 
        didReceiveResponse:(NSURLResponse*)response
{
    // Notify to downloader
    SRDownloader*   downloader;
    downloader = [self downladerForDownlaod:download];
    [downloader download:download didReceiveResponse:response];
    
    // Notify status changed
    [[NSNotificationCenter defaultCenter] 
            postNotificationName:SRDownloadStatusChangedNotification 
            object:downloader];
}

- (void)download:(NSURLDownload*)download 
        decideDestinationWithSuggestedFilename:(NSString*)fileName
{
    // Notify to downloader
    SRDownloader*   downloader;
    downloader = [self downladerForDownlaod:download];
    [downloader download:download decideDestinationWithSuggestedFilename:fileName];
}

- (void)download:(NSURLDownload*)download 
        didCreateDestination:(NSString*)path
{
    // Notify to downloader
    SRDownloader*   downloader;
    downloader = [self downladerForDownlaod:download];
    [downloader download:download didCreateDestination:path];
}

- (void)download:(NSURLDownload*)download 
        didReceiveDataOfLength:(unsigned)length
{
    // Notify to downloader
    SRDownloader*   downloader;
    downloader = [self downladerForDownlaod:download];
    [downloader download:download didReceiveDataOfLength:length];
}

- (void)downloadDidFinish:(NSURLDownload*)download
{
    // Notify to downloader
    SRDownloader*   downloader;
    downloader = [self downladerForDownlaod:download];
    [downloader downloadDidFinish:download];
    
    // Notify status changed
    [[NSNotificationCenter defaultCenter] 
            postNotificationName:SRDownloadStatusChangedNotification 
            object:downloader];
}

- (void)download:(NSURLDownload*)download 
        didFailWithError:(NSError*)error
{
    // Notify to downloader
    SRDownloader*   downloader;
    downloader = [self downladerForDownlaod:download];
    [downloader download:download didFailWithError:error];
    
    // Notify status changed
    [[NSNotificationCenter defaultCenter] 
            postNotificationName:SRDownloadStatusChangedNotification 
            object:downloader];
}

- (BOOL)download:(NSURLDownload*)download 
        shouldDecodeSourceDataOfMIMEType:(NSString*)encodingType
{
    // Decode automatically
    return YES;
}

@end
