/*
SRSDFeedManager.m

Author: Makoto Kinoshita

Copyright 2004 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 "SRSDSyndication.h"
#import "SRSDRSSDocument.h"
#import "SRSDAppController.h"
#import "SRSDFeedManager.h"
#import "SRSDXMLFileManager.h"

#import "SRSDUtil.h"

@interface SRSDFeedManager (private)
- (void)notifyTimerFired:(NSNotification*)notification;
@end

@implementation SRSDFeedManager

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

- (id)initWithAppController:(SRSDAppController*)appController
{
    self = [super init];
    if (!self) {
        return nil;
    }
    
    //  Initialize member variables
    _appController = appController;
    _feedURLs = [[NSMutableArray array] retain];
    _XMLFileDicts = [[NSMutableArray array] retain];
    _downloads = [[NSMutableArray array] retain];
    _tmpXMLFilePathDict = [[NSMutableDictionary dictionary] retain];
    _refreshingAllFeeds = NO;
    _willNotify = NO;
    
    return self;
}

- (void)dealloc
{
    [_feedURLs release];
    [_XMLFileDicts release];
    [_downloads release];
    [_tmpXMLFilePathDict release];
    
    [super dealloc];
}

//--------------------------------------------------------------//
#pragma mark -- Refresh feeds --
//--------------------------------------------------------------//

- (void)_refreshNextFeeds
{
    // Get max connection number
    int maxNumber;
    maxNumber = [[NSUserDefaults standardUserDefaults] integerForKey:SRSDMaxConnectionNumber];
    if (maxNumber <= 0 || maxNumber > 16) {
        maxNumber = 4;
    }
    
    // Refresh feeds
    NSMutableArray* sentFeedURLs;
    NSEnumerator*   enumerator;
    NSString*       feedURL;
    sentFeedURLs = [NSMutableArray array];
    enumerator = [_feedURLs objectEnumerator];
    while ((feedURL = [enumerator nextObject]) && [_downloads count] < maxNumber) {
        // Download specified URL
        NSURLRequest*   request;
        NSURLDownload*  download;
        request = [NSURLRequest requestWithURL:[NSURL URLWithString:feedURL]];
        download = [[NSURLDownload alloc] initWithRequest:request delegate:self];
        [_downloads addObject:download];
        
        [sentFeedURLs addObject:feedURL];
    }
    
    // Remove sent feed URLs
    [_feedURLs removeObjectsInArray:sentFeedURLs];
}

- (void)refreshFeedURLs:(NSArray*)feedURLs
{
    // Notify feed refresh start
    [[NSDistributedNotificationCenter defaultCenter] 
            postNotificationName:SRSDFeedWillStartRefresh object:nil]; 
    
    // Copy feed URLs
    [_feedURLs addObjectsFromArray:feedURLs];
    
    // Refresh next feeds
    [self _refreshNextFeeds];
}

- (void)cancelAllRefresh
{
    // Cancel all downloads
    NSEnumerator*   enumerator;
    NSURLDownload*  download;
    enumerator = [_downloads objectEnumerator];
    while (download = [enumerator nextObject]) {
        [download cancel];
    }
    [_downloads removeAllObjects];
    [_feedURLs removeAllObjects];
    
    // Cancel notify timer
    if (_willNotify) {
        [_notifyTimer invalidate];
        _notifyTimer = nil;
        _willNotify = NO;
    }
    [self notifyTimerFired:nil];
}

#if 0
//--------------------------------------------------------------//
#pragma mark -- Refresh feeds --
//--------------------------------------------------------------//

- (NSString*)loadingStatusDescription
{
    if (!_refreshingAllFeeds) {
        return @"";
    }
    
    int remain;
    remain = [_downloads count];
    
    NSString*   description = @"";
    if (remain == 1) {
        description = [NSString stringWithFormat:NSLocalizedString(UTF8STR("%d file is loading…"), nil), [_downloads count]];
    }
    else if (remain > 1) {
        description = [NSString stringWithFormat:NSLocalizedString(UTF8STR("%d files are loading…"), nil), [_downloads count]];
    }
    
    return description;
    
}
#endif

//--------------------------------------------------------------//
#pragma mark -- Notify timer --
//--------------------------------------------------------------//

- (void)notifyTimerFired:(NSNotification*)notification
{
    // Collect document IDs
    NSMutableArray* documentIds;
    NSEnumerator*   enumerator;
    NSDictionary*   XMLFileDict;
    documentIds = [NSMutableArray array];
    enumerator = [_XMLFileDicts objectEnumerator];
    while (XMLFileDict = [enumerator nextObject]) {
        NSString*   documentId;
        documentId = [XMLFileDict objectForKey:@"documentId"];
        if (documentId) {
            [documentIds addObject:documentId];
        }
    }
    
    // Add XML files to feeds.plist
    int count = 0;
    [[_appController XMLFileManager] addXMLFileDicts:_XMLFileDicts numberOfNewItems:&count];
    [_XMLFileDicts removeAllObjects];
    
    // For progress
    [[NSDistributedNotificationCenter defaultCenter] 
            postNotificationName:SRSDFeedProgressRefresh object:nil 
            userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
                    documentIds, @"documentIds", 
                    [NSNumber numberWithInt:count], @"numberOfNewItems", nil]]; 
    
    // Refresh next feeds
    [self _refreshNextFeeds];
    
    // For finished
    if ([_downloads count] == 0) {
        [[NSDistributedNotificationCenter defaultCenter] 
                postNotificationName:SRSDFeedDidEndRefresh object:nil]; 
        
        // Terminate itself
        [_appController terminate];
    }
    
    _willNotify = NO;
    _notifyTimer = nil;
}

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

//- (void)downloadDidBegin:(NSURLDownload*)download;

- (void)download:(NSURLDownload*)download decideDestinationWithSuggestedFilename:(NSString*)filename
{
    // Create UUID string
    NSString*   uuidString;
    uuidString = SRCreateUUID();
    
    // Create tmp path
    NSString*   tmpPathDir;
    NSString*   tmpPath;
    tmpPathDir = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"Shiira"]];
    if (![[NSFileManager defaultManager] fileExistsAtPath:tmpPathDir]) {
        // Create directory
        [[NSFileManager defaultManager] createDirectoryAtPath:tmpPathDir attributes:nil];
    }
    tmpPath = [tmpPathDir stringByAppendingPathComponent:uuidString];
    
    [_tmpXMLFilePathDict setObject:tmpPath forKey:[[[download request] URL] absoluteString]];
    
    // Set detination file path
    [download setDestination:tmpPath allowOverwrite:YES];
}

//- (void)download:(NSURLDownload*)download didCreateDestination:(NSString*)path;
//- (NSURLRequest*)download:(NSURLDownload*)download willSendRequest:(NSURLRequest*)request redirectResponse:(NSURLResponse*)redirectResponse;
//- (void)download:(NSURLDownload*)download didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge*)challenge;
//- (void)download:(NSURLDownload*)download didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge*)challenge;
//- (void)download:(NSURLDownload*)download didReceiveResponse:(NSURLResponse*)response;
//- (void)download:(NSURLDownload*)download willResumeWithResponse:(NSURLResponse *)response fromByte:(long long)startingByte;
//- (void)download:(NSURLDownload*)download didReceiveDataOfLength:(unsigned)length;
//- (BOOL)download:(NSURLDownload*)download shouldDecodeSourceDataOfMIMEType:(NSString*)encodingType;

- (void)_finishDownload:(NSURLDownload*)download
{
    // Remove download
    if ([_downloads containsObject:download]) {
        [_downloads removeObject:download];
    }
    
    // Notify refresh finish
    if (!_willNotify) {
        // Start timer
        _willNotify = YES;
        _notifyTimer = [NSTimer scheduledTimerWithTimeInterval:2.0f 
                target:self 
                selector:@selector(notifyTimerFired:) 
                userInfo:nil 
                repeats:NO];
    }
#if 0
    else {
        // Check downloads number
        if ([_downloads count] == 0) {
            // Invalidate timer immediately, and notify soon
            [_notifyTimer invalidate];
            _notifyTimer = nil;
            [self notifyTimerFired:nil];
        }
    }
#endif
}

- (void)downloadDidFinish:(NSURLDownload*)download
{
    // Get tmp path
    NSString*   tmpPath;
    tmpPath = [_tmpXMLFilePathDict objectForKey:[[[download request] URL] absoluteString]];
    
    // Move file
    NSString*   XMLPath;
    XMLPath = [[_appController XMLFileManager] tmpXMLFilePathWithURL:[[download request] URL]];
    [[NSFileManager defaultManager] movePath:tmpPath toPath:XMLPath handler:NULL];
    
#if 1
    // Get URL string
    NSString*   URLString;
    URLString = [[[download request] URL] absoluteString];
    
    // Add XML file
    if (URLString) {
        NSDictionary*   XMLFileDict;
        XMLFileDict = [NSDictionary dictionaryWithObjectsAndKeys:
                XMLPath, @"XMLPath", 
                URLString, @"documentId", 
                nil];
        [_XMLFileDicts addObject:XMLFileDict];
    }
#else
    // Parse RSS document
    SRSDRSSDocument*    document;
    document = [[SRSDRSSDocument alloc] initWithContentsOfURL:[NSURL fileURLWithPath:xmlPath] options:0 error:NULL];
    if (document) {
        [document setIdentifier:[[[download request] URL] absoluteString]];
        [_RSSDocuments addObject:document];
        [document release];
    }
#endif
    
    [self _finishDownload:download];
}

- (void)download:(NSURLDownload*)download didFailWithError:(NSError*)error
{
    // Error
    NSLog(@"Download failed, %@", [error localizedDescription]);
    
    [self _finishDownload:download];
}

@end
