//
//  ZYJOSSHttpResponseParser.m
//  AliyunZYJOSSSDK
//
//  Created by huaixu on 2018/1/22.
//  Copyright © 2018年 aliyun. All rights reserved.
//

#import "ZYJOSSHttpResponseParser.h"

#import "NSMutableData+ZYJOSS_CRC.h"
#import "ZYJOSSXMLDictionary.h"
#import "ZYJOSSDefine.h"
#import "ZYJOSSModel.h"
#import "ZYJOSSUtil.h"
#import "ZYJOSSLog.h"
#import "ZYJOSSGetObjectACLResult.h"
#import "ZYJOSSDeleteMultipleObjectsResult.h"
#import "ZYJOSSGetBucketInfoResult.h"
#import "ZYJOSSRestoreObjectResult.h"
#import "ZYJOSSPutSymlinkResult.h"
#import "ZYJOSSGetSymlinkResult.h"


@implementation ZYJOSSHttpResponseParser {
    
    ZYJOSSOperationType _operationTypeForThisParser;
    
    NSFileHandle * _fileHandle;
    NSMutableData * _collectingData;
    NSHTTPURLResponse * _response;
    uint64_t _crc64ecma;
}

- (void)reset {
    _collectingData = nil;
    _fileHandle = nil;
    _response = nil;
}

- (instancetype)initForOperationType:(ZYJOSSOperationType)operationType {
    if (self = [super init]) {
        _operationTypeForThisParser = operationType;
    }
    return self;
}

- (void)consumeHttpResponse:(NSHTTPURLResponse *)response {
    _response = response;
}

- (ZYJOSSTask *)consumeHttpResponseBody:(NSData *)data
{
    if (_crc64Verifiable&&(_operationTypeForThisParser == ZYJOSSOperationTypeGetObject))
    {
        NSMutableData *mutableData = [NSMutableData dataWithData:data];
        if (_crc64ecma != 0)
        {
            _crc64ecma = [ZYJOSSUtil crc64ForCombineCRC1:_crc64ecma
                                                 CRC2:[mutableData ZYJOSS_crc64]
                                               length:mutableData.length];
        }else
        {
            _crc64ecma = [mutableData ZYJOSS_crc64];
        }
    }
    
    if (self.onRecieveBlock) {
        self.onRecieveBlock(data);
        return [ZYJOSSTask taskWithResult:nil];
    }
    
    NSError * error;
    if (self.downloadingFileURL)
    {
        if (!_fileHandle)
        {
            NSFileManager * fm = [NSFileManager defaultManager];
            NSString * dirName = [[self.downloadingFileURL path] stringByDeletingLastPathComponent];
            if (![fm fileExistsAtPath:dirName])
            {
                [fm createDirectoryAtPath:dirName withIntermediateDirectories:YES attributes:nil error:&error];
            }
            if (![fm fileExistsAtPath:dirName] || error)
            {
                return [ZYJOSSTask taskWithError:[NSError errorWithDomain:ZYJOSSClientErrorDomain
                                                                  code:ZYJOSSClientErrorCodeFileCantWrite
                                                              userInfo:@{ZYJOSSErrorMessageTOKEN: [NSString stringWithFormat:@"Can't create dir at %@", dirName]}]];
            }
            [fm createFileAtPath:[self.downloadingFileURL path] contents:nil attributes:nil];
            if (![fm fileExistsAtPath:[self.downloadingFileURL path]])
            {
                return [ZYJOSSTask taskWithError:[NSError errorWithDomain:ZYJOSSClientErrorDomain
                                                                  code:ZYJOSSClientErrorCodeFileCantWrite
                                                              userInfo:@{ZYJOSSErrorMessageTOKEN: [NSString stringWithFormat:@"Can't create file at %@", [self.downloadingFileURL path]]}]];
            }
            _fileHandle = [NSFileHandle fileHandleForWritingToURL:self.downloadingFileURL error:&error];
            if (error)
            {
                return [ZYJOSSTask taskWithError:[NSError errorWithDomain:ZYJOSSClientErrorDomain
                                                                  code:ZYJOSSClientErrorCodeFileCantWrite
                                                              userInfo:[error userInfo]]];
            }
            [_fileHandle writeData:data];
        } else
        {
            @try {
                [_fileHandle writeData:data];
            }
            @catch (NSException *exception) {
                return [ZYJOSSTask taskWithError:[NSError errorWithDomain:ZYJOSSServerErrorDomain
                                                                  code:ZYJOSSClientErrorCodeFileCantWrite
                                                              userInfo:@{ZYJOSSErrorMessageTOKEN: [exception description]}]];
            }
        }
    } else
    {
        if (!_collectingData)
        {
            _collectingData = [[NSMutableData alloc] initWithData:data];
        }
        else
        {
            [_collectingData appendData:data];
        }
    }
    return [ZYJOSSTask taskWithResult:nil];
}

- (void)parseResponseHeader:(NSHTTPURLResponse *)response toResultObject:(ZYJOSSResult *)result
{
    result.httpResponseCode = [_response statusCode];
    result.httpResponseHeaderFields = [NSDictionary dictionaryWithDictionary:[_response allHeaderFields]];
    [[_response allHeaderFields] enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
        NSString * keyString = (NSString *)key;
        if ([keyString isEqualToString:@"x-oss-request-id"])
        {
            result.requestId = obj;
        }
        else if ([keyString isEqualToString:@"x-oss-hash-crc64ecma"])
        {
            result.remoteCRC64ecma = obj;
        }
    }];
}

- (NSDictionary *)parseResponseHeaderToGetMeta:(NSHTTPURLResponse *)response
{
    NSMutableDictionary * meta = [NSMutableDictionary new];
    
    /* define a constant array to contain all meta header name */
    static NSArray * ZYJOSSObjectMetaFieldNames = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        ZYJOSSObjectMetaFieldNames = @[@"Content-Type", @"Content-Length", @"Etag", @"Last-Modified", @"x-oss-request-id", @"x-oss-object-type",
                                    @"If-Modified-Since", @"If-Unmodified-Since", @"If-Match", @"If-None-Match"];
    });
    /****************************************************************/
    
    [[_response allHeaderFields] enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
        NSString * keyString = (NSString *)key;
        if ([ZYJOSSObjectMetaFieldNames containsObject:keyString] || [keyString hasPrefix:@"x-oss-meta"]) {
            [meta setObject:obj forKey:key];
        }
    }];
    return meta;
}

- (nullable id)constructResultObject
{
    if (self.onRecieveBlock)
    {
        return nil;
    }
    
    switch (_operationTypeForThisParser)
    {
        case ZYJOSSOperationTypeGetService:
        {
            ZYJOSSGetServiceResult * getServiceResult = [ZYJOSSGetServiceResult new];
            if (_response)
            {
                [self parseResponseHeader:_response toResultObject:getServiceResult];
            }
            if (_collectingData)
            {
                NSDictionary * parseDict = [NSDictionary ZYJOSS_dictionaryWithXMLData:_collectingData];
                ZYJOSSLogVerbose(@"Get service dict: %@", parseDict);
                if (parseDict)
                {
                    getServiceResult.ownerId = [[parseDict objectForKey:ZYJOSSOwnerXMLTOKEN] objectForKey:ZYJOSSIDXMLTOKEN];
                    getServiceResult.ownerDispName = [[parseDict objectForKey:ZYJOSSOwnerXMLTOKEN] objectForKey:ZYJOSSDisplayNameXMLTOKEN];
                    getServiceResult.prefix = [parseDict objectForKey:ZYJOSSPrefixXMLTOKEN];
                    getServiceResult.marker = [parseDict objectForKey:ZYJOSSMarkerXMLTOKEN];
                    getServiceResult.maxKeys = [[parseDict objectForKey:ZYJOSSMaxKeysXMLTOKEN] intValue];
                    getServiceResult.isTruncated = [[parseDict objectForKey:ZYJOSSIsTruncatedXMLTOKEN] boolValue];
                    
                    id bucketObject = [[parseDict objectForKey:ZYJOSSBucketsXMLTOKEN] objectForKey:ZYJOSSBucketXMLTOKEN];
                    if ([bucketObject isKindOfClass:[NSArray class]]) {
                        getServiceResult.buckets = bucketObject;
                    } else if ([bucketObject isKindOfClass:[NSDictionary class]]) {
                        NSArray * arr = [NSArray arrayWithObject:bucketObject];
                        getServiceResult.buckets = arr;
                    } else {
                        getServiceResult.buckets = nil;
                    }
                }
            }
            return getServiceResult;
        }
            
        case ZYJOSSOperationTypeCreateBucket:
        {
            ZYJOSSCreateBucketResult * createBucketResult = [ZYJOSSCreateBucketResult new];
            if (_response)
            {
                [self parseResponseHeader:_response toResultObject:createBucketResult];
                [_response.allHeaderFields enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
                    if ([((NSString *)key) isEqualToString:@"Location"]) {
                        createBucketResult.location = obj;
                        *stop = YES;
                    }
                }];
            }
            return createBucketResult;
        }
            
        case ZYJOSSOperationTypeGetBucketACL:
        {
            ZYJOSSGetBucketACLResult * getBucketACLResult = [ZYJOSSGetBucketACLResult new];
            if (_response)
            {
                [self parseResponseHeader:_response toResultObject:getBucketACLResult];
            }
            if (_collectingData)
            {
                NSDictionary * parseDict = [NSDictionary ZYJOSS_dictionaryWithXMLData:_collectingData];
                ZYJOSSLogVerbose(@"Get service dict: %@", parseDict);
                if (parseDict)
                {
                    getBucketACLResult.aclGranted = [[parseDict objectForKey:ZYJOSSAccessControlListXMLTOKEN] objectForKey:ZYJOSSGrantXMLTOKEN];
                }
            }
            return getBucketACLResult;
        }
            
        case ZYJOSSOperationTypeDeleteBucket:
        {
            ZYJOSSDeleteBucketResult * deleteBucketResult = [ZYJOSSDeleteBucketResult new];
            if (_response) {
                [self parseResponseHeader:_response toResultObject:deleteBucketResult];
            }
            return deleteBucketResult;
        }
            
        case ZYJOSSOperationTypeGetBucket:
        {
            ZYJOSSGetBucketResult * getBucketResult = [ZYJOSSGetBucketResult new];
            if (_response) {
                [self parseResponseHeader:_response toResultObject:getBucketResult];
            }
            if (_collectingData) {
                NSDictionary * parsedDict = [NSDictionary ZYJOSS_dictionaryWithXMLData:_collectingData];
                ZYJOSSLogVerbose(@"Get bucket dict: %@", parsedDict);
                
                if (parsedDict) {
                    getBucketResult.bucketName = [parsedDict objectForKey:ZYJOSSNameXMLTOKEN];
                    getBucketResult.prefix = [parsedDict objectForKey:ZYJOSSPrefixXMLTOKEN];
                    getBucketResult.marker = [parsedDict objectForKey:ZYJOSSMarkerXMLTOKEN];
                    getBucketResult.nextMarker = [parsedDict objectForKey:ZYJOSSNextMarkerXMLTOKEN];
                    getBucketResult.maxKeys = (int32_t)[[parsedDict objectForKey:ZYJOSSMaxKeysXMLTOKEN] integerValue];
                    getBucketResult.delimiter = [parsedDict objectForKey:ZYJOSSDelimiterXMLTOKEN];
                    getBucketResult.isTruncated = [[parsedDict objectForKey:ZYJOSSIsTruncatedXMLTOKEN] boolValue];
                    
                    id contentObject = [parsedDict objectForKey:ZYJOSSContentsXMLTOKEN];
                    if ([contentObject isKindOfClass:[NSArray class]]) {
                        getBucketResult.contents = contentObject;
                    } else if ([contentObject isKindOfClass:[NSDictionary class]]) {
                        NSArray * arr = [NSArray arrayWithObject:contentObject];
                        getBucketResult.contents = arr;
                    } else {
                        getBucketResult.contents = nil;
                    }
                    
                    NSMutableArray * commentPrefixesArr = [NSMutableArray new];
                    id commentPrefixes = [parsedDict objectForKey:ZYJOSSCommonPrefixesXMLTOKEN];
                    if ([commentPrefixes isKindOfClass:[NSArray class]]) {
                        for (NSDictionary * prefix in commentPrefixes) {
                            [commentPrefixesArr addObject:[prefix objectForKey:@"Prefix"]];
                        }
                    } else if ([commentPrefixes isKindOfClass:[NSDictionary class]]) {
                        [commentPrefixesArr addObject:[(NSDictionary *)commentPrefixes objectForKey:@"Prefix"]];
                    } else {
                        commentPrefixesArr = nil;
                    }
                    
                    getBucketResult.commentPrefixes = commentPrefixesArr;
                }
            }
            return getBucketResult;
        }
            
        case ZYJOSSOperationTypeListMultipartUploads:
        {
            ZYJOSSListMultipartUploadsResult * listMultipartUploadsResult = [ZYJOSSListMultipartUploadsResult new];
            if (_response) {
                [self parseResponseHeader:_response toResultObject:listMultipartUploadsResult];
            }
            if (_collectingData) {
                NSDictionary * parsedDict = [NSDictionary ZYJOSS_dictionaryWithXMLData:_collectingData];
                ZYJOSSLogVerbose(@"List multipart uploads dict: %@", parsedDict);
                
                if (parsedDict) {
                    listMultipartUploadsResult.bucketName = [parsedDict objectForKey:ZYJOSSBucketXMLTOKEN];
                    listMultipartUploadsResult.prefix = [parsedDict objectForKey:ZYJOSSPrefixXMLTOKEN];
                    listMultipartUploadsResult.uploadIdMarker = [parsedDict objectForKey:ZYJOSSUploadIdMarkerXMLTOKEN];
                    listMultipartUploadsResult.nextUploadIdMarker = [parsedDict objectForKey:ZYJOSSUploadIdMarkerXMLTOKEN];
                    listMultipartUploadsResult.keyMarker = [parsedDict objectForKey:ZYJOSSKeyMarkerXMLTOKEN];
                    listMultipartUploadsResult.nextKeyMarker = [parsedDict objectForKey:ZYJOSSNextKeyMarkerXMLTOKEN];
                    listMultipartUploadsResult.maxUploads = (int32_t)[[parsedDict objectForKey:ZYJOSSMaxUploadsXMLTOKEN] integerValue];
                    listMultipartUploadsResult.delimiter = [parsedDict objectForKey:ZYJOSSDelimiterXMLTOKEN];
                    listMultipartUploadsResult.isTruncated = [[parsedDict objectForKey:ZYJOSSIsTruncatedXMLTOKEN] boolValue];
                    
                    id contentObject = [parsedDict objectForKey:ZYJOSSUploadXMLTOKEN];
                    if ([contentObject isKindOfClass:[NSArray class]]) {
                        listMultipartUploadsResult.uploads = contentObject;
                    } else if ([contentObject isKindOfClass:[NSDictionary class]]) {
                        NSArray * arr = [NSArray arrayWithObject:contentObject];
                        listMultipartUploadsResult.uploads = arr;
                    } else {
                        listMultipartUploadsResult.uploads = nil;
                    }
                    
                    NSMutableArray * commentPrefixesArr = [NSMutableArray new];
                    id commentPrefixes = [parsedDict objectForKey:ZYJOSSCommonPrefixesXMLTOKEN];
                    if ([commentPrefixes isKindOfClass:[NSArray class]]) {
                        for (NSDictionary * prefix in commentPrefixes) {
                            [commentPrefixesArr addObject:[prefix objectForKey:@"Prefix"]];
                        }
                    } else if ([commentPrefixes isKindOfClass:[NSDictionary class]]) {
                        [commentPrefixesArr addObject:[(NSDictionary *)commentPrefixes objectForKey:@"Prefix"]];
                    } else {
                        commentPrefixesArr = nil;
                    }
                    
                    listMultipartUploadsResult.commonPrefixes = commentPrefixesArr;
                }
            }
            return listMultipartUploadsResult;
        }
            
        case ZYJOSSOperationTypeHeadObject:
        {
            ZYJOSSHeadObjectResult * headObjectResult = [ZYJOSSHeadObjectResult new];
            if (_response)
            {
                [self parseResponseHeader:_response toResultObject:headObjectResult];
                headObjectResult.objectMeta = [self parseResponseHeaderToGetMeta:_response];
            }
            return headObjectResult;
        }
            
        case ZYJOSSOperationTypeGetObject:
        {
            ZYJOSSGetObjectResult * getObejctResult = [ZYJOSSGetObjectResult new];
            ZYJOSSLogDebug(@"GetObjectResponse: %@", _response);
            if (_response)
            {
                [self parseResponseHeader:_response toResultObject:getObejctResult];
                getObejctResult.objectMeta = [self parseResponseHeaderToGetMeta:_response];
                if (_crc64ecma != 0)
                {
                    getObejctResult.localCRC64ecma = [NSString stringWithFormat:@"%llu",_crc64ecma];
                }
            }
            if (_fileHandle) {
                [_fileHandle closeFile];
            }
            
            if (_collectingData) {
                getObejctResult.downloadedData = _collectingData;
            }
            return getObejctResult;
        }
        case ZYJOSSOperationTypeGetObjectACL:
        {
            ZYJOSSGetObjectACLResult * getObjectACLResult = [ZYJOSSGetObjectACLResult new];
            ZYJOSSLogDebug(@"GetObjectResponse: %@", _response);
            if (_response)
            {
                [self parseResponseHeader:_response toResultObject:getObjectACLResult];
            }
            
            if (_collectingData) {
                NSDictionary * parseDict = [NSDictionary ZYJOSS_dictionaryWithXMLData:_collectingData];
                ZYJOSSLogVerbose(@"Get service dict: %@", parseDict);
                getObjectACLResult.grant = parseDict[@"AccessControlList"][@"Grant"];
            }
            
            
            return getObjectACLResult;
        }
            
        case ZYJOSSOperationTypePutObject:
        {
            ZYJOSSPutObjectResult * putObjectResult = [ZYJOSSPutObjectResult new];
            if (_response)
            {
                [self parseResponseHeader:_response toResultObject:putObjectResult];
                [_response.allHeaderFields enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
                    if ([((NSString *)key) isEqualToString:@"Etag"]) {
                        putObjectResult.eTag = obj;
                        *stop = YES;
                    }
                }];
            }
            if (_collectingData) {
                putObjectResult.serverReturnJsonString = [[NSString alloc] initWithData:_collectingData encoding:NSUTF8StringEncoding];
            }
            return putObjectResult;
        }
            
        case ZYJOSSOperationTypeAppendObject:
        {
            ZYJOSSAppendObjectResult * appendObjectResult = [ZYJOSSAppendObjectResult new];
            if (_response) {
                [self parseResponseHeader:_response toResultObject:appendObjectResult];
                [_response.allHeaderFields enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
                    if ([((NSString *)key) isEqualToString:@"Etag"]) {
                        appendObjectResult.eTag = obj;
                    }
                    if ([((NSString *)key) isEqualToString:@"x-oss-next-append-position"]) {
                        appendObjectResult.xZYJOSSNextAppendPosition = [((NSString *)obj) longLongValue];
                    }
                }];
            }
            return appendObjectResult;
        }
            
        case ZYJOSSOperationTypeDeleteObject: {
            ZYJOSSDeleteObjectResult * deleteObjectResult = [ZYJOSSDeleteObjectResult new];
            if (_response) {
                [self parseResponseHeader:_response toResultObject:deleteObjectResult];
            }
            return deleteObjectResult;
        }
        case ZYJOSSOperationTypeDeleteMultipleObjects: {
            ZYJOSSDeleteMultipleObjectsResult * deleteObjectResult = [ZYJOSSDeleteMultipleObjectsResult new];
            if (_response) {
                [self parseResponseHeader:_response toResultObject:deleteObjectResult];
            }
            
            if (_collectingData) {
                NSDictionary *dict = [NSDictionary ZYJOSS_dictionaryWithXMLData:_collectingData];
                deleteObjectResult.encodingType = dict[@"EncodingType"];
                deleteObjectResult.deletedObjects = dict[@"Deleted"];
            }
            
            return deleteObjectResult;
        }
        case ZYJOSSOperationTypePutObjectACL: {
            ZYJOSSPutObjectACLResult * putObjectACLResult = [ZYJOSSPutObjectACLResult new];
            if (_response) {
                [self parseResponseHeader:_response toResultObject:putObjectACLResult];
            }
            return putObjectACLResult;
        }
            
        case ZYJOSSOperationTypeCopyObject: {
            ZYJOSSCopyObjectResult * copyObjectResult = [ZYJOSSCopyObjectResult new];
            if (_response) {
                [self parseResponseHeader:_response toResultObject:copyObjectResult];
            }
            if (_collectingData) {
                ZYJOSSLogVerbose(@"copy object dict: %@", [NSDictionary ZYJOSS_dictionaryWithXMLData:_collectingData]);
                NSDictionary * parsedDict = [NSDictionary ZYJOSS_dictionaryWithXMLData:_collectingData];
                if (parsedDict) {
                    copyObjectResult.lastModifed = [parsedDict objectForKey:ZYJOSSLastModifiedXMLTOKEN];
                    copyObjectResult.eTag = [parsedDict objectForKey:ZYJOSSETagXMLTOKEN];
                }
            }
            return copyObjectResult;
        }
            
        case ZYJOSSOperationTypeInitMultipartUpload: {
            ZYJOSSInitMultipartUploadResult * initMultipartUploadResult = [ZYJOSSInitMultipartUploadResult new];
            if (_response) {
                [self parseResponseHeader:_response toResultObject:initMultipartUploadResult];
            }
            if (_collectingData) {
                NSDictionary * parsedDict = [NSDictionary ZYJOSS_dictionaryWithXMLData:_collectingData];
                ZYJOSSLogVerbose(@"init multipart upload result: %@", parsedDict);
                if (parsedDict) {
                    initMultipartUploadResult.uploadId = [parsedDict objectForKey:ZYJOSSUploadIdXMLTOKEN];
                }
            }
            return initMultipartUploadResult;
        }
            
        case ZYJOSSOperationTypeUploadPart: {
            ZYJOSSUploadPartResult * uploadPartResult = [ZYJOSSUploadPartResult new];
            if (_response) {
                [self parseResponseHeader:_response toResultObject:uploadPartResult];
                [_response.allHeaderFields enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
                    if ([((NSString *)key) isEqualToString:@"Etag"]) {
                        uploadPartResult.eTag = obj;
                        *stop = YES;
                    }
                }];
            }
            return uploadPartResult;
        }
            
        case ZYJOSSOperationTypeCompleteMultipartUpload: {
            ZYJOSSCompleteMultipartUploadResult * completeMultipartUploadResult = [ZYJOSSCompleteMultipartUploadResult new];
            if (_response) {
                [self parseResponseHeader:_response toResultObject:completeMultipartUploadResult];
            }
            if (_collectingData) {
                if ([[[_response.allHeaderFields objectForKey:ZYJOSSHttpHeaderContentType] description] isEqual:@"application/xml"]) {
                    ZYJOSSLogVerbose(@"complete multipart upload result: %@", [NSDictionary ZYJOSS_dictionaryWithXMLData:_collectingData]);
                    NSDictionary * parsedDict = [NSDictionary ZYJOSS_dictionaryWithXMLData:_collectingData];
                    if (parsedDict) {
                        completeMultipartUploadResult.location = [parsedDict objectForKey:ZYJOSSLocationXMLTOKEN];
                        completeMultipartUploadResult.eTag = [parsedDict objectForKey:ZYJOSSETagXMLTOKEN];
                    }
                } else {
                    completeMultipartUploadResult.serverReturnJsonString = [[NSString alloc] initWithData:_collectingData encoding:NSUTF8StringEncoding];
                }
            }
            return completeMultipartUploadResult;
        }
            
        case ZYJOSSOperationTypeListMultipart: {
            ZYJOSSListPartsResult * listPartsReuslt = [ZYJOSSListPartsResult new];
            if (_response) {
                [self parseResponseHeader:_response toResultObject:listPartsReuslt];
            }
            if (_collectingData) {
                NSDictionary * parsedDict = [NSDictionary ZYJOSS_dictionaryWithXMLData:_collectingData];
                ZYJOSSLogVerbose(@"list multipart upload result: %@", parsedDict);
                if (parsedDict) {
                    listPartsReuslt.nextPartNumberMarker = [[parsedDict objectForKey:ZYJOSSNextPartNumberMarkerXMLTOKEN] intValue];
                    listPartsReuslt.maxParts = [[parsedDict objectForKey:ZYJOSSMaxPartsXMLTOKEN] intValue];
                    listPartsReuslt.isTruncated = [[parsedDict objectForKey:ZYJOSSIsTruncatedXMLTOKEN] boolValue];
                    
                    id partsObject = [parsedDict objectForKey:ZYJOSSPartXMLTOKEN];
                    if ([partsObject isKindOfClass:[NSArray class]]) {
                        listPartsReuslt.parts = partsObject;
                    } else if ([partsObject isKindOfClass:[NSDictionary class]]) {
                        NSArray * arr = [NSArray arrayWithObject:partsObject];
                        listPartsReuslt.parts = arr;
                    } else {
                        listPartsReuslt.parts = nil;
                    }
                }
            }
            return listPartsReuslt;
        }
            
        case ZYJOSSOperationTypeAbortMultipartUpload: {
            ZYJOSSAbortMultipartUploadResult * abortMultipartUploadResult = [ZYJOSSAbortMultipartUploadResult new];
            if (_response) {
                [self parseResponseHeader:_response toResultObject:abortMultipartUploadResult];
            }
            return abortMultipartUploadResult;
        }
        case ZYJOSSOperationTypeTriggerCallBack: {
            ZYJOSSCallBackResult *callbackResult = [ZYJOSSCallBackResult new];
            if (_response) {
                [self parseResponseHeader:_response toResultObject:callbackResult];
            }
            
            if (_collectingData) {
                if ([[[_response.allHeaderFields objectForKey:ZYJOSSHttpHeaderContentType] description] isEqual:@"application/xml"]) {
                    NSDictionary * parsedDict = [NSDictionary ZYJOSS_dictionaryWithXMLData:_collectingData];
                    ZYJOSSLogVerbose(@"callback trigger result<xml>: %@", parsedDict);
                    callbackResult.serverReturnXML = parsedDict;
                } else if ([[[_response.allHeaderFields objectForKey:ZYJOSSHttpHeaderContentType] description] isEqual:@"application/json"]) {
                    callbackResult.serverReturnJsonString = [[NSString alloc] initWithData:_collectingData encoding:NSUTF8StringEncoding];
                    ZYJOSSLogVerbose(@"callback trigger result<json>: %@", callbackResult.serverReturnJsonString);
                }
            }
            return callbackResult;
        }
        case ZYJOSSOperationTypeImagePersist: {
            ZYJOSSImagePersistResult *imagePersistResult = [ZYJOSSImagePersistResult new];
            if (_response) {
                [self parseResponseHeader:_response toResultObject:imagePersistResult];
            }
            return imagePersistResult;
        }
        case ZYJOSSOperationTypeGetBucketInfo: {
            ZYJOSSGetBucketInfoResult *bucketInfoResult = [[ZYJOSSGetBucketInfoResult alloc] init];
            if (_collectingData)
            {
                NSDictionary * parseDict = [NSDictionary ZYJOSS_dictionaryWithXMLData:_collectingData];
                if ([parseDict valueForKey:@"Bucket"])
                {
                    NSDictionary *result = [parseDict valueForKey:@"Bucket"];
                    ZYJOSSLogVerbose(@"Get bucketInfo dict: %@", parseDict);
                    bucketInfoResult.bucketName = [result valueForKey:@"Name"];
                    bucketInfoResult.storageClass = [result valueForKey:@"StorageClass"];
                    bucketInfoResult.location = [result valueForKey:@"Location"];
                    bucketInfoResult.intranetEndpoint = [result valueForKey:@"IntranetEndpoint"];
                    bucketInfoResult.extranetEndpoint = [result valueForKey:@"ExtranetEndpoint"];
                    bucketInfoResult.creationDate = [result valueForKey:@"CreationDate"];
                    
                    if ([result valueForKey:@"Owner"]) {
                        bucketInfoResult.owner = [[ZYJOSSBucketOwner alloc] init];
                        bucketInfoResult.owner.userName = [[result valueForKey:@"Owner"] valueForKey:@"DisplayName"];
                        bucketInfoResult.owner.userId = [[result valueForKey:@"Owner"] valueForKey:@"ID"];
                    }
                    
                    if ([result valueForKey:@"AccessControlList"]) {
                        bucketInfoResult.acl = [ZYJOSSAccessControlList new];
                        bucketInfoResult.acl.grant = [[result valueForKey:@"AccessControlList"] valueForKey:@"Grant"];
                    }
                }
            }
            if (_response) {
                [self parseResponseHeader:_response toResultObject:bucketInfoResult];
            }
            return bucketInfoResult;
        }
        case ZYJOSSOperationTypeRestoreObject: {
            ZYJOSSRestoreObjectResult * restoreObjectResult = [ZYJOSSRestoreObjectResult new];
            if (_response) {
                [self parseResponseHeader:_response toResultObject:restoreObjectResult];
            }
            return restoreObjectResult;
        }
        case ZYJOSSOperationTypePutSymlink: {
            ZYJOSSPutSymlinkResult * putSymlinkResult = [ZYJOSSPutSymlinkResult new];
            if (_response) {
                [self parseResponseHeader:_response toResultObject:putSymlinkResult];
            }
            return putSymlinkResult;
        }
        case ZYJOSSOperationTypeGetSymlink: {
            ZYJOSSGetSymlinkResult * getSymlinkResult = [ZYJOSSGetSymlinkResult new];
            if (_response) {
                [self parseResponseHeader:_response toResultObject:getSymlinkResult];
            }
            return getSymlinkResult;
        }
        default: {
            ZYJOSSLogError(@"unknown operation type");
            break;
        }
    }
    return nil;
}

@end
