#import <Foundation/Foundation.h>
#import "RNFileCacheDownloader.h"
#import "RNFileCacheDownloaderTask.h"
#import "RNFileCacheStat.h"

typedef void (^CacheDownloaderCompletionHandler)(NSError *err);

static RNFileCacheDownloader *defaultDownloader;

@implementation RNFileCacheDownloader {
  NSURLSession *session;
  int timeoutIntervalForRequest;
  int timeoutIntervalForResource;
  RNFileCacheStat *stat;
}

+ (void)setTimeoutIntervalForRequest:(int)timeoutIntervalForRequest
{
  if(defaultDownloader == nil) {
    defaultDownloader = [[RNFileCacheDownloader alloc] init];
  }
  [defaultDownloader setTimeoutIntervalForRequest: timeoutIntervalForRequest];
}

+ (void)setTimeoutIntervalForResource:(int)timeoutIntervalForResource
{
  if(defaultDownloader == nil) {
    defaultDownloader = [[RNFileCacheDownloader alloc] init];
  }
  [defaultDownloader setTimeoutIntervalForResource: timeoutIntervalForResource];
}

- (void)setTimeoutIntervalForRequest:(int)value
{
  timeoutIntervalForRequest = value;
}

- (void)setTimeoutIntervalForResource:(int)value
{
  timeoutIntervalForResource = value;
}

- (id)init
{
  if(self = [super init]) {
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
    config.timeoutIntervalForRequest = 60;
    config.timeoutIntervalForResource = 60*60*24*7; // default: 7daysA
    stat = [[RNFileCacheStat alloc] init];
    session = [NSURLSession sessionWithConfiguration: config
                                            delegate: self
                                       delegateQueue: [NSOperationQueue mainQueue]];
  }
  return self;
}

- (double)bpsFrom:(double)from to:(double)to
{
  return [stat bpsFrom:from to:to];
}

- (void)downloadURL:(NSURL *)url path:(NSString *)path
{
  NSURLSessionDataTask *dataTask = [session dataTaskWithURL: url];
  RNFileCacheDownloaderTask *task = [[RNFileCacheDownloaderTask alloc] initWithTask:dataTask path:path];
  [task download];
}

- (void)cancelDownloadURL:(NSURL *)url
{
  RNFileCacheDownloaderTask *task = [RNFileCacheDownloaderTask taskForURL: url];
  if(task != nil) {
    [task cancel];
  }
}

- (void)URLSession:(NSURLSession *)session
          dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
 completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
{
  RNFileCacheDownloaderTask *task = [RNFileCacheDownloaderTask task:[dataTask taskIdentifier]];
  [task didReceiveResponse:response completionHandler: completionHandler];

  [stat start: [dataTask taskIdentifier]];
}

- (void)URLSession:(NSURLSession *)session
          dataTask:(NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data
{
  RNFileCacheDownloaderTask *task = [RNFileCacheDownloaderTask task:[dataTask taskIdentifier]];
  [task didReceiveData:data];

  [stat end: [dataTask taskIdentifier] withData: data];
}

- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)dataTask
didCompleteWithError:(NSError *)error
{
  RNFileCacheDownloaderTask *task = [RNFileCacheDownloaderTask task:[dataTask taskIdentifier]];
  [task didCompleteWithError:error];
}
  
+ (void)download:(NSURL *)url to:(NSString *)path
{
  if(defaultDownloader == nil) {
    defaultDownloader = [[RNFileCacheDownloader alloc] init];
  }
  [defaultDownloader downloadURL:url path:path];
}
  
+ (void)cancelDownload:(NSURL *)url
{
  if(defaultDownloader == nil) {
    return;
  }
  [defaultDownloader cancelDownloadURL:url];
}
  
+ (double)bpsFrom:(double)from to:(double)to
{
  if(defaultDownloader == nil) {
    return 0.0;
  }
  return [defaultDownloader bpsFrom:from to:to];
}

@end
