/* This code is licensed in the Public Domain. Please contribute any fixes back to hakan@konstochvanligasaker.se 
   See https://konstochvanligasaker.se/code for det latest version. */
   
#import "BatchDownloader.h"

@interface NSObject (PtrValueUtils)
- (NSValue *)ptrValue;
@end

@implementation NSObject (PtrValueUtils)
- (NSValue *)ptrValue
{
  return [NSValue valueWithPointer:self];
}
@end

@interface BatchDownloader (Private)
- (void)removeAllTracesOfDownload:(NSURLDownload *)download URL:(NSString *)URL;
@end

@implementation BatchDownloader

- (id)init
{
  if ((self = [super init])) {
    downloadPtrsToURLs = [NSMutableDictionary new];
    downloadURLsToObjects = [NSMutableDictionary new];
    downloadURLsToLocalPaths = [NSMutableDictionary new];
  }
  return self;
}

- (id)initWithDestinationFolder:(NSString *)path delegate:(id)theDelegate
{
  if ((self = [self init])) {
    delegate = theDelegate;
    // does the dest dir exist?
    if (! [[NSFileManager defaultManager] contentsAtPath:path]) {
      // try to create it.
      BOOL succeeded = [[NSFileManager defaultManager] createDirectoryAtPath:path attributes:nil];
      // TODO: throw (or something) on failure
    }
    destinationFolder = [path copy];
  }
  return self;
}

- (void)dealloc
{
  delegate = nil;
  [destinationFolder release];
  
  [downloadURLsToObjects release];
  [downloadPtrsToURLs release];
  [downloadURLsToLocalPaths release];
  
  [super dealloc];
}

#pragma mark -

- (void)addDownload:(NSString *)URL
{
  NSURLDownload *download = [[[NSURLDownload alloc] initWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:URL]] delegate:self] autorelease];
    
  NSString *destPath = [destinationFolder stringByAppendingPathComponent:[URL lastPathComponent]];
  [download setDestination:destPath allowOverwrite:NO];
    
  [downloadURLsToObjects setObject:download forKey:URL];
  [downloadPtrsToURLs setObject:URL forKey:[download ptrValue]];
}

- (void)addDownloads:(NSArray *)downloadPaths
{
  // TODO: start notification timer so we can report back in batches as well

  // start downloading
  NSString *URL = nil;
  NSEnumerator *downloadEnumerator = [downloadPaths objectEnumerator];
  while ((URL = [downloadEnumerator nextObject])) {
    [self addDownload:URL];
  }
}

- (void)removeAllTracesOfDownload:(NSURLDownload *)download URL:(NSString *)URL
{
  [downloadPtrsToURLs removeObjectForKey:[download ptrValue]];
  [downloadURLsToObjects removeObjectForKey:URL];
  [downloadURLsToLocalPaths removeObjectForKey:URL];
}

#pragma mark -

- (void)download:(NSURLDownload *)download didCreateDestination:(NSString *)path
{
  [downloadURLsToLocalPaths setObject:path forKey:[downloadPtrsToURLs objectForKey:[download ptrValue]]];
}

- (void)download:(NSURLDownload *)download didFailWithError:(NSError *)error
{
  NSString *URL = [downloadPtrsToURLs objectForKey:[download ptrValue]];

  // notify delegate
  // TODO: batch these notifications
  if (delegate && [delegate respondsToSelector:@selector(downloadsFailed:)]) {
    [delegate downloadsFailed:[NSArray arrayWithObject:URL]];
  }
  
  [self removeAllTracesOfDownload:download URL:URL];
}

- (void)downloadDidFinish:(NSURLDownload *)download
{
  NSString *URL = [downloadPtrsToURLs objectForKey:[download ptrValue]];
  
  // notify delegate
  // TODO: batch these notifications
  if (delegate && [delegate respondsToSelector:@selector(downloadsReady:)]) {
    NSString *destPath = [downloadURLsToLocalPaths objectForKey:URL];
    [delegate downloadsReady:[NSDictionary dictionaryWithObject:destPath forKey:URL]];
  }
  
  [self removeAllTracesOfDownload:download URL:URL];
}

@end
