//
//  HSNSURLSession.m
//  HSDownloadManagerExample
//
//  Created by hans on 15/8/4.
//  Copyright © 2015年 hans. All rights reserved.
//

#import "WSDownloadSession.h"

//#import "MsgEntityFrameModel.h"
//#import "NoticeModels.h"


@interface WSDownloadSession()<NSURLSessionDelegate>
@property (nonatomic,copy)NSString *msgUUID;
/** 流 */
@property (nonatomic, strong) NSOutputStream *stream;

//下载任务
@property (nonatomic, strong)NSURLSessionDataTask *task;
/** 下载地址 */
@property (nonatomic, copy) NSString *url;

/**
 *  缓存根路径/A/
 */
@property (nonatomic , copy) NSString *cacheRootPath;

/**
 *  绝对路径(最后的两个绝对,用来拼接)xxj/之后的路径,(需要传出来,所以带上filename)
 */
@property (nonatomic , copy) NSString *localPath;

@property (nonatomic , copy) NSString *attachName;

@property (nonatomic , copy) NSString *fileMd5;

/**
 *  附件完整路径/A/xx.yy
 */
@property (nonatomic , copy) NSString *attachFullPath;
/**
 *  文件大小描述文件完全路径
 */
@property (nonatomic , copy) NSString *attachTotalLengthFileFullPath;

/**
 *  已下载长度
 */
@property (nonatomic , assign)NSInteger downloadedLength;

/** 获得服务器这次请求 返回数据的总长度 */
@property (nonatomic, assign) NSInteger totalLengthSaveFromServer;

//请求时文件模型告知的实际大小.
@property (nonatomic , assign) NSInteger totalLengthNeedDownload;

@property (nonatomic, assign)NSURLSession *session;

@end
//取消
static const NSUInteger SessionCancerCode = -999;
//超时
@implementation WSDownloadSession

+ (id)oneDownloadSessionWithFileUrlString:(NSString *)downloadUrl savePath:(NSString *)path localPath:(NSString *)localPath fileMd5:(NSString *)md5 UUID:(NSString *)uuid fileName:(NSString *)fileName downloadedSize:(NSInteger)downloadedSize fileSize:(NSInteger)fileSize progressblock:(DownloadProgressBlock)progressBlock successblock:(DownloadSuccessBlock)successblock failedBlock:(DownloadFailedBlock)failedBlock;
{
    WSDownloadSession *wsDowunloadSession = [[WSDownloadSession alloc]initOneDownloadSessionWithFileUrlString:downloadUrl savePath:path localPath:localPath fileMd5:md5 UUID:uuid fileName:fileName downloadedSize:downloadedSize fileSize:fileSize progressblock:progressBlock successblock:successblock failedBlock:failedBlock];
    
    return wsDowunloadSession;
    
}

//SAVE PATH: .../Library/xxj/cloudstorage
//localpath /cloudstorage/filename


//                   savepath/  localpath /filename
//...library/xxj/cloudStorage/dada78dafada/xxx.filename
- (instancetype)initOneDownloadSessionWithFileUrlString:(NSString *)downloadUrl savePath:(NSString *)savePath localPath:(NSString *)localPath fileMd5:(NSString *)md5 UUID:(NSString *)uuid fileName:(NSString *)fileName downloadedSize:(NSInteger)downloadedSize fileSize:(NSInteger)fileSize progressblock:(DownloadProgressBlock)progressBlock successblock:(DownloadSuccessBlock)successblock failedBlock:(DownloadFailedBlock)failedBlock
{
    if (self = [super init]) {
        
        self.msgUUID = uuid;
        self.fileMd5 = md5;
        self.url = downloadUrl;
        self.totalLengthNeedDownload = fileSize;
        /**
         *  实际效果不大?,还是读取实际的大小.
         */
        self.downloadedLength = downloadedSize;
        
        self.downloadProgressBlock = progressBlock;
        self.downloadSuccessBlock = successblock;
        self.downloadFailedBlock = failedBlock;
        self.attachName = fileName;
        self.localPath = ![localPath isEqualToString:fileName]?[NSString stringWithFormat:@"%@/%@",localPath,fileName]:fileName;//存入数据库中.
        //下载完注意删除
        self.attachTotalLengthFileFullPath = [savePath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@_%@_totalLength.plist",fileName,md5]];
        self.attachFullPath = [NSString stringWithFormat:@"%@/%@",savePath,self.localPath];
        self.cacheRootPath = ![localPath isEqualToString:fileName]?[NSString stringWithFormat:@"%@/%@",savePath,localPath]:savePath;
        
        [self createCacheDirectory];
        NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc]init]];
        //写入文件专用.
        NSOutputStream *stream = [NSOutputStream outputStreamToFileAtPath:self.attachFullPath append:YES];
        
        //中文字符的链接处理下
        // 创建请求
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[downloadUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
        
        // 设置请求头
        NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.downloadedLength];
        [request setValue:range forHTTPHeaderField:@"Range"];
        [request addValue:@"close" forHTTPHeaderField:@"Connection"];
        
        
        // 创建一个Data任务
        NSURLSessionDataTask *task = [session dataTaskWithRequest:request];
        NSUInteger taskIdentifier = arc4random() % ((arc4random() % 10000 + arc4random() % 10000));
        [task setValue:@(taskIdentifier) forKeyPath:@"taskIdentifier"];
        self.task = task;
        self.stream = stream;
        
        [self start];
        
        self.session = session;
    }
    
    return self;

}

/**
 *  创建缓存目录文件
 */
- (void)createCacheDirectory
{

    NSFileManager *fileManager = [NSFileManager defaultManager];
    if (![fileManager fileExistsAtPath:self.cacheRootPath]) {
        [fileManager createDirectoryAtPath:self.cacheRootPath withIntermediateDirectories:YES attributes:nil error:NULL];
    }
}


//实时获取文件大小
- (NSInteger)downloadedLength
{
    return [[[NSFileManager defaultManager] attributesOfItemAtPath:[self.cacheRootPath stringByAppendingPathComponent:self.attachName] error:nil][NSFileSize] integerValue];
}

//挂起.
- (void)handle
{
  
    if (self.task.state == NSURLSessionTaskStateRunning) {
        [self pause];
    } else {
        [self start];
    }
}

/**
 *  开始下载
 */
- (void)start
{
 
    [self.task resume];

}

/**
 *  暂停下载-如果url相同的话就有问题.
 */
- (void)pause
{

    //可能超时,show error,直接cancer吧。
    
    if (!self.task) {
        return;
    }
    [self.task suspend];
   
    

    
}

- (void)cancer
{

    if (!self.task) {
        return;
    }
    


    [self.session finishTasksAndInvalidate];
    [self.session invalidateAndCancel];
    
    
    // 关闭流
    [self.stream close];
    self.stream.delegate = nil;
    
    // 清除任务
    [self.task cancel];
    
    self.task = nil;
    self.stream = nil;
    self.session = nil;
}

/**
 *  判断该文件是否下载完成
 */
- (BOOL)isCompletion
{
 
    if (self.downloadedLength == self.totalLengthNeedDownload ) {
        return YES;
    }
    return NO;
    
}

/**
 *  根据服务端返回的总大小生成的文件 获取该资源总大小
 */
- (NSInteger)fileTotalLength
{
    return [[NSDictionary dictionaryWithContentsOfFile:self.attachTotalLengthFileFullPath][self.attachName] integerValue];
}

#pragma mrak --
#pragma mark -- URLSessionDelegate

/**
 * 接收到响应
 */
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSHTTPURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
{
    // 打开流
    [self.stream open];
    
    // 获得服务器这次请求 返回数据的总长度
    NSInteger totalLength = [response.allHeaderFields[@"Content-Length"] integerValue] + self.downloadedLength;
    self.totalLengthSaveFromServer = totalLength;
    
    // 存储总长度
    NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithContentsOfFile:self.attachTotalLengthFileFullPath];
    
    if (dict == nil) dict = [NSMutableDictionary dictionary];
    dict[self.attachName] = @(totalLength);

    [dict writeToFile:self.attachTotalLengthFileFullPath atomically:YES];
    
    // 接收这个请求，允许接收服务器的数据
    completionHandler(NSURLSessionResponseAllow);

}

/**
 * 接收到服务器返回的数据
 */
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
{

        // 写入数据
    [self.stream write:data.bytes maxLength:data.length];
    
    
    
    // 下载进度
    NSUInteger receivedSize = self.downloadedLength;
    NSUInteger expectedSize = self.totalLengthSaveFromServer;
    CGFloat progress = 1.0 * receivedSize / expectedSize;
    
    NSLog(@"后台下载进度---%f",progress);
    if (self.downloadProgressBlock) {
        self.downloadProgressBlock(receivedSize, expectedSize, progress,self.attachFullPath,self.msgUUID);
    }
    
//    if (self.downloadProgressDBBlock) {
//        self.downloadProgressDBBlock(receivedSize, expectedSize, progress,self.attachFullPath,self.msgUUID);
//    }
    
}

/**
* 请求完毕（成功|失败）
*/
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
    __weak typeof(self)weakself = self;
    
#warning 待加入重试机制.抛出retryblock.maxcount=3.
    if ([self isCompletion]) {
        // 下载完成
        
        if (weakself.downloadSuccessBlock) {
#warning 2017-06-29 待将localrootpath传出,数据库写入.
            weakself.downloadSuccessBlock(weakself.downloadedLength,weakself.localPath,weakself.msgUUID);
        }
        NSError *error = nil;
        [[NSFileManager defaultManager]removeItemAtPath:self.attachTotalLengthFileFullPath error:&error];
        
//        if (weakself.downloadSuccessDBBlock) {
//            weakself.downloadSuccessDBBlock(weakself.downloadedLength,weakself.localPath,weakself.msgUUID);
//        }
    
    } else if (error.code != SessionCancerCode){
        // 下载失败
        if (self.downloadFailedBlock) {
            self.downloadFailedBlock(@"error",self.msgUUID);
        }
        
//        if (self.downloadFailedDBBlock) {
//            self.downloadFailedDBBlock(@"error",self.msgUUID);
//        }

    }
    
    [session finishTasksAndInvalidate];
    [session invalidateAndCancel];
    
    
    // 关闭流
    [self.stream close];
    self.stream.delegate = nil;
    
    // 清除任务
    [self.task cancel];
    
    self.task = nil;
    self.stream = nil;
    session = nil;

}

- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error
{
    
}


@end
