//
//  CODownloadManager.h
//  classonline
//
//  Created by hyz on 2019/2/25.
//  Copyright © 2019 offcn. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <Reachability/Reachability.h>
#import "WXCOMacros.h"

NS_ASSUME_NONNULL_BEGIN

/// 通知更新缓存管理中的列表信息
/// 在新增、移除、文件丢失、已下载完成时需要抛出该通知，更新下载列表
#define NotiUpdateDownloadInfo   @"NotiUpdateDownloadInfo"

@class CODownloadObject;
@class CODownloadModel;
@class CODownloadRejectModel;

/**
 * 大文件下载管理器，用于管理文件的下载和下载文件信息的存储，文件下载时对文件和文件信息都要存储，
    进入下载管理的文件不管是什么DownloadState都可以被删除，删除时要已下载的文件（如果本地有已下载的文件）和下载时保存的文件信息。
 *
 *
 * 下载时网络变化对下载的影响：注意以下networkChangeDownloadArrayM是同一个数组变量
 *
 * 1>、变为WI-FI时：检测networkChangeDownloadArrayM中是否有数据，如果有因网络变化被暂停的下载对象时，将这些对象开启下载，不用提示用户，
 *     并清空networkChangeDownloadArrayM数据。
 *
 * 2>、变为WALN时：先对正在下载中和等待下载中的下载对像做暂停处理，并将这些数据记录到networkChangeDownloadArrayM中，
 *     如果networkChangeDownloadArrayM有数据时弹框提示用户是否要消耗移动流量。如果用户不愿意使用流量，则流量下载暂停状态；
 *     如果用户愿意使用流量，则将记录的networkChangeDownloadArrayM数据还原成变化之前状态。并清空networkChangeDownloadArrayM数据
 *
 * 3>、变为无网络时：对正在下载中和等待下载中的下载对像做暂停处理，并将这些数据记录到networkChangeDownloadArrayM中。
 *
 * 下载状态说明：
 *
 * 0、未开启下载【stateNoDownload】：用户点击下载后生成下载模型时首先进入该状态。该状态则可以进入正在下载中（下载队列未到最大并发量时）、
 *                               等待下载（下载器已到最大并发量时）、暂停；如果处于WALN时提示用户将要消耗流量，用户同意则进入下载器，
 *                               否则将变为暂停状态，如果是无网络，则将变为暂停状态。
 *
 * 1、正在下载中【stateDownloading】：下载器正在从网络下载数据到本地。该状态可以进入等待下载（被强制插队）、暂停、完成、异常状态。
 *
 * 2、等待下载【stateWaiting】：下载器已达到最大下载并发量时，进入该状态，排队等候下载。
 *                           该状态可以进入正在下载中（强制插队，下载的顺序被移动到最前面）、暂停状态。
 *
 * 3、下载暂停【statePaused】：用户点击暂停、网络不可用、网络变为移动网络时化首先进入该状态。
 *                          该状态可以进入正在下载中（下载队列未到最大并发量时）、暂停状态。
 *
 * 4、下载完成【stateCompleted】：文件下载结束并且下载过程中没有发生错误时进入该状态。
 *
 * 5、下载异常【stateInterupt】：下载过程中发生错误时进入该状态，
 *                            该状态可以进入正在下载中（下载队列未到最大并发量时）、等待下载（下载器已到最大并发量时）。
 *
 * 6、下载完成一部分【stateCompletedPart】：文件夹下载，这是一个下载包，包含了若干个可下载的文件。PDF讲义库有用到该状态。
 *
 */
@interface CODownloadManager : NSObject

/// 包含了所有下载状态下的下载对象集合
@property (nonatomic, strong) NSMutableArray <CODownloadObject *> *allDownloads;
/// 处于下载队列中的下载对象集合
@property (nonatomic, strong) NSMutableArray <CODownloadObject *> *downloadingQueue;
/// 本次（优先）下载操作新生成的下载模型数据集合，用于批量插入下载模型数据到数据库
@property (nonatomic, strong, nullable) NSMutableArray <CODownloadModel *> *newDownloadModels;

/// framework add
/// 下载通道可以同时执行的下载的最大下载并发数量
@property (nonatomic, assign, readonly) NSInteger maxDownloadCount;

@property (nonatomic, assign) BOOL isReachable;
@property (nonatomic, assign) BOOL isViaWWAN;
@property (nonatomic, assign) BOOL isViaWiFi;

/// framework add

/// 单例对象
+ (instancetype)sharedInstance;

/// 通过读取当前用户本地存储的下载信息，重置下载队列和未完成下载的两个队列数据，以便执行下载操作
- (void)co_resetDownloadInfoWithUserID:(NSString *)userID;

/// 清空当前用户下全部有关下载的数据，包括已下载的文件和本地存储的下载信息，清理缓存时调用
- (void)co_emptyAllDownloadDataWithUserID:(NSString *)userID;

/// 退出登录时暂停当前用户下的可下载（正在下载中、等待下载）的对象
- (void)co_logoutPauseAllDownloadData;

/// 重新开启上次app退出时的正在下载或者等待下载对象，请在登录后调用该方法
- (void)co_restartDownloadByAppTerminate;

/// 网络状态变化时对处于下载（正在下载中、等待下载）的影响
/// @param network 变化后的网络状态
- (void)co_networkChanged:(NetworkStatus)network;

#pragma mark - 下载操作方法

/// 执行开始下载操作，可以指定是否执行优先下载
/// @param objectArray 下载对象数据的集合
/// @param block 下载被拒绝原因回调，rejectArray 回调中被拒原因数组
/// @param rejectArray 附加下载被拒原因数组，主要是生成下载时由于某些原因（下载URL为空、类型不支持等）造成的，和block回调中的rejectArray合并返回
/// @param isPriority 是否是要执行优先下载
- (void)co_startDownload:(NSMutableArray <CODownloadObject *>*)objectArray
     downloadRejectBlock:(nullable void (^)(NSMutableArray <CODownloadRejectModel *> * _Nullable rejectArray))block
        subjoinRejectionArray:(nullable NSMutableArray *)rejectArray
    withPriorityDownload:(BOOL)isPriority;

/// 执行暂停下载操作
/// @param objectArray 下载对象数据的集合
- (void)co_pauseDownload:(NSMutableArray <CODownloadObject *>*)objectArray;

/// 执行删除下载对象操作
/// @param objectArray 下载对象数据的集合
- (void)co_deleteDownload:(NSMutableArray <CODownloadObject *>*)objectArray userID:(NSString *)userID;

/// 执行完成下载对象操作
/// @param object 下载对象
- (void)co_completeDownload:(CODownloadObject *)object;

/// 推动下载队列
- (void)co_processDownloadQueue;

#pragma mark - 下载对象的相关方法

/// 通过下载URL获取下载对象，该方法只适用于通过URL执行的下载，回放类型是通过房间号和观看密码执行的下载，不适合该方法，如果没有匹配到数据，则返回nil
/// @param url 下载地址
/// @return 下载数据
- (CODownloadObject *)co_getDownloadObjectByUrl:(NSString *)url;

/// 检测下载对象是否已下载完成
/// @param object 下载对象
/// @return 下载对象是否已完成下载
- (BOOL)co_isDownloadCompleted:(CODownloadObject *)object;

/// 下载对象变为已完成状态
/// @param object 下载对象
- (void)downloadObject2CompleteState:(CODownloadObject *)object;

/// 下载完成时同步课件下载记录数据
/// @param model 下载模型
- (void)co_syncDownRecordForDownloadModel:(CODownloadModel *)model;

/// 完成下载记录同步后更改是否需要同步标记
/// @param lessonId 课件ID
- (void)co_completeDownloadSyncSignByLessonId:(NSString *)lessonId;

/// 登录成功后检查是否有需要同步的下载记录
- (void)co_loginSucceedCheckNeedSyncDownload;

/// 获取下载完成的下载对象集合
/// @param lessonType 课件类型
/// @return 下载完成的下载对象集合
- (NSMutableArray <CODownloadObject *> *)co_getCompletedDownloadObject:(COLessonType)lessonType;

/// 获取下载队列中的下载对象集合
/// @return 下载完成的下载对象集合
- (NSMutableArray <CODownloadObject *> *)co_getDownloadObjectInDownloadQueue;

/// 获取下载完成个数
/// @return 已完成的下载个数
- (NSInteger)co_getDownloadCompleteNum;

@end

NS_ASSUME_NONNULL_END
