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

package s3

import (
	"context"
	"fmt"
	"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/aws-sdk-go-v2/service/s3/types"
	"github.com/aws/smithy-go/middleware"
	smithyhttp "github.com/aws/smithy-go/transport/http"
)

// Lists the annotations attached to an Amazon S3 object. Results are paginated,
// with a maximum of 1,000 annotations per object. Use the AnnotationPrefix
// parameter to filter the results by name prefix.
//
// To use this operation, you must have the s3:ListObjectAnnotations permission.
//
// Annotations are not supported by the following features: S3 Inventory Reports,
// API Gateway, S3 Storage Lens, Amazon S3 File Gateway, Amazon FSx, S3 on
// Outposts, and S3 Express One Zone (directory buckets).
//
// The following operations are related to ListObjectAnnotations :
//
// [PutObjectAnnotation]
//
// [GetObjectAnnotation]
//
// [DeleteObjectAnnotation]
//
// [GetObjectAnnotation]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAnnotation.html
// [DeleteObjectAnnotation]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjectAnnotation.html
// [PutObjectAnnotation]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectAnnotation.html
func (c *Client) ListObjectAnnotations(ctx context.Context, params *ListObjectAnnotationsInput, optFns ...func(*Options)) (*ListObjectAnnotationsOutput, error) {
	if params == nil {
		params = &ListObjectAnnotationsInput{}
	}

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

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

type ListObjectAnnotationsInput struct {

	// The name of the bucket that contains the object.
	//
	// This member is required.
	Bucket *string

	// The object key.
	//
	// This member is required.
	Key *string

	// Filter results to annotations whose name begins with the specified prefix.
	AnnotationPrefix *string

	// Continuation token returned by a previous request to retrieve the next page.
	ContinuationToken *string

	// The account ID of the expected bucket owner.
	ExpectedBucketOwner *string

	// The maximum number of annotations to return in the response. Maximum is 1,000.
	MaxAnnotationResults *int32

	// Confirms that the requester knows that they will be charged for the request.
	// Bucket owners need not specify this parameter in their requests. If either the
	// source or destination S3 bucket has Requester Pays enabled, the requester will
	// pay for the corresponding charges. For information about downloading objects
	// from Requester Pays buckets, see [Downloading Objects in Requester Pays Buckets]in the Amazon S3 User Guide.
	//
	// This functionality is not supported for directory buckets.
	//
	// [Downloading Objects in Requester Pays Buckets]: https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html
	RequestPayer types.RequestPayer

	// The version ID of the object.
	VersionId *string

	noSmithyDocumentSerde
}

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

	p.Bucket = in.Bucket

}

type ListObjectAnnotationsOutput struct {

	// The number of annotations returned.
	AnnotationCount *int32

	// The prefix used to filter the response.
	AnnotationPrefix *string

	// The list of annotations attached to the object.
	Annotations []types.AnnotationEntry

	// The bucket name.
	Bucket *string

	// The continuation token used in this request.
	ContinuationToken *string

	// The object key.
	Key *string

	// The maximum number of annotations returned in the response.
	MaxAnnotationResults *int32

	// The continuation token to use to retrieve the next page of results.
	NextContinuationToken *string

	// The version ID of the object.
	ObjectVersionId *string

	// If present, indicates that the requester was successfully charged for the
	// request. For more information, see [Using Requester Pays buckets for storage transfers and usage]in the Amazon Simple Storage Service user
	// guide.
	//
	// This functionality is not supported for directory buckets.
	//
	// [Using Requester Pays buckets for storage transfers and usage]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/RequesterPaysBuckets.html
	RequestCharged types.RequestCharged

	// Metadata pertaining to the operation's result.
	ResultMetadata middleware.Metadata

	noSmithyDocumentSerde
}

func (c *Client) addOperationListObjectAnnotationsMiddlewares(stack *middleware.Stack, options Options) (err error) {
	err = stack.Serialize.Add(&awsRestxml_serializeOpListObjectAnnotations{}, middleware.After)
	if err != nil {
		return err
	}
	err = stack.Deserialize.Add(&awsRestxml_deserializeOpListObjectAnnotations{}, middleware.After)
	if err != nil {
		return err
	}

	if err = addlegacyEndpointContextSetter(stack, options); 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 = addRecordResponseTiming(stack); err != nil {
		return err
	}
	if err = smithyhttp.AddErrorCloseResponseBodyMiddleware(stack); err != nil {
		return err
	}
	if err = smithyhttp.AddCloseResponseBodyMiddleware(stack); err != nil {
		return err
	}
	if err = addPutBucketContextMiddleware(stack); err != nil {
		return err
	}
	if err = addIsExpressUserAgent(stack); err != nil {
		return err
	}
	if err = addCredentialSource(stack, options); err != nil {
		return err
	}
	if err = addOpListObjectAnnotationsValidationMiddleware(stack); err != nil {
		return err
	}
	if err = stack.Initialize.Add(newServiceMetadataMiddleware(options.Region, "ListObjectAnnotations"), middleware.Before); err != nil {
		return err
	}
	if err = addMetadataRetrieverMiddleware(stack); err != nil {
		return err
	}
	if err = addListObjectAnnotationsUpdateEndpoint(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 = addInterceptors(stack, options); err != nil {
		return err
	}
	return nil
}

// ListObjectAnnotationsPaginatorOptions is the paginator options for
// ListObjectAnnotations
type ListObjectAnnotationsPaginatorOptions struct {
	// The maximum number of annotations to return in the response. Maximum is 1,000.
	Limit int32

	// Set to true if pagination should stop if the service returns a pagination token
	// that matches the most recent token provided to the service.
	StopOnDuplicateToken bool
}

// ListObjectAnnotationsPaginator is a paginator for ListObjectAnnotations
type ListObjectAnnotationsPaginator struct {
	options   ListObjectAnnotationsPaginatorOptions
	client    ListObjectAnnotationsAPIClient
	params    *ListObjectAnnotationsInput
	nextToken *string
	firstPage bool
}

// NewListObjectAnnotationsPaginator returns a new ListObjectAnnotationsPaginator
func NewListObjectAnnotationsPaginator(client ListObjectAnnotationsAPIClient, params *ListObjectAnnotationsInput, optFns ...func(*ListObjectAnnotationsPaginatorOptions)) *ListObjectAnnotationsPaginator {
	if params == nil {
		params = &ListObjectAnnotationsInput{}
	}

	options := ListObjectAnnotationsPaginatorOptions{}
	if params.MaxAnnotationResults != nil {
		options.Limit = *params.MaxAnnotationResults
	}

	for _, fn := range optFns {
		fn(&options)
	}

	return &ListObjectAnnotationsPaginator{
		options:   options,
		client:    client,
		params:    params,
		firstPage: true,
		nextToken: params.ContinuationToken,
	}
}

// HasMorePages returns a boolean indicating whether more pages are available
func (p *ListObjectAnnotationsPaginator) HasMorePages() bool {
	return p.firstPage || (p.nextToken != nil && len(*p.nextToken) != 0)
}

// NextPage retrieves the next ListObjectAnnotations page.
func (p *ListObjectAnnotationsPaginator) NextPage(ctx context.Context, optFns ...func(*Options)) (*ListObjectAnnotationsOutput, error) {
	if !p.HasMorePages() {
		return nil, fmt.Errorf("no more pages available")
	}

	params := *p.params
	params.ContinuationToken = p.nextToken

	var limit *int32
	if p.options.Limit > 0 {
		limit = &p.options.Limit
	}
	params.MaxAnnotationResults = limit

	optFns = append([]func(*Options){
		addIsPaginatorUserAgent,
	}, optFns...)
	result, err := p.client.ListObjectAnnotations(ctx, &params, optFns...)
	if err != nil {
		return nil, err
	}
	p.firstPage = false

	prevToken := p.nextToken
	p.nextToken = result.NextContinuationToken

	if p.options.StopOnDuplicateToken &&
		prevToken != nil &&
		p.nextToken != nil &&
		*prevToken == *p.nextToken {
		p.nextToken = nil
	}

	return result, nil
}

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

// ListObjectAnnotationsAPIClient is a client that implements the
// ListObjectAnnotations operation.
type ListObjectAnnotationsAPIClient interface {
	ListObjectAnnotations(context.Context, *ListObjectAnnotationsInput, ...func(*Options)) (*ListObjectAnnotationsOutput, error)
}

var _ ListObjectAnnotationsAPIClient = (*Client)(nil)

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