// Code generated by smithy-go-codegen DO NOT EDIT.

package s3

import (
	"context"
	"fmt"
	awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware"
	"github.com/aws/aws-sdk-go-v2/aws/signer/v4"
	s3cust "github.com/aws/aws-sdk-go-v2/service/s3/internal/customizations"
	"github.com/aws/smithy-go/middleware"
	smithyhttp "github.com/aws/smithy-go/transport/http"
	"time"
)

// Renames an existing object in a directory bucket that uses the S3 Express One
// Zone storage class. You can use RenameObject by specifying an existing object’s
// name as the source and the new name of the object as the destination within the
// same directory bucket.
//
// RenameObject is only supported for objects stored in the S3 Express One Zone
// storage class.
//
// To prevent overwriting an object, you can use the If-None-Match conditional
// header.
//
//   - If-None-Match - Renames the object only if an object with the specified
//     name does not already exist in the directory bucket. If you don't want to
//     overwrite an existing object, you can add the If-None-Match conditional header
//     with the value ‘*’ in the RenameObject request. Amazon S3 then returns a 412
//     Precondition Failed error if the object with the specified name already
//     exists. For more information, see [RFC 7232].
//
// Permissions  To grant access to the RenameObject operation on a directory
// bucket, we recommend that you use the CreateSession operation for session-based
// authorization. Specifically, you grant the s3express:CreateSession permission
// to the directory bucket in a bucket policy or an IAM identity-based policy.
// Then, you make the CreateSession API call on the directory bucket to obtain a
// session token. With the session token in your request header, you can make API
// requests to this operation. After the session token expires, you make another
// CreateSession API call to generate a new session token for use. The Amazon Web
// Services CLI and SDKs will create and manage your session including refreshing
// the session token automatically to avoid service interruptions when a session
// expires. In your bucket policy, you can specify the s3express:SessionMode
// condition key to control who can create a ReadWrite or ReadOnly session. A
// ReadWrite session is required for executing all the Zonal endpoint API
// operations, including RenameObject . For more information about authorization,
// see [CreateSession]CreateSession . To learn more about Zonal endpoint APT operations, see [Authorizing Zonal endpoint API operations with CreateSession] in
// the Amazon S3 User Guide.
//
// HTTP Host header syntax  Directory buckets - The HTTP Host header syntax is
// Bucket-name.s3express-zone-id.region-code.amazonaws.com .
//
// [CreateSession]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateSession.html
// [RFC 7232]: https://datatracker.ietf.org/doc/rfc7232/
// [Authorizing Zonal endpoint API operations with CreateSession]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-express-create-session.html
func (c *Client) RenameObject(ctx context.Context, params *RenameObjectInput, optFns ...func(*Options)) (*RenameObjectOutput, error) {
	if params == nil {
		params = &RenameObjectInput{}
	}

	result, metadata, err := c.invokeOperation(ctx, "RenameObject", params, optFns, c.addOperationRenameObjectMiddlewares)
	if err != nil {
		return nil, err
	}

	out := result.(*RenameObjectOutput)
	out.ResultMetadata = metadata
	return out, nil
}

type RenameObjectInput struct {

	// The bucket name of the directory bucket containing the object.
	//
	// You must use virtual-hosted-style requests in the format
	// Bucket-name.s3express-zone-id.region-code.amazonaws.com . Path-style requests
	// are not supported. Directory bucket names must be unique in the chosen
	// Availability Zone. Bucket names must follow the format
	// bucket-base-name--zone-id--x-s3 (for example,
	// amzn-s3-demo-bucket--usw2-az1--x-s3 ). For information about bucket naming
	// restrictions, see [Directory bucket naming rules]in the Amazon S3 User Guide.
	//
	// [Directory bucket naming rules]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/directory-bucket-naming-rules.html
	//
	// This member is required.
	Bucket *string

	// Key name of the object to rename.
	//
	// This member is required.
	Key *string

	// Specifies the source for the rename operation. The value must be URL encoded.
	//
	// This member is required.
	RenameSource *string

	//  A unique string with a max of 64 ASCII characters in the ASCII range of 33 -
	// 126. RenameObject supports idempotency using a client token. To make an
	// idempotent API request using RenameObject , specify a client token in the
	// request. You should not reuse the same client token for other API requests. If
	// you retry a request that completed successfully using the same client token and
	// the same parameters, the retry succeeds without performing any further actions.
	// If you retry a successful request using the same client token, but one or more
	// of the parameters are different, the retry fails and an
	// IdempotentParameterMismatch error is returned.
	ClientToken *string

	// Renames the object only if the ETag (entity tag) value provided during the
	// operation matches the ETag of the object in S3. The If-Match header field makes
	// the request method conditional on ETags. If the ETag values do not match, the
	// operation returns a 412 Precondition Failed error.
	//
	// Expects the ETag value as a string.
	DestinationIfMatch *string

	// Renames the object if the destination exists and if it has been modified since
	// the specified time.
	DestinationIfModifiedSince *time.Time

	//  Renames the object only if the destination does not already exist in the
	// specified directory bucket. If the object does exist when you send a request
	// with If-None-Match:* , the S3 API will return a 412 Precondition Failed error,
	// preventing an overwrite. The If-None-Match header prevents overwrites of
	// existing data by validating that there's not an object with the same key name
	// already in your directory bucket.
	//
	// Expects the * character (asterisk).
	DestinationIfNoneMatch *string

	// Renames the object if it hasn't been modified since the specified time.
	DestinationIfUnmodifiedSince *time.Time

	// Renames the object if the source exists and if its entity tag (ETag) matches
	// the specified ETag.
	SourceIfMatch *string

	// Renames the object if the source exists and if it has been modified since the
	// specified time.
	SourceIfModifiedSince *time.Time

	// Renames the object if the source exists and if its entity tag (ETag) is
	// different than the specified ETag. If an asterisk ( * ) character is provided,
	// the operation will fail and return a 412 Precondition Failed error.
	SourceIfNoneMatch *string

	// Renames the object if the source exists and hasn't been modified since the
	// specified time.
	SourceIfUnmodifiedSince *time.Time

	noSmithyDocumentSerde
}

func (in *RenameObjectInput) bindEndpointParams(p *EndpointParameters) {

	p.Bucket = in.Bucket
	p.Key = in.Key

}

type RenameObjectOutput struct {
	// Metadata pertaining to the operation's result.
	ResultMetadata middleware.Metadata

	noSmithyDocumentSerde
}

func (c *Client) addOperationRenameObjectMiddlewares(stack *middleware.Stack, options Options) (err error) {
	if err := stack.Serialize.Add(&setOperationInputMiddleware{}, middleware.After); err != nil {
		return err
	}
	err = stack.Serialize.Add(&awsRestxml_serializeOpRenameObject{}, middleware.After)
	if err != nil {
		return err
	}
	err = stack.Deserialize.Add(&awsRestxml_deserializeOpRenameObject{}, middleware.After)
	if err != nil {
		return err
	}
	if err := addProtocolFinalizerMiddlewares(stack, options, "RenameObject"); err != nil {
		return fmt.Errorf("add protocol finalizers: %v", err)
	}

	if err = addlegacyEndpointContextSetter(stack, options); err != nil {
		return err
	}
	if err = addSetLoggerMiddleware(stack, options); err != nil {
		return err
	}
	if err = addClientRequestID(stack); err != nil {
		return err
	}
	if err = addComputeContentLength(stack); err != nil {
		return err
	}
	if err = addResolveEndpointMiddleware(stack, options); err != nil {
		return err
	}
	if err = addComputePayloadSHA256(stack); err != nil {
		return err
	}
	if err = addRetry(stack, options); err != nil {
		return err
	}
	if err = addRawResponseToMetadata(stack); err != nil {
		return err
	}
	if err = addRecordResponseTiming(stack); err != nil {
		return err
	}
	if err = addSpanRetryLoop(stack, options); err != nil {
		return err
	}
	if err = addClientUserAgent(stack, options); err != nil {
		return err
	}
	if err = smithyhttp.AddErrorCloseResponseBodyMiddleware(stack); err != nil {
		return err
	}
	if err = smithyhttp.AddCloseResponseBodyMiddleware(stack); err != nil {
		return err
	}
	if err = addSetLegacyContextSigningOptionsMiddleware(stack); err != nil {
		return err
	}
	if err = addPutBucketContextMiddleware(stack); err != nil {
		return err
	}
	if err = addTimeOffsetBuild(stack, c); err != nil {
		return err
	}
	if err = addUserAgentRetryMode(stack, options); err != nil {
		return err
	}
	if err = addIsExpressUserAgent(stack); err != nil {
		return err
	}
	if err = addCredentialSource(stack, options); err != nil {
		return err
	}
	if err = addIdempotencyToken_opRenameObjectMiddleware(stack, options); err != nil {
		return err
	}
	if err = addOpRenameObjectValidationMiddleware(stack); err != nil {
		return err
	}
	if err = stack.Initialize.Add(newServiceMetadataMiddleware_opRenameObject(options.Region), middleware.Before); err != nil {
		return err
	}
	if err = addMetadataRetrieverMiddleware(stack); err != nil {
		return err
	}
	if err = addRecursionDetection(stack); err != nil {
		return err
	}
	if err = addRenameObjectUpdateEndpoint(stack, options); err != nil {
		return err
	}
	if err = addResponseErrorMiddleware(stack); err != nil {
		return err
	}
	if err = v4.AddContentSHA256HeaderMiddleware(stack); err != nil {
		return err
	}
	if err = disableAcceptEncodingGzip(stack); err != nil {
		return err
	}
	if err = addRequestResponseLogging(stack, options); err != nil {
		return err
	}
	if err = addDisableHTTPSMiddleware(stack, options); err != nil {
		return err
	}
	if err = addSerializeImmutableHostnameBucketMiddleware(stack, options); err != nil {
		return err
	}
	if err = addSpanInitializeStart(stack); err != nil {
		return err
	}
	if err = addSpanInitializeEnd(stack); err != nil {
		return err
	}
	if err = addSpanBuildRequestStart(stack); err != nil {
		return err
	}
	if err = addSpanBuildRequestEnd(stack); err != nil {
		return err
	}
	return nil
}

func (v *RenameObjectInput) bucket() (string, bool) {
	if v.Bucket == nil {
		return "", false
	}
	return *v.Bucket, true
}

type idempotencyToken_initializeOpRenameObject struct {
	tokenProvider IdempotencyTokenProvider
}

func (*idempotencyToken_initializeOpRenameObject) ID() string {
	return "OperationIdempotencyTokenAutoFill"
}

func (m *idempotencyToken_initializeOpRenameObject) HandleInitialize(ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler) (
	out middleware.InitializeOutput, metadata middleware.Metadata, err error,
) {
	if m.tokenProvider == nil {
		return next.HandleInitialize(ctx, in)
	}

	input, ok := in.Parameters.(*RenameObjectInput)
	if !ok {
		return out, metadata, fmt.Errorf("expected middleware input to be of type *RenameObjectInput ")
	}

	if input.ClientToken == nil {
		t, err := m.tokenProvider.GetIdempotencyToken()
		if err != nil {
			return out, metadata, err
		}
		input.ClientToken = &t
	}
	return next.HandleInitialize(ctx, in)
}
func addIdempotencyToken_opRenameObjectMiddleware(stack *middleware.Stack, cfg Options) error {
	return stack.Initialize.Add(&idempotencyToken_initializeOpRenameObject{tokenProvider: cfg.IdempotencyTokenProvider}, middleware.Before)
}

func newServiceMetadataMiddleware_opRenameObject(region string) *awsmiddleware.RegisterServiceMetadata {
	return &awsmiddleware.RegisterServiceMetadata{
		Region:        region,
		ServiceID:     ServiceID,
		OperationName: "RenameObject",
	}
}

// getRenameObjectBucketMember returns a pointer to string denoting a provided
// bucket member valueand a boolean indicating if the input has a modeled bucket
// name,
func getRenameObjectBucketMember(input interface{}) (*string, bool) {
	in := input.(*RenameObjectInput)
	if in.Bucket == nil {
		return nil, false
	}
	return in.Bucket, true
}
func addRenameObjectUpdateEndpoint(stack *middleware.Stack, options Options) error {
	return s3cust.UpdateEndpoint(stack, s3cust.UpdateEndpointOptions{
		Accessor: s3cust.UpdateEndpointParameterAccessor{
			GetBucketFromInput: getRenameObjectBucketMember,
		},
		UsePathStyle:                   options.UsePathStyle,
		UseAccelerate:                  options.UseAccelerate,
		SupportsAccelerate:             true,
		TargetS3ObjectLambda:           false,
		EndpointResolver:               options.EndpointResolver,
		EndpointResolverOptions:        options.EndpointOptions,
		UseARNRegion:                   options.UseARNRegion,
		DisableMultiRegionAccessPoints: options.DisableMultiRegionAccessPoints,
	})
}
