package acceptencoding

import (
	
	
	
	

	
	
	smithyhttp 
)

const acceptEncodingHeaderKey = "Accept-Encoding"
const contentEncodingHeaderKey = "Content-Encoding"

// AddAcceptEncodingGzipOptions provides the options for the
// AddAcceptEncodingGzip middleware setup.
type AddAcceptEncodingGzipOptions struct {
	Enable bool
}

// AddAcceptEncodingGzip explicitly adds handling for accept-encoding GZIP
// middleware to the operation stack. This allows checksums to be correctly
// computed without disabling GZIP support.
func ( *middleware.Stack,  AddAcceptEncodingGzipOptions) error {
	if .Enable {
		if  := .Finalize.Add(&EnableGzip{}, middleware.Before);  != nil {
			return 
		}
		if  := .Deserialize.Insert(&DecompressGzip{}, "OperationDeserializer", middleware.After);  != nil {
			return 
		}
		return nil
	}

	return .Finalize.Add(&DisableGzip{}, middleware.Before)
}

// DisableGzip provides the middleware that will
// disable the underlying http client automatically enabling for gzip
// decompress content-encoding support.
type DisableGzip struct{}

// ID returns the id for the middleware.
func (*DisableGzip) () string {
	return "DisableAcceptEncodingGzip"
}

// HandleFinalize implements the FinalizeMiddleware interface.
func (*DisableGzip) (
	 context.Context,  middleware.FinalizeInput,  middleware.FinalizeHandler,
) (
	 middleware.FinalizeOutput,  middleware.Metadata,  error,
) {
	,  := .Request.(*smithyhttp.Request)
	if ! {
		return , , &smithy.SerializationError{
			Err: fmt.Errorf("unknown request type %T", .Request),
		}
	}

	// Explicitly enable gzip support, this will prevent the http client from
	// auto extracting the zipped content.
	.Header.Set(acceptEncodingHeaderKey, "identity")

	return .HandleFinalize(, )
}

// EnableGzip provides a middleware to enable support for
// gzip responses, with manual decompression. This prevents the underlying HTTP
// client from performing the gzip decompression automatically.
type EnableGzip struct{}

// ID returns the id for the middleware.
func (*EnableGzip) () string {
	return "AcceptEncodingGzip"
}

// HandleFinalize implements the FinalizeMiddleware interface.
func (*EnableGzip) (
	 context.Context,  middleware.FinalizeInput,  middleware.FinalizeHandler,
) (
	 middleware.FinalizeOutput,  middleware.Metadata,  error,
) {
	,  := .Request.(*smithyhttp.Request)
	if ! {
		return , , &smithy.SerializationError{
			Err: fmt.Errorf("unknown request type %T", .Request),
		}
	}

	// Explicitly enable gzip support, this will prevent the http client from
	// auto extracting the zipped content.
	.Header.Set(acceptEncodingHeaderKey, "gzip")

	return .HandleFinalize(, )
}

// DecompressGzip provides the middleware for decompressing a gzip
// response from the service.
type DecompressGzip struct{}

// ID returns the id for the middleware.
func (*DecompressGzip) () string {
	return "DecompressGzip"
}

// HandleDeserialize implements the DeserializeMiddlware interface.
func (*DecompressGzip) (
	 context.Context,  middleware.DeserializeInput,  middleware.DeserializeHandler,
) (
	 middleware.DeserializeOutput,  middleware.Metadata,  error,
) {
	, ,  = .HandleDeserialize(, )
	if  != nil {
		return , , 
	}

	,  := .RawResponse.(*smithyhttp.Response)
	if ! {
		return , , &smithy.DeserializationError{
			Err: fmt.Errorf("unknown response type %T", .RawResponse),
		}
	}
	if  := .Header.Get(contentEncodingHeaderKey);  != "gzip" {
		return , , 
	}

	// Clear content length since it will no longer be valid once the response
	// body is decompressed.
	.Header.Del("Content-Length")
	.ContentLength = -1

	.Body = wrapGzipReader(.Body)

	return , , 
}

type gzipReader struct {
	reader io.ReadCloser
	gzip   *gzip.Reader
}

func ( io.ReadCloser) *gzipReader {
	return &gzipReader{
		reader: ,
	}
}

// Read wraps the gzip reader around the underlying io.Reader to extract the
// response bytes on the fly.
func ( *gzipReader) ( []byte) ( int,  error) {
	if .gzip == nil {
		.gzip,  = gzip.NewReader(.reader)
		if  != nil {
			.gzip = nil // ensure uninitialized gzip value isn't used in close.
			return 0, fmt.Errorf("failed to decompress gzip response, %w", )
		}
	}

	return .gzip.Read()
}

func ( *gzipReader) () error {
	if .gzip == nil {
		return nil
	}

	if  := .gzip.Close();  != nil {
		.reader.Close()
		return fmt.Errorf("failed to decompress gzip response, %w", )
	}

	return .reader.Close()
}