//
//  KMCloudOperation.m
//  PDF Reader
//
//  Created by wanjun on 2020/7/14.
//  Copyright © 2020 Kdan Mobile. All rights reserved.
//

#import "KMCloudOperation.h"
#import <ObjectiveDropboxOfficial/ObjectiveDropboxOfficial.h>
#import "GTMSessionFetcher.h"
#import "KMGoogleDriveManager.h"

@interface KMCloudOperation ()

@property (assign, nonatomic, getter = isExecuting)     BOOL executing;
@property (assign, nonatomic, getter = isFinished)      BOOL finished;
@property (assign, nonatomic, getter = isCancelled)     BOOL cancelled;

@property (nonatomic, strong) KMGoogleDriveManager *cloudModel;
@property (nonatomic, assign) BOOL isDownload;
@property (nonatomic, strong) NSURL *localPath;

/* Google Drive */
@property (nonatomic, strong) GTLRServiceTicket *uploadFileTicket;
@property (nonatomic, strong) GTLRServiceTicket *downloadFileTicket;
/* DropBox */
@property (nonatomic, retain) DBUploadTask *uploadTask;
@property (nonatomic, retain) DBDownloadUrlTask *downloadTask;

@property (nonatomic, strong) KMServicesCloudFile *fileData;

@property (nonatomic, copy) CurrentProgressCallBack progressCallBack;
@property (nonatomic, copy) CompletionCallBack callback;

@property (nonatomic,assign) long long downloadSize;
@property (nonatomic,assign) long long downloadTotalSize;

@end

@implementation KMCloudOperation

@synthesize executing       = _executing;
@synthesize finished        = _finished;
@synthesize cancelled       = _cancelled;

- (void)dealloc {}

#pragma mark - init

- (instancetype)initWithLoadCloudPath:(KMServicesCloudFile *)cloudPath
                           serverType:(KMServerType)serverType
                            localPath:(NSURL *)localPath
                            loadState:(KMCloudLoadState)state
                currentConvetProgress:(CurrentProgressCallBack)currentProgress
                           completion:(CompletionCallBack)completion {
    self = [super init];
    if (self) {
//        if (state) {
//            if (serverType == KMDropbox) {
//                self.fromPath = cloudPath.displayName;
//                self.toPath = [localPath path];
//            } else if (serverType == KMGoogleDrive) {
//                self.fromPath = cloudPath.fileId;
//                self.toPath = [localPath path];
//            }
//        } else {
//            if (serverType == KMDropbox) {
//                self.fromPath = [localPath path];
//                self.toPath = cloudPath.displayName;
//            } else if (serverType == KMGoogleDrive) {
//                self.fromPath = [localPath path];
//                self.toPath = cloudPath.fileId;
//            }
//        }
        self.fromPath = cloudPath;
        self.toPath = [localPath path];
        
        self.cloudLoadState = state;
        self.filePath = cloudPath.displayName;
        
        _serverType = serverType;
        _localPath = localPath;
        _isDownload = state;
        
        self.queuePriority = NSOperationQueuePriorityNormal;
        if (serverType == KMGoogleDrive) {
            _cloudModel = [KMGoogleDriveManager shareInstance];
        }
        self.fileData = cloudPath;
        
        self.name = self.filePath;
        self.executing = NO;
        self.finished = NO;
        self.progressCallBack = currentProgress;
        self.callback = completion;
        
        self.downloadSize = 0;
    }
    return self;
}

#pragma mark - setter

- (void)setExecuting:(BOOL)executing
{
    [self willChangeValueForKey:@"isExecuting"];
    _executing = executing;
    [self didChangeValueForKey:@"isExecuting"];
}

- (void)setFinished:(BOOL)finished
{
    [self willChangeValueForKey:@"isFinished"];
    _finished = finished;
    [self didChangeValueForKey:@"isFinished"];
}

- (void)setCancelled:(BOOL)cancelled
{
    [self willChangeValueForKey:@"isCancelled"];
    _cancelled = cancelled;
    [self didChangeValueForKey:@"isCancelled"];
}

#pragma mark - overwrite

- (void)start {
    if ([self p_checkCancelled]) {
        return;
    }
    
    if (self.cloudLoadState == KMCloudLoadState_Download) {
        dispatch_async(dispatch_get_main_queue(), ^{
            self.state = KMCloudDownLoadOperationStateStart;
            [[NSNotificationCenter defaultCenter] postNotificationName:KMServerCloudFileManagerDownloadStateChangeNotification object:self];
        });
    }
    
    self.executing  = YES;
    
    [NSThread detachNewThreadSelector:@selector(main) toTarget:self withObject:nil];
}

- (void)main {
    @try {
        if ([self p_checkCancelled]) {
            return;
        }
        if (_isDownload) {
            [self cloudDownloadDataWithCloudPath:self.fromPath localPath:_localPath];
        } else {
            [self cloudUploadDataWithCloudPath:self.toPath localPath:_localPath];
        }
        
        while (self.executing) {
            if ([self p_checkCancelled]) {
                return;
            }
        }
    }
    @catch (NSException * e) {
        NSLog(@"Exception %@", e);
    }
}

- (void)cancel
{
    [super cancel];
    
    if (_isDownload) {
        //取消下载
        if (_serverType == KMDropbox) {
            [self.downloadTask cancel];
        } else if (_serverType == KMGoogleDrive) {
            [_downloadFileTicket cancelTicket];
        }
    } else {
        //取消上传
        if (_serverType == KMDropbox) {
            [self.uploadTask cancel];
        } else if (_serverType == KMGoogleDrive) {
            [_uploadFileTicket cancelTicket];
        }
    }
    
    if (self.executing) {
        self.executing = NO;
        self.finished = YES;
    } else {
        self.finished = NO;
    }
    self.cancelled = YES;
    
    if (self.cloudLoadState == KMCloudLoadState_Download) {
        self.state = KMCloudDownLoadOperationStateCancel;
        [[NSNotificationCenter defaultCenter] postNotificationName:KMServerCloudFileManagerDownloadStateChangeNotification object:self];
    }
}

#pragma mark - private methods

- (void)p_done
{
    self.executing  = NO;
    self.finished   = YES;
}

- (BOOL)p_checkCancelled
{
    if (self.cancelled) {
        self.finished = YES;
        return YES;
    }
    return NO;
}

#pragma mark - updata

//暂时处理成根据上传到指定文件夹FileID的位置,需要添加替换功能,当文件重名时
- (void)cloudUploadDataWithCloudPath:(NSString *)cloudPath localPath:(NSURL *)localPath {
    if (_serverType == KMDropbox) {
        [self dropboxUploadDataWithCloudPath:_fromPath.displayName localPath:localPath];
    } else if (_serverType == KMGoogleDrive) {
        [self googleDriveUploadDataWithCloudPath:_fromPath.fileId localPath:localPath];
    }
}
//DropBox
- (void)dropboxUploadDataWithCloudPath:(NSString *)cloudPath localPath:(NSURL *)localPath {
    NSData *fileData = [[NSData alloc] initWithContentsOfURL:localPath];
    NSString * path = [NSString stringWithFormat:@"%@/%@",cloudPath,[[localPath path] lastPathComponent]];
    DBFILESWriteMode *mode = [[DBFILESWriteMode alloc] initWithOverwrite];
    
    DBUserClient *client = [DBClientsManager authorizedClient];
//    self.uploadTask = [client.filesRoutes uploadData:cloudPath mode:mode autorename:@(YES) clientModified:nil mute:@(NO) inputData:fileData];
//    self.uploadTask = [client.filesRoutes uploadData:path mode:mode autorename:@(YES) clientModified:nil mute:@(NO) propertyGroups:nil strictConflict:nil inputData:fileData];
    self.uploadTask = [client.filesRoutes uploadData:cloudPath mode:mode autorename:@(YES) clientModified:nil mute:@(NO) propertyGroups:nil strictConflict:nil contentHash:nil inputData:fileData];
    [[self.uploadTask setResponseBlock:^(DBFILESFileMetadata *result, DBFILESUploadError *routeError, DBRequestError *networkError) {
          if (result) {
              KMServicesCloudFile *fileModel = [[KMServicesCloudFile alloc] init];
              fileModel.client_modified = result.clientModified;
              fileModel.fileModiDate = result.serverModified;
              fileModel.fileId = result.id_;
              fileModel.fileName = result.name;
              fileModel.displayName = result.pathDisplay;
              fileModel.path_lower = result.pathLower;
              fileModel.rev = result.rev;
              fileModel.fileSize = result.size.integerValue;
              fileModel.content_hash = result.contentHash;
              fileModel.filetype = KMCloudServiceFileType_File;
              if (_callback) {
                  _callback(self.fileData,YES);
              }
              NSDictionary *dict =[[NSDictionary alloc] initWithObjectsAndKeys:fileModel,@"CloudFile",nil];
              [[NSNotificationCenter defaultCenter] postNotificationName:KMServerCloudFileManagerUploadSuccessfulNotification object:self userInfo:dict];
              
              [self p_done];
          } else {
              [self cancel];
              
              KMDropboxErrorMetadata *errorModel = [[KMDropboxErrorMetadata alloc] init];
              errorModel.routeError = [NSNumber numberWithInteger:routeError.tag];
              errorModel.networkError = [NSNumber numberWithInteger:networkError.statusCode.integerValue];
              if (self.callback) {
                  self.callback(self.fileData,NO);
              }
              NSDictionary *dict =[[NSDictionary alloc] initWithObjectsAndKeys:errorModel,@"UploadError",nil];
              [[NSNotificationCenter defaultCenter] postNotificationName:KMServerCloudFileManagerUploadFailureNotification object:self userInfo:dict];
              
          }
        }] setProgressBlock:^(int64_t bytesUploaded, int64_t totalBytesUploaded, int64_t totalBytesExpectedToUploaded) {
            CGFloat loadProgress = totalBytesUploaded/(CGFloat)(totalBytesExpectedToUploaded);
            if (_progressCallBack) {
                _progressCallBack(self.fileData,loadProgress);
            }
    }];
}

//Goolge Drive
- (void)googleDriveUploadDataWithCloudPath:(NSString *)cloudPath localPath:(NSURL *)localPath {
    NSError *fileError;
    if (![localPath checkPromisedItemIsReachableAndReturnError:&fileError]) {
      return;
    }

    GTLRDriveService *service = _cloudModel.driveService;
    
    NSString *filename = [localPath lastPathComponent];
    NSString *mimeType = [self MIMETypeFileName:filename defaultMIMEType:@"binary/octet-stream"];
    NSData *fileData = [NSData dataWithContentsOfURL:localPath];
    
    GTLRUploadParameters *uploadParameters = [GTLRUploadParameters uploadParametersWithData:fileData
                                                                                   MIMEType:mimeType];
    GTLRDrive_File *metadata = [GTLRDrive_File object];
    metadata.name = localPath.lastPathComponent;
//    if ([cloudPath lengthOfBytesUsingEncoding:NSASCIIStringEncoding] > 0) {
//        metadata.parents = @[cloudPath];
//    }
    if (self.fromPath.parensID) {
        metadata.parents = @[self.fromPath.parensID];
    }
    GTLRDriveQuery_FilesCreate *query = [GTLRDriveQuery_FilesCreate queryWithObject:metadata
                                                                   uploadParameters:uploadParameters];
    query.fields = @"id";
    query.executionParameters.uploadProgressBlock = ^(GTLRServiceTicket *callbackTicket,
                                                      unsigned long long numberOfBytesRead,
                                                      unsigned long long dataLength) {
        CGFloat loadProgress = numberOfBytesRead/(CGFloat)(dataLength);
        if (_progressCallBack) {
            _progressCallBack(self.fileData,loadProgress);
        }
    };
    self.uploadFileTicket = [service executeQuery:query completionHandler:^(GTLRServiceTicket *ticket,
                                                         GTLRDrive_File *uploadedFile,
                                                         NSError *callbackError) {
            self.uploadFileTicket = nil;
            if (callbackError == nil) {
                // Succeeded
                KMServicesCloudFile *fileModel = [[KMServicesCloudFile alloc] init];
                fileModel.mimeType = uploadedFile.mimeType;
                fileModel.fileId = uploadedFile.identifier;
                fileModel.kind = uploadedFile.kind;
                fileModel.fileName = uploadedFile.name;
                fileModel.ownedByMe = uploadedFile.ownedByMe;
                fileModel.fileSize = uploadedFile.size.integerValue;
                fileModel.fileModiDate = uploadedFile.modifiedByMeTime.date;
                fileModel.lastUserName = uploadedFile.lastModifyingUser.displayName;
                fileModel.createdTime = uploadedFile.createdTime.date;
                fileModel.parensID = uploadedFile.parents[0];
                if (_callback) {
                    _callback(self.fileData,YES);
                }
                NSDictionary *dict =[[NSDictionary alloc] initWithObjectsAndKeys:self.fileData,@"CloudFile",nil];
                [[NSNotificationCenter defaultCenter] postNotificationName:KMServerCloudFileManagerUploadSuccessfulNotification object:self userInfo:dict];
                
                [self p_done];
            } else {
                NSLog(@"Upload Failed callbackError==%@",callbackError);
                [self cancel];
    
                if (self.callback) {
                    self.callback(self.fileData,NO);
                }
                [[NSNotificationCenter defaultCenter] postNotificationName:KMServerCloudFileManagerDownloadStateChangeNotification object:self];
                NSDictionary *dict =[[NSDictionary alloc] initWithObjectsAndKeys:callbackError,@"UploadError",nil];
                [[NSNotificationCenter defaultCenter] postNotificationName:KMServerCloudFileManagerUploadFailureNotification object:self userInfo:dict];
            }
        }];
}
- (NSString *)MIMETypeFileName:(NSString *)path
                    defaultMIMEType:(NSString *)defaultType {
  NSString *result = defaultType;
  NSString *extension = [path pathExtension];
  CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension,
      (__bridge CFStringRef)extension, NULL);
  if (uti) {
    CFStringRef cfMIMEType = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType);
    if (cfMIMEType) {
      result = CFBridgingRelease(cfMIMEType);
    }
    CFRelease(uti);
  }
  return result;
}

#pragma mark - downdata

- (void)cloudDownloadDataWithCloudPath:(KMServicesCloudFile *)cloudPath localPath:(NSURL *)localPath {
    if (_serverType == KMDropbox) {
        [self dropboxDownloadDataWithCloudPath:cloudPath localPath:localPath];
    } else if (_serverType == KMGoogleDrive) {
        [self googleDriveDownloadDataWithCloudPath:cloudPath localPath:localPath];
    }
}
//DropBox
- (void)dropboxDownloadDataWithCloudPath:(KMServicesCloudFile *)cloudPath localPath:(NSURL *)localPath {
    NSString *formString = cloudPath.displayName;

    NSString *fileType = [formString pathExtension];
    //判断文件是文件还是文件夹
    if ([fileType isEqualToString:@""]) {
        [self dropboxMultipleFilesDownloadWithPath:formString toPath:localPath];
    } else {
        [self dropboxSingleFileDownloadWithPath:formString toPath:localPath];
    }
}

//单个文件下载
- (void)dropboxSingleFileDownloadWithPath:(NSString *)fromPath toPath:(NSURL *)toPath {
    DBUserClient *client = [DBClientsManager authorizedClient];
    self.downloadTask = [client.filesRoutes downloadUrl:fromPath overwrite:NO destination:toPath];
    [[self.downloadTask setResponseBlock:^(DBFILESFileMetadata * _Nullable result, DBFILESDownloadError * _Nullable routeError, DBRequestError * _Nullable networkError, NSURL * _Nonnull destination) {
        if (result) {
            KMServicesCloudFile *fileModel = [[KMServicesCloudFile alloc] init];
            fileModel.client_modified = result.clientModified;
            fileModel.fileModiDate = result.serverModified;
            fileModel.fileId = result.id_;
            fileModel.fileName = result.name;
            fileModel.displayName = result.pathDisplay;
            fileModel.path_lower = result.pathLower;
            fileModel.rev = result.rev;
            fileModel.fileSize = result.size.integerValue;
            fileModel.content_hash = result.contentHash;
            fileModel.filetype = KMCloudServiceFileType_File;
            
            if (_callback) {
                _callback(self.fileData,YES);
            }
            
            if (self.cloudLoadState == KMCloudLoadState_Download) {
                self.state = KMCloudDownLoadOperationStateSuccess;
                NSDictionary *dict =[[NSDictionary alloc] initWithObjectsAndKeys:fileModel,@"CloudFile",nil];
                [[NSNotificationCenter defaultCenter] postNotificationName:KMServerCloudFileManagerDownloadStateChangeNotification object:self];
                [[NSNotificationCenter defaultCenter] postNotificationName:KMServerCloudFileManagerDownloadSuccessfulNotification object:self userInfo:dict];
            }
            
            [self p_done];
        } else {
            [self cancel];
            
            KMDropboxErrorMetadata *errorModel = [[KMDropboxErrorMetadata alloc] init];
            errorModel.routeError = [NSNumber numberWithInteger:routeError.tag];
            if (self.callback) {
                self.callback(self.fileData,NO);
            }
            
            if (self.cloudLoadState == KMCloudLoadState_Download) {
                self.state = KMCloudDownLoadOperationStateFail;
                [[NSNotificationCenter defaultCenter] postNotificationName:KMServerCloudFileManagerDownloadStateChangeNotification object:self];
                NSDictionary *dict =[[NSDictionary alloc] initWithObjectsAndKeys:errorModel,@"DownloadError",nil];
                [[NSNotificationCenter defaultCenter] postNotificationName:KMServerCloudFileManagerDownloadFailureNotification object:self userInfo:dict];
            }
            
        }
    }] setProgressBlock:^(int64_t bytesDownloaded, int64_t totalBytesDownloaded, int64_t totalBytesExpectedToDownload) {
        
        if (self.cloudLoadState == KMCloudLoadState_Download) {
            self.state = KMCloudDownLoadOperationStateProgress;
            self.downloadSize = (CGFloat)totalBytesDownloaded;
            self.downloadTotalSize = (CGFloat)totalBytesExpectedToDownload;
            [[NSNotificationCenter defaultCenter] postNotificationName:KMServerCloudFileManagerDownloadStateChangeNotification object:self];
        }
        
        CGFloat loadProgress = totalBytesDownloaded/(CGFloat)(totalBytesExpectedToDownload);
        if (_progressCallBack) {
            _progressCallBack(self.fileData,loadProgress);
        }
    }];
}

//多个文件下载为 Zip
- (void)dropboxMultipleFilesDownloadWithPath:(NSString *)fromPath toPath:(NSURL *)toPath {
    DBUserClient *client = [DBClientsManager authorizedClient];
//    self.downloadTask = [client.filesRoutes downloadZipUrl:fromPath overwrite:NO destination:toPath];
    [[self.downloadTask setResponseBlock:^(DBFILESFileMetadata * _Nullable result, DBFILESDownloadError * _Nullable routeError, DBRequestError * _Nullable networkError, NSURL * _Nonnull destination) {
          if (result) {
            KMServicesCloudFile *fileModel = [[KMServicesCloudFile alloc] init];
            fileModel.client_modified = result.clientModified;
            fileModel.fileModiDate = result.serverModified;
            fileModel.fileId = result.id_;
            fileModel.fileName = result.name;
            fileModel.displayName = result.pathDisplay;
            fileModel.path_lower = result.pathLower;
            fileModel.rev = result.rev;
              fileModel.fileSize = result.size.integerValue;
            fileModel.content_hash = result.contentHash;
            fileModel.filetype = KMCloudServiceFileType_File;
            
            if (_callback) {
                _callback(self.fileData,YES);
            }
              
            if (self.cloudLoadState == KMCloudLoadState_Download) {
                self.state = KMCloudDownLoadOperationStateSuccess;
                NSDictionary *dict =[[NSDictionary alloc] initWithObjectsAndKeys:fileModel,@"CloudFile",nil];
                [[NSNotificationCenter defaultCenter] postNotificationName:KMServerCloudFileManagerDownloadSuccessfulNotification object:self userInfo:dict];
            }
              
            [self p_done];
          } else {
              [self cancel];
              
              KMDropboxErrorMetadata *errorModel = [[KMDropboxErrorMetadata alloc] init];
              errorModel.routeError = [NSNumber numberWithInteger:routeError.tag];
              if (self.callback) {
                  self.callback(self.fileData,NO);
              }
              
              if (self.cloudLoadState == KMCloudLoadState_Download) {
                  self.state = KMCloudDownLoadOperationStateFail;
                  [[NSNotificationCenter defaultCenter] postNotificationName:KMServerCloudFileManagerDownloadStateChangeNotification object:self];
                  NSDictionary *dict =[[NSDictionary alloc] initWithObjectsAndKeys:errorModel,@"UploadError",nil];
                  [[NSNotificationCenter defaultCenter] postNotificationName:KMServerCloudFileManagerDownloadFailureNotification object:self userInfo:dict];
              }
              
          }
    }] setProgressBlock:^(int64_t bytesDownloaded, int64_t totalBytesDownloaded, int64_t totalBytesExpectedToDownload) {
        
        if (self.cloudLoadState == KMCloudLoadState_Download) {
            self.state = KMCloudDownLoadOperationStateProgress;
            [[NSNotificationCenter defaultCenter] postNotificationName:KMServerCloudFileManagerDownloadStateChangeNotification object:self];
        }
        
        CGFloat loadProgress = totalBytesDownloaded/(CGFloat)(totalBytesExpectedToDownload);
        if (_progressCallBack) {
            _progressCallBack(self.fileData,loadProgress);
        }
    }];
}

//Google Drive
- (void)googleDriveDownloadDataWithCloudPath:(KMServicesCloudFile *)cloudPath localPath:(NSURL *)localPath {
    NSString *fileType = @"";
    if ([cloudPath.mimeType isEqualToString:@"application/vnd.google-apps.presentation"]) {
        fileType = @"application/vnd.openxmlformats-officedocument.presentationml.presentation";
    } else if ([cloudPath.mimeType isEqualToString:@"application/vnd.google-apps.document"]) {
        fileType = @"application/vnd.openxmlformats-officedocument.wordprocessingml.document";
    } else if ([cloudPath.mimeType isEqualToString:@"application/vnd.google-apps.spreadsheet"]) {
        fileType = @"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
    } else if ([cloudPath.mimeType isEqualToString:@"application/vnd.google-apps.form"]) {
        fileType = @"text/csv";
    } else if ([cloudPath.mimeType isEqualToString:@"application/vnd.google-apps.map"]) {
        fileType = @"application/vnd.google-apps.script+json";
    } else if ([cloudPath.mimeType isEqualToString:@"application/vnd.google-apps.drawing"]) {
        fileType = @"image/jpeg";
    } else if ([cloudPath.mimeType isEqualToString:@"application/vnd.google-apps.site"]) {
        fileType = @"text/html";
    } else if([cloudPath.mimeType isEqualToString:@"application/vnd.google-apps.script"]) {
        fileType = @"application/vnd.google-apps.script+json";
    } else if([cloudPath.mimeType isEqualToString:@"application/vnd.google-apps.photo"]) {
        fileType = @"image/jpeg";
    }
    
    NSString *formString = cloudPath.fileId;
    
    GTLRDriveService *service = _cloudModel.driveService;
    GTLRQuery *query = [GTLRDriveQuery_FilesExport queryForMediaWithFileId:formString mimeType:fileType];
    if ([fileType isEqualToString:@""]) {
        query = [GTLRDriveQuery_FilesGet queryForMediaWithFileId:formString];
    } else {
        query = [GTLRDriveQuery_FilesExport queryForMediaWithFileId:formString mimeType:fileType];
    }
    
    //下载进度
    self.downloadFileTicket = [service executeQuery:query
                              completionHandler:^(GTLRServiceTicket *callbackTicket,
                                                  GTLRDataObject *object,
                                                  NSError *callbackError) {
        NSError *errorToReport = callbackError;
        NSError *writeError;
        self.downloadFileTicket = nil;
        if (callbackError == nil) {
            NSLog(@"object == %@ toPath==%@",object,[localPath path]);
            BOOL didSave = [object.data writeToURL:localPath
                                       options:NSDataWritingAtomic
                                         error:&writeError];
            if (!didSave) {
                errorToReport = writeError;
            }
        }
        if (errorToReport == nil) {
            NSLog(@"Downloaded == %@", [localPath path]);
            KMServicesCloudFile *fileModel = [[KMServicesCloudFile alloc] init];
            fileModel.fileId = formString;
            
            if (_callback) {
                _callback(self.fileData,YES);
            }
            
            if (self.cloudLoadState == KMCloudLoadState_Download) {
                self.state = KMCloudDownLoadOperationStateSuccess;
                NSDictionary *dict =[[NSDictionary alloc] initWithObjectsAndKeys:self.fileData,@"CloudFile",nil];
                [[NSNotificationCenter defaultCenter] postNotificationName:KMServerCloudFileManagerDownloadSuccessfulNotification object:self userInfo:dict];
            }
            
            [self p_done];
        } else {
            NSLog(@"Error Downloading File == %@", errorToReport);
            [self cancel];
            if (self.cloudLoadState == KMCloudLoadState_Download) {
                self.state = KMCloudDownLoadOperationStateFail;
                [[NSNotificationCenter defaultCenter] postNotificationName:KMServerCloudFileManagerDownloadStateChangeNotification object:self];
                [[NSNotificationCenter defaultCenter] postNotificationName:KMServerCloudFileManagerDownloadFailureNotification object:self userInfo:nil];
            }
            if (_callback) {
                _callback(self.fileData,NO);
            }
        }
        }];
}

@end