//
//  ZYJOSSClient.h
//  ZYJOSS_ios_sdk
//
//  Created by zhouzhuo on 8/16/15.
//  Copyright (c) 2015 aliyun.com. All rights reserved.
//

#import <Foundation/Foundation.h>
@class ZYJOSSGetServiceRequest;
@class ZYJOSSCreateBucketRequest;
@class ZYJOSSDeleteBucketRequest;
@class ZYJOSSHeadObjectRequest;
@class ZYJOSSGetBucketRequest;
@class ZYJOSSGetBucketACLRequest;
@class ZYJOSSGetObjectRequest;
@class ZYJOSSGetObjectACLRequest;
@class ZYJOSSPutObjectRequest;
@class ZYJOSSPutObjectACLRequest;
@class ZYJOSSDeleteObjectRequest;
@class ZYJOSSDeleteMultipleObjectsRequest;
@class ZYJOSSCopyObjectRequest;
@class ZYJOSSInitMultipartUploadRequest;
@class ZYJOSSUploadPartRequest;
@class ZYJOSSCompleteMultipartUploadRequest;
@class ZYJOSSListPartsRequest;
@class ZYJOSSListMultipartUploadsRequest;
@class ZYJOSSAbortMultipartUploadRequest;
@class ZYJOSSAppendObjectRequest;
@class ZYJOSSResumableUploadRequest;
@class ZYJOSSMultipartUploadRequest;
@class ZYJOSSCallBackRequest;
@class ZYJOSSImagePersistRequest;
@class ZYJOSSGetBucketInfoRequest;
@class ZYJOSSPutSymlinkRequest;
@class ZYJOSSGetSymlinkRequest;
@class ZYJOSSRestoreObjectRequest;

@class ZYJOSSTask;
@class ZYJOSSExecutor;
@class ZYJOSSNetworking;
@class ZYJOSSClientConfiguration;
@protocol ZYJOSSCredentialProvider;

NS_ASSUME_NONNULL_BEGIN

/**
 ZYJOSSClient is the entry class to access ZYJOSS in an iOS client. It provides all the methods to communicate with ZYJOSS.
 Generally speaking, only one instance of ZYJOSSClient is needed in the whole app.
 */
@interface ZYJOSSClient : NSObject

/**
 ZYJOSS endpoint. It varies in different regions. Please check out ZYJOSS official website for the exact endpoints for your data.
 */
@property (nonatomic, strong) NSString * endpoint;

/**
 The networking instance for sending and receiving data
 */
@property (nonatomic, strong) ZYJOSSNetworking * networking;

/**
 The credential provider instance
 */
@property (nonatomic, strong) id<ZYJOSSCredentialProvider> credentialProvider;

/**
 Client configuration instance
 */
@property (nonatomic, strong) ZYJOSSClientConfiguration * clientConfiguration;

/**
 ZYJOSS operation task queue
 */
@property (nonatomic, strong, readonly) ZYJOSSExecutor * ZYJOSSOperationExecutor;

/**
 Initializes an ZYJOSSClient instance with the default client configuration.
 @endpoint it specifies domain of the bucket's region. Starting 2017, the domain must be prefixed with "https://" to follow Apple's ATS policy.
             For example: "https://ZYJOSS-cn-hangzhou.aliyuncs.com"
 @credentialProvider The credential provider
 */
- (instancetype)initWithEndpoint:(NSString *)endpoint
              credentialProvider:(id<ZYJOSSCredentialProvider>) credentialProvider;

/**
 Initializes an ZYJOSSClient with the custom client configuration.
 @endpoint it specifies domain of the bucket's region. Starting 2017, the domain must be prefixed with "https://" to follow Apple's ATS policy.
             For example: "https://ZYJOSS-cn-hangzhou.aliyuncs.com"
 @credentialProvider The credential provider
 @conf The custom client configuration such as retry time, timeout values, etc.
 */
- (instancetype)initWithEndpoint:(NSString *)endpoint
              credentialProvider:(id<ZYJOSSCredentialProvider>)credentialProvider
             clientConfiguration:(ZYJOSSClientConfiguration *)conf;

#pragma mark restful-api

/**
 The corresponding RESTFul API: GetService
 Gets all the buckets of the current user
 Notes：
 1. STS is not supported yet in this call.
 2. When all buckets are returned, the xml in response body does not have nodes of Prefix, Marker, MaxKeys, IsTruncated and NextMarker.
    If there're remaining buckets to return, the xml will have these nodes. The nextMarker is the value of marker in the next call.
 */
- (ZYJOSSTask *)getService:(ZYJOSSGetServiceRequest *)request;

@end


@interface ZYJOSSClient (Bucket)

/**
 The corresponding RESTFul API: PutBucket
 Creates a bucket--it does not support anonymous access. By default, the datacenter used is ZYJOSS-cn-hangzhou.
 Callers could explicitly specify the datacenter for the bucket to optimize the performance and cost or meet the regulation requirement.
 Notes:
 1. STS is not supported yet.
 */
- (ZYJOSSTask *)createBucket:(ZYJOSSCreateBucketRequest *)request;

/**
 The corresponding RESTFul API: DeleteBucket
 Deletes a bucket.
 */
- (ZYJOSSTask *)deleteBucket:(ZYJOSSDeleteBucketRequest *)request;

/**
 The corresponding RESTFul API: GetBucket
 Lists all objects in a bucket. It could be specified with filters such as prefix, marker, delimeter and max-keys.
 */
- (ZYJOSSTask *)getBucket:(ZYJOSSGetBucketRequest *)request;

/**
 The corresponding RESTFul API: GetBucketInfo
 Gets the {@link Bucket}'s basic information as well as its ACL.
 */
- (ZYJOSSTask *)getBucketInfo:(ZYJOSSGetBucketInfoRequest *)request;

/**
 The corresponding RESTFul API: GetBucketACL
 Gets the bucket ACL.
 */
- (ZYJOSSTask *)getBucketACL:(ZYJOSSGetBucketACLRequest *)request;

@end


@interface ZYJOSSClient (Object)

/**
 The corresponding RESTFul API: HeadObject
 Gets the object's metadata information. The object's content is not returned.
 */
- (ZYJOSSTask *)headObject:(ZYJOSSHeadObjectRequest *)request;

/**
 The corresponding RESTFul API: GetObject
 Gets the whole object (includes content). It requires caller have read permission on the object.
 */
- (ZYJOSSTask *)getObject:(ZYJOSSGetObjectRequest *)request;

/**
 The corresponding RESTFul API: GetObjectACL
 get the acl of an object.
 */
- (ZYJOSSTask *)getObjectACL:(ZYJOSSGetObjectACLRequest *)request;

/**
 The corresponding RESTFul API: PutObject
 Uploads a file.
 */
- (ZYJOSSTask *)putObject:(ZYJOSSPutObjectRequest *)request;

/**
 Sets the object's ACL. Right now an object has three access permissions: private, public-ready, public-read-write.
 The operation specifies the x-ZYJOSS-object-acl header in the put request. The caller must be the owner of the object.
 If succeeds, it returns HTTP status 200; otherwise it returns related error code and error messages.
 */
- (ZYJOSSTask *)putObjectACL:(ZYJOSSPutObjectACLRequest *)request;

/**
 The corresponding RESTFul API: AppendObject
 Appends data to an existing or non-existing object. The object created by this operation is appendable.
 As a comparison, the object created by Put Object is normal (non-appendable).
 */
- (ZYJOSSTask *)appendObject:(ZYJOSSAppendObjectRequest *)request;

/**
 *  @brief      Appends data to an existing or non-existing object on the ZYJOSS server.
 *              The object created by this operation is appendable.
 *  @request    request
 *  @crc64ecma  crc64ecma
 *             if object has been stored on ZYJOSS server, you need to invoke headObject
 *             api get object's crc64ecma,then use this api to append data to the
 *             object.
 */
- (ZYJOSSTask *)appendObject:(ZYJOSSAppendObjectRequest *)request withCrc64ecma:(nullable NSString *)crc64ecma;

/**
 The corresponding RESTFul API: copyObject
 Copies an existing object to another one.The operation sends a PUT request with x-ZYJOSS-copy-source header to specify the source object.
 ZYJOSS server side will detect and copy the object. If it succeeds, the new object's metadata information will be returned.
 The operation applies for files less than 1GB. For big files, use UploadPartCopy RESTFul API.
 */
- (ZYJOSSTask *)copyObject:(ZYJOSSCopyObjectRequest *)request;

/**
 * Batch deletes the specified files under a specific bucket. If the files
 * are non-exist, the operation will still return successful.
 *
 * @param request
 *            A ZYJOSSDeleteMultipleObjectsRequest instance which specifies the
 *            bucket and file keys to delete.
 * @return A ZYJOSSTask with result of ZYJOSSDeleteMultipleObjectsResult instance which specifies each
 *         file's result in normal mode or only failed deletions in quite
 *         mode. By default it's quite mode.
 */
- (ZYJOSSTask *)deleteMultipleObjects:(ZYJOSSDeleteMultipleObjectsRequest *)request;

/**
 The corresponding RESTFul API: DeleteObject
 Deletes an object
 */
- (ZYJOSSTask *)deleteObject:(ZYJOSSDeleteObjectRequest *)request;

/**
 * Creates a symbol link to a target file under the bucket---this is not
 * supported for archive class bucket.
 *
 * @param request
 *            A ZYJOSSPutSymlinkRequest instance that specifies the
 *            bucket name, symlink name.
 * @return An instance of ZYJOSSTask. On successful execution, `task.result` will
 *         contain an instance of `ZYJOSSPutSymlinkResult`,otherwise will contain
 *         an instance of NSError.
 *
 * for more information,please refer to https://help.aliyun.com/document_detail/45126.html
 */
- (ZYJOSSTask *)putSymlink:(ZYJOSSPutSymlinkRequest *)request;

/**
 * Gets the symlink information for the given symlink name.
 *
 * @param request
 *            A ZYJOSSGetSymlinkRequest instance which specifies the bucket
 *            name and symlink name.
 * @return An instance of ZYJOSSTask. On successful execution, `task.result` will
 *         contain an instance of `ZYJOSSGetSymlinkResult`,otherwise will contain
 *         an instance of NSError.
 *
 * for more information,please refer to https://help.aliyun.com/document_detail/45146.html
 */
- (ZYJOSSTask *)getSymlink:(ZYJOSSGetSymlinkRequest *)request;

/**
 * Restores the object of archive storage. The function is not applicable to
 * Normal or IA storage. The restoreObject() needs to be called prior to
 * calling getObject() on an archive object.
 *
 * @param request
 *          A container for the necessary parameters to execute the RestoreObject
 *          service method.
 *
 * @return An instance of ZYJOSSTask. On successful execution, `task.result` will
 *         contain an instance of `ZYJOSSRestoreObjectResult`,otherwise will contain
 *         an instance of NSError.
 *
 * for more information,please refer to https://help.aliyun.com/document_detail/52930.html
 */
- (ZYJOSSTask *)restoreObject:(ZYJOSSRestoreObjectRequest *)request;

@end

@interface ZYJOSSClient (MultipartUpload)

/**
 The corresponding RESTFul API: InitiateMultipartUpload
 Initiates a multipart upload to get a upload Id. It's needed before starting uploading parts data.
 The upload Id is used for subsequential operations such as aborting the upload, querying the uploaded parts, etc.
 */
- (ZYJOSSTask *)multipartUploadInit:(ZYJOSSInitMultipartUploadRequest *)request;

/**
 The corresponding RESTFul API: UploadPart
 After the multipart upload is initiated, this API could be called to upload the data to the target file with the upload Id.
 Every uploaded part has a unique id called part number, which ranges from 1 to 10,000.
 For a given upload Id, the part number identifies the specific range of the data in the whole file.
 If the same part number is used for another upload, the existing data will be overwritten by the new upload.
 Except the last part, all other part's minimal size is 100KB.
 But no minimal size requirement on the last part.
 */
- (ZYJOSSTask *)uploadPart:(ZYJOSSUploadPartRequest *)request;

/**
 The corresponding RESTFul API: CompleteMultipartUpload
 This API is to complete the multipart upload after all parts data have been uploaded.
 It must be provided with a valid part list (each part has the part number and ETag).
 ZYJOSS will validate every part and then complete the multipart upload.
 If any part is invalid (e.g. the part is updated by another part upload), this API will fail.
 */
- (ZYJOSSTask *)completeMultipartUpload:(ZYJOSSCompleteMultipartUploadRequest *)request;

/**
 The corresponding RESTFul API: ListParts
 Lists all uploaded parts of the specified upload id.
 */
- (ZYJOSSTask *)listParts:(ZYJOSSListPartsRequest *)request;

/**
 The corresponding RESTFul API: ListMultipartUploads
 Lists all multipart uploads with the specified bucket.
 */
- (ZYJOSSTask *)listMultipartUploads:(ZYJOSSListMultipartUploadsRequest *)request;

/**
 The corresponding RESTFul API: AbortMultipartUpload
 Aborts the multipart upload by the specified upload Id.
 Once the multipart upload is aborted by this API, all parts data will be deleted and the upload Id is invalid anymore.
 */
- (ZYJOSSTask *)abortMultipartUpload:(ZYJOSSAbortMultipartUploadRequest *)request;

- (ZYJOSSTask *)abortResumableMultipartUpload:(ZYJOSSResumableUploadRequest *)request;

/**
 Multipart upload API
 */
- (ZYJOSSTask *)multipartUpload:(ZYJOSSMultipartUploadRequest *)request;
/**
 TODOTODO
 Resumable upload API
 This API wraps the multipart upload and also enables resuming upload by reading/writing  the checkpoint data.
 For a new file, multipartUploadInit() needs to be called first to get the upload Id. Then use this upload id to call this API to upload the data.
 If the upload fails, checks the error messages:
 If it's a recoverable error, then call this API again with the same upload Id to retry. The uploaded data will not be uploaded again.
 Otherwise then you may need to recreates a new upload Id and call this method again.
 Check out demo for the detail.
 */
- (ZYJOSSTask *)resumableUpload:(ZYJOSSResumableUploadRequest *)request;

/**
 * multipart upload sequentially in order,support resume upload
 */
- (ZYJOSSTask *)sequentialMultipartUpload:(ZYJOSSResumableUploadRequest *)request;

@end


@interface ZYJOSSClient (PresignURL)

/**
 Generates a signed URL for the object and anyone has this URL will get the GET permission on the object.
 @bucketName object's bucket name
 @objectKey Object name
 @interval Expiration time in seconds. The URL could be specified with the expiration time to limit the access window on the object.
 */
- (ZYJOSSTask *)presignConstrainURLWithBucketName:(NSString *)bucketName
                                 withObjectKey:(NSString *)objectKey
                        withExpirationInterval:(NSTimeInterval)interval;

/**
 Generates a signed URL for the object and anyone has this URL will get the specified permission on the object.
 @bucketName object's bucket name
 @objectKey Object name
 @interval Expiration time in seconds. The URL could be specified with the expiration time to limit the access window on the object.
 @parameter it could specify allowed HTTP methods
 */
- (ZYJOSSTask *)presignConstrainURLWithBucketName:(NSString *)bucketName
                                 withObjectKey:(NSString *)objectKey
                        withExpirationInterval:(NSTimeInterval)interval
                                withParameters:(NSDictionary *)parameters;

/**
 Generates a signed URL for the object and anyone has this URL will get the specified permission on the object. currently only support get and head method.
 @bucketName object's bucket name
 @objectKey Object name
 @httpMethod http method.currently only support get and head.
 @interval Expiration time in seconds. The URL could be specified with the expiration time to limit the access window on the object.
 @parameter it could specify allowed HTTP methods
 */
- (ZYJOSSTask *)presignConstrainURLWithBucketName:(NSString *)bucketName
                                 withObjectKey:(NSString *)objectKey
                                    httpMethod:(NSString *)method
                        withExpirationInterval:(NSTimeInterval)interval
                                withParameters:(NSDictionary *)parameters;

/**
 If the object's ACL is public read or public read-write, use this API to generate a signed url for sharing.
 @bucketName Object's bucket name
 @objectKey Object name
 */
- (ZYJOSSTask *)presignPublicURLWithBucketName:(NSString *)bucketName
                              withObjectKey:(NSString *)objectKey;

/** TODOTODO
 If the object's ACL is public read or public read-write, use this API to generate a signed url for sharing.
 @bucketName Object's bucket name
 @objectKey Object name
 @parameter the request parameters.
 */
- (ZYJOSSTask *)presignPublicURLWithBucketName:(NSString *)bucketName
                              withObjectKey:(NSString *)objectKey
                             withParameters:(NSDictionary *)parameters;

@end


@interface ZYJOSSClient (ImageService)

/*
 * image persist action
 * https://help.aliyun.com/document_detail/55811.html
 */
- (ZYJOSSTask *)imageActionPersist:(ZYJOSSImagePersistRequest *)request;

@end


@interface ZYJOSSClient (Utilities)

/**
 Checks if the object exists
 @bucketName Object's bucket name
 @objectKey Object name
 
 return YES                     Object exists
 return NO && *error = nil      Object does not exist
 return NO && *error != nil     Error occured.
 */
- (BOOL)doesObjectExistInBucket:(NSString *)bucketName
                      objectKey:(NSString *)objectKey
                          error:(const NSError **)error;

@end


@interface ZYJOSSClient (Callback)

- (ZYJOSSTask *)triggerCallBack:(ZYJOSSCallBackRequest *)request;

@end

NS_ASSUME_NONNULL_END
