//
//  CloudStorageDownloadCenter.m
//  zhuxun
//
//  Created by winsoft on 17/6/26.
//
//


#import "CloudStorageDownloadCenter.h"



#import "HttpRequest.h"

@interface CloudStorageDownloadCenter()
@property (nonatomic , assign) CGFloat maxConcurrenceDownloadCount;
/**
 *  同时最大文件下载并发数
 */

@property (nonatomic , strong) NSMutableDictionary *maxConcurrenceDownloadTasks;//downloadmodel.

/**
 *  全部下载任务
 */
@property (nonatomic , strong) NSMutableDictionary *totalDownloadTasks;

/**
 *  上一个新增的model.
 */
@property (nonatomic , strong) CSFileDownUpModel *lastOneDowunUpModel; // last one = nil;//动态.

@property (nonatomic , strong) CSFileDownUpModel *firstOneDowunUpModel;//动态.

@end
@implementation CloudStorageDownloadCenter
static CloudStorageDownloadCenter *cloudStorageDownloadCenter;

+ (instancetype)sharedInstance
{
    static dispatch_once_t onceToken;
    
    dispatch_once(&onceToken, ^{
        cloudStorageDownloadCenter = [[self alloc] init];
    });
    
    return cloudStorageDownloadCenter;
}

- (void)userServerOut
{
    for ( CloudDownloadSession *cloudUploadingSession  in self.maxConcurrenceDownloadTasks.allValues) {
        [cloudUploadingSession cancerDownLoad];
    }
    
    [self.maxConcurrenceDownloadTasks removeAllObjects];
    [self.totalDownloadTasks removeAllObjects];
    self.firstOneDowunUpModel = nil;
    self.lastOneDowunUpModel = nil;
}

- (instancetype)init
{
    if (self = [super init]) {
        _totalDownloadTasks = [NSMutableDictionary dictionary];
        _maxConcurrenceDownloadTasks = [NSMutableDictionary dictionary];
    }
    
    return self;
}

- (CGFloat)maxConcurrenceDownloadCount
{
    //数据库设计..
    return 1;
}

//获取md5+name 的operation
- (BOOL)judgeSameFileIsProcessWithFileDownUpModel:(CSFileDownUpModel *)fileDownUpModel
{
    BOOL hasSameFile = NO;
    
    NSString *searchNameAndMd5= [NSString stringWithFormat:@"%@_%@",[fileDownUpModel.downUpUUID componentsSeparatedByString:@"_"][0],[fileDownUpModel.downUpUUID componentsSeparatedByString:@"_"][1]];
    
    //self.name,self.md5  name_md5
    for (NSString *allUUID in self.maxConcurrenceDownloadTasks.allKeys) {
        
        if ([searchNameAndMd5 isEqualToString:allUUID]) {
            
            hasSameFile = YES;
            break;
        }else continue;
        
        
    }
    
    return hasSameFile;
}

- (NSString *)getTrueFileNmae_Md5:(CSFileDownUpModel *)csFileDownUpModel
{
    NSString *searchNameAndMd5= [NSString stringWithFormat:@"%@_%@",csFileDownUpModel.name,csFileDownUpModel.md5];
    return searchNameAndMd5;
}

- (void)addOneDownloadWithFileDownUpModel:(CSFileDownUpModel *)fileDownUpModel
{
    //判断是否重复
    if ([self.totalDownloadTasks objectForKey:fileDownUpModel.downUpUUID]||[self.maxConcurrenceDownloadTasks objectForKey:[self getTrueFileNmae_Md5:fileDownUpModel]] ||fileDownUpModel.isdir) {
        return;
    }
    
    //无论成功还是失败还是暂停,都要对队列进行重新排序
    
    //进行队列初始化.,如果其中排队的某个暂停,则对其进行重新排队. a->b->c ,if b pause, a.next = b.next
    
    
    if (_lastOneDowunUpModel != fileDownUpModel && _lastOneDowunUpModel) {
        
        _lastOneDowunUpModel.nextFileDownUpModel = fileDownUpModel;
        fileDownUpModel.lastFileDownUpModel = _lastOneDowunUpModel;
    }
    
    if (!_firstOneDowunUpModel) {
        _firstOneDowunUpModel = fileDownUpModel;
    }
    
    _lastOneDowunUpModel = fileDownUpModel;
    
    DownUpStatus oldStatus = fileDownUpModel.downUpStatus;
    //待存储.并通知translistcontroller.
    fileDownUpModel.downUpStatus = DownUpStatusWait;
    
    //先获取所有需要下载的文件.
    if (!fileDownUpModel.isdir) {
        
        [self.totalDownloadTasks setObject:fileDownUpModel forKey:fileDownUpModel.downUpUUID];
        
        if (self.maxConcurrenceDownloadTasks.allKeys.count < self.maxConcurrenceDownloadCount) {
            
            [self startOneDownloadWithDownUpFileModel:fileDownUpModel];
        }
        
        
    }
    
    if (oldStatus != fileDownUpModel.downUpStatus) {
        [kCloudStorageDB updateCSDownUpFileStatusWithCSFileDownUpModel:fileDownUpModel];
    }
    
}

- (void)addOneDownloadWithFileDownUpModels:(NSArray *)fileDownUpModels
{
    for (CSFileDownUpModel *csFileDownUpModel in fileDownUpModels) {
        [self addOneDownloadWithFileDownUpModel:csFileDownUpModel];
    }
}


//max队列<5
//轮到下载时再获取下载地址

- (void)startOneDownloadWithDownUpFileModel:(CSFileDownUpModel *)fileDownUpModel
{
    
    //延迟1秒的目的: 完成task的cell更新和下一条进行更新的cell不同时进行reloaddata
    
    //    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1*NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    
    
    if (!fileDownUpModel || self.maxConcurrenceDownloadTasks.allKeys.count >= self.maxConcurrenceDownloadCount) {
        return;
    }
    __weak typeof(self)weakself = self;
    //待存储.并通知translistcontroller.
    fileDownUpModel.downUpStatus = DownUpStatusDoing;
    
    CloudDownloadSession *csDownUpSession  = nil;
    
    if ([self judgeSameFileIsProcessWithFileDownUpModel:fileDownUpModel]) {
        
        csDownUpSession = [self.maxConcurrenceDownloadTasks objectForKey:[self getTrueFileNmae_Md5:fileDownUpModel]];
        
    }else{
        
        csDownUpSession= [CloudDownloadSession startDownloadFileWithFileDownUpModel:fileDownUpModel];
        
        [self.maxConcurrenceDownloadTasks setObject:csDownUpSession forKey:[self getTrueFileNmae_Md5:fileDownUpModel]];
    }
    
    csDownUpSession.downloadSuccessDBBlock = ^(NSInteger receivedSize,NSString *localFullFileRouter,CSFileDownUpModel *fileDownUpModel,NSString *uuid){
        
        
        //重新排队
        if (fileDownUpModel.lastFileDownUpModel && fileDownUpModel.nextFileDownUpModel) {
            
            fileDownUpModel.lastFileDownUpModel.nextFileDownUpModel = fileDownUpModel.nextFileDownUpModel;
            
            fileDownUpModel.nextFileDownUpModel.lastFileDownUpModel = fileDownUpModel.lastFileDownUpModel;
        }else if (fileDownUpModel.nextFileDownUpModel && !fileDownUpModel.lastFileDownUpModel)
        {
            //只有下一个,没有上一个,说明是队头,
            
            //移除下一个的上一个,即指定下一个为头.
            fileDownUpModel.nextFileDownUpModel.lastFileDownUpModel = nil;
            
            weakself.firstOneDowunUpModel = fileDownUpModel.nextFileDownUpModel;
            
        }
#warning 2017-07-18
        //待移步至二层operation,且设置时间1s存储一次.
        //        [CloudStorageDB updateCSDownUpFileStatusWithCSFileDownUpModel:fileDownUpModel];
        
        [weakself.maxConcurrenceDownloadTasks removeObjectForKey:[self getTrueFileNmae_Md5:fileDownUpModel]];
        [weakself.totalDownloadTasks removeObjectForKey:fileDownUpModel.downUpUUID];
        
        if ([_firstOneDowunUpModel.downUpUUID isEqualToString:fileDownUpModel.downUpUUID]) {
            _firstOneDowunUpModel = nil;
        }
        
        if ([_lastOneDowunUpModel.downUpUUID isEqualToString:fileDownUpModel.downUpUUID]) {
            _lastOneDowunUpModel = nil;
        }
        
        [weakself queueForMuiltTastWithFinishedModel:weakself.firstOneDowunUpModel currentMaxTaskCount:weakself.maxConcurrenceDownloadTasks.allValues.count];
        //        [weakself queueForTaskNextWithFinishedModel:weakself.firstOneDowunUpModel];
    };
    
    csDownUpSession.downloadProgressDBBlock = ^(NSInteger receivedSize, NSInteger expectedSize, CGFloat progress,NSString *router,CSFileDownUpModel *fileDownUpModel,NSString *uuid){
        
        //         [CloudStorageDB updateCSDownUpFileStatusWithCSFileDownUpModel:fileDownUpModel];
    };
    
    csDownUpSession.downloadFailedDBBlock = ^(NSString* errMessage,CSFileDownUpModel *fileDownUpModel,NSString *uuid){
        
        
        
        //重新排队
        if (fileDownUpModel.lastFileDownUpModel && fileDownUpModel.nextFileDownUpModel) {
            
            fileDownUpModel.lastFileDownUpModel.nextFileDownUpModel = fileDownUpModel.nextFileDownUpModel;
            
            fileDownUpModel.nextFileDownUpModel.lastFileDownUpModel = fileDownUpModel.lastFileDownUpModel;
        }else if (fileDownUpModel.nextFileDownUpModel && !fileDownUpModel.lastFileDownUpModel)
        {
            //只有下一个,没有上一个,说明是队头,
            
            //移除下一个的上一个,即指定下一个为头.
            fileDownUpModel.nextFileDownUpModel.lastFileDownUpModel = nil;
            
            weakself.firstOneDowunUpModel = fileDownUpModel.nextFileDownUpModel;
            
        }
        
        
        
        //         [CloudStorageDB updateCSDownUpFileStatusWithCSFileDownUpModel:fileDownUpModel];
        
        [weakself.maxConcurrenceDownloadTasks removeObjectForKey:[self getTrueFileNmae_Md5:fileDownUpModel]];
        [weakself.totalDownloadTasks removeObjectForKey:fileDownUpModel.downUpUUID];
        
        if ([_firstOneDowunUpModel.downUpUUID isEqualToString:fileDownUpModel.downUpUUID]) {
            _firstOneDowunUpModel = nil;
        }
        
        if ([_lastOneDowunUpModel.downUpUUID isEqualToString:fileDownUpModel.downUpUUID]) {
            _lastOneDowunUpModel = nil;
        }
        //下一个.
        [weakself queueForMuiltTastWithFinishedModel:weakself.firstOneDowunUpModel currentMaxTaskCount:weakself.maxConcurrenceDownloadTasks.allValues.count];
        
    };
    
    //通知UI开始任务
    if (weakself.fileDownStatusChangeBlock) {
        weakself.fileDownStatusChangeBlock(fileDownUpModel);
    }
    
    
    //   });
    
    
}

//开始下一个任务(队头开始算)
//- (void)queueForTaskNextWithFinishedModel:(CSFileDownUpModel *)csfileDownUpModel
//{
//#warning next.last = nil ???..
//    __weak typeof(self)weakSelf = self;
//    if (csfileDownUpModel.downUpStatus == DownUpStatusWait && csfileDownUpModel) {
//        [self startOneDownloadWithDownUpFileModel:csfileDownUpModel];
//    }else{
//
//        //递归获取nextwait
//       [self getQueueUntileWaitTaskWithFinishedModel:csfileDownUpModel resultBlock:^(CSFileDownUpModel *nextFileDownUpModel) {
//
//           if (nextFileDownUpModel) {
//                [weakSelf startOneDownloadWithDownUpFileModel:nextFileDownUpModel];
//           }
//
//
//       }];
//    }
//
//}

//开始(可能的)多个任务.
- (void)queueForMuiltTastWithFinishedModel:(CSFileDownUpModel *)csfileDownUpModel currentMaxTaskCount:(NSInteger)currentMaxTaskCount
{
    __weak typeof(self)weakSelf = self;
    
    if (currentMaxTaskCount < self.maxConcurrenceDownloadCount) {
        
        if (csfileDownUpModel.downUpStatus == DownUpStatusWait && csfileDownUpModel ) {
            
            [self startOneDownloadWithDownUpFileModel:csfileDownUpModel];
            [self queueForMuiltTastWithFinishedModel:csfileDownUpModel.nextFileDownUpModel currentMaxTaskCount:currentMaxTaskCount + 1];
        }else{
            
            //递归获取nextwait
            
            
            [self getQueueUntileWaitTaskWithFinishedModel:csfileDownUpModel resultBlock:^(CSFileDownUpModel *nextFileDownUpModel) {
                
                if (nextFileDownUpModel) {
                    
                    [weakSelf startOneDownloadWithDownUpFileModel:nextFileDownUpModel];
                    [weakSelf queueForMuiltTastWithFinishedModel:csfileDownUpModel.nextFileDownUpModel currentMaxTaskCount:currentMaxTaskCount + 1];
                }
                
                
            }];
        }
        
    }
    
}

//查询下一个任务
- (void)getQueueUntileWaitTaskWithFinishedModel:(CSFileDownUpModel *)csfileDownUpModel resultBlock:(void(^)(CSFileDownUpModel *csfileDownUpModel))resultBlock
{
    if (!csfileDownUpModel) {
        resultBlock(nil);
        return;
    }
    
    if (csfileDownUpModel.nextFileDownUpModel) {
        if (csfileDownUpModel.nextFileDownUpModel.downUpStatus == DownUpStatusDoing) {
            
            csfileDownUpModel = csfileDownUpModel.nextFileDownUpModel;
            
            [self getQueueUntileWaitTaskWithFinishedModel:csfileDownUpModel resultBlock:resultBlock];
            
        }else if(csfileDownUpModel.nextFileDownUpModel.downUpStatus == DownUpStatusWait)resultBlock(csfileDownUpModel.nextFileDownUpModel);
        
    }else resultBlock(nil);
    
    
}


- (void)registeDownloadBlockForUIWithcsFileDownUpModel:(CSFileDownUpModel *)csFileDownUpModel ProcessBlock:(DownloadProgressUIBlock)processBlock successBlock:(DownloadSuccessUIBlock)successBlock failBlock:(DownloadFailedUIBlock)failBlock
{
    CloudDownloadSession *csDownUpSession = [self.maxConcurrenceDownloadTasks objectForKey:[self getTrueFileNmae_Md5:csFileDownUpModel]];
    
    if (csDownUpSession) {
        [csDownUpSession giveBlockToUIWithUUID:csFileDownUpModel.downUpUUID withProcessBlock:processBlock successBlock:successBlock failBlock:failBlock];
        
    }
}

//- (void)registeDownloadBlockForUIWithUUIDs:(NSArray *)UUIDs ProcessBlock:(DownloadProgressUIBlock)processBlock successBlock:(DownloadSuccessUIBlock)successBlock failBlock:(DownloadFailedUIBlock)failBlock
//{
//
//    for (NSString *uuid in UUIDs) {
//
//        CloudDownloadSession *csDownUpSession = [self.maxConcurrenceDownloadTasks objectForKey:[self getTrueFileNmae_Md5:uuid]];
//
//        if (csDownUpSession) {
//            [csDownUpSession giveBlockToUIWithUUID:uuid withProcessBlock:processBlock successBlock:successBlock failBlock:failBlock];
//            break;
//        }else continue;
//
//    }
//}

#warning 2017-07-18 待新增两个方法.
//只适用于单个任务,如果多任务,则队列需要重新整理.
- (void)updateOneDownloadStatusWithcsfileDownUpModel:(CSFileDownUpModel *)csfileDownUpModel downUpStatus:(DownUpStatus)downUpStatus
{
    __weak typeof(self)weakself = self;
    if (downUpStatus == DownUpStatusWait) {
        
        
        [self addOneDownloadWithFileDownUpModel:csfileDownUpModel];
        
    }else{
        
        CSFileDownUpModel *oldFilDownUpModel = [self.totalDownloadTasks objectForKey:csfileDownUpModel.downUpUUID];
        
        CloudDownloadSession *cloudUploadingSession = [self.maxConcurrenceDownloadTasks objectForKey:[self getTrueFileNmae_Md5:csfileDownUpModel]];
        
        if (cloudUploadingSession) {
            
            [cloudUploadingSession cancerDownLoad];
            
            [self.maxConcurrenceDownloadTasks removeObjectForKey:[self getTrueFileNmae_Md5:csfileDownUpModel]];
        }
        
        if (oldFilDownUpModel) {
            
            //重新排队
            if (oldFilDownUpModel.lastFileDownUpModel && oldFilDownUpModel.nextFileDownUpModel) {
                
                oldFilDownUpModel.lastFileDownUpModel.nextFileDownUpModel = oldFilDownUpModel.nextFileDownUpModel;
                
                oldFilDownUpModel.nextFileDownUpModel.lastFileDownUpModel = oldFilDownUpModel.lastFileDownUpModel;
            }else if (oldFilDownUpModel.nextFileDownUpModel && !oldFilDownUpModel.lastFileDownUpModel)
            {
                //只有下一个,没有上一个,说明是队头,
                
                //移除下一个的上一个,即指定下一个为头.
                oldFilDownUpModel.nextFileDownUpModel.lastFileDownUpModel = nil;
                
                weakself.firstOneDowunUpModel = oldFilDownUpModel.nextFileDownUpModel;
                
            }
            
            //next down(最大5个.)
            
            [self queueForMuiltTastWithFinishedModel:self.firstOneDowunUpModel currentMaxTaskCount:self.maxConcurrenceDownloadTasks.allValues.count];
            //            [self queueForTaskNextWithFinishedModel:weakself.firstOneDowunUpModel];
            
            
            [self.totalDownloadTasks removeObjectForKey:csfileDownUpModel.downUpUUID];
            
            if ([_firstOneDowunUpModel.downUpUUID isEqualToString:csfileDownUpModel.downUpUUID]) {
                _firstOneDowunUpModel = nil;
            }
            
            if ([_lastOneDowunUpModel.downUpUUID isEqualToString:csfileDownUpModel.downUpUUID]) {
                _lastOneDowunUpModel = nil;
            }
        }
        
        
        
    }
    
    
}

//注意队列线程安全
- (void)updateDownloadStatusWithcsfileDownUpModels:(NSArray<CSFileDownUpModel *> *)csfileDownUpModels downUpStatus:(DownUpStatus)downUpStatus
{
    __weak typeof(self)weakself = self;
    //1.全部暂停的,则全部移除队列并且重新排序.
    //2.全部开始的,则直接addin队列
    if (downUpStatus == DownUpStatusWait) {
        
        for (CSFileDownUpModel *csfileDownUpModel in csfileDownUpModels){
            
            [self addOneDownloadWithFileDownUpModel:csfileDownUpModel];
            
        }
        
    }else{
        
        
        //先移除进行中的任务
        for (CSFileDownUpModel *csfileDownUpModel in csfileDownUpModels){
            
            CSFileDownUpModel *oldFilDownUpModel = [self.totalDownloadTasks objectForKey:csfileDownUpModel.downUpUUID];
            
            CloudDownloadSession *cloudUploadingSession = [self.maxConcurrenceDownloadTasks objectForKey:[self getTrueFileNmae_Md5:csfileDownUpModel]];
            
            if (cloudUploadingSession) {
                
                [cloudUploadingSession cancerDownLoad];
                
                [self.maxConcurrenceDownloadTasks removeObjectForKey:[self getTrueFileNmae_Md5:csfileDownUpModel]];
            }
            
            if (oldFilDownUpModel) {
                
                //重新排队
                if (oldFilDownUpModel.lastFileDownUpModel && oldFilDownUpModel.nextFileDownUpModel) {
                    
                    oldFilDownUpModel.lastFileDownUpModel.nextFileDownUpModel = oldFilDownUpModel.nextFileDownUpModel;
                    
                    oldFilDownUpModel.nextFileDownUpModel.lastFileDownUpModel = oldFilDownUpModel.lastFileDownUpModel;
                }else if (oldFilDownUpModel.nextFileDownUpModel && !oldFilDownUpModel.lastFileDownUpModel)
                {
                    //只有下一个,没有上一个,说明是队头,
                    
                    //移除下一个的上一个,即指定下一个为头.
                    oldFilDownUpModel.nextFileDownUpModel.lastFileDownUpModel = nil;
                    
                    weakself.firstOneDowunUpModel = oldFilDownUpModel.nextFileDownUpModel;
                    
                }
                
                //待使用category.反之key=nil的情况.
                [self.totalDownloadTasks removeObjectForKey:csfileDownUpModel.downUpUUID];
                
                if ([_firstOneDowunUpModel.downUpUUID isEqualToString:csfileDownUpModel.downUpUUID]) {
                    _firstOneDowunUpModel = nil;
                }
                
                if ([_lastOneDowunUpModel.downUpUUID isEqualToString:csfileDownUpModel.downUpUUID]) {
                    _lastOneDowunUpModel = nil;
                }
            }
            
            
        }
        
        
        [self queueForMuiltTastWithFinishedModel:self.firstOneDowunUpModel currentMaxTaskCount:self.maxConcurrenceDownloadTasks.allValues.count];
        
        //同时更新2000多个.
        //             [kCloudStorageDB updateCSDownUpFileStatusWithCSFileDownUpModel:csfileDownUpModel];
    }
    
    if (downUpStatus !=  DownUpStatusDelete) {
        [kCloudStorageDB updateCSDownUpFileStatusWithCSFileDownUpModels:csfileDownUpModels downUpType:DownUpModelDown downUpStatus:downUpStatus];
    }
    
}
@end
