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


package ecs

import (
	"github.com/aws/aws-sdk-go-v2/aws"
	awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware"
	"github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn"
	"context"
	"github.com/aws/aws-sdk-go-v2/internal/endpoints"
	"errors"
	"fmt"
	"net/http"
	internalConfig "github.com/aws/aws-sdk-go-v2/internal/configsources"
	internalendpoints "github.com/aws/aws-sdk-go-v2/service/ecs/internal/endpoints"
	"github.com/aws/smithy-go/middleware"
	"os"
	"github.com/aws/smithy-go/ptr"
	smithyauth "github.com/aws/smithy-go/auth"
	smithyendpoints "github.com/aws/smithy-go/endpoints"
	smithyhttp "github.com/aws/smithy-go/transport/http"
	"strings"
	"github.com/aws/smithy-go/tracing"
	"net/url"
)

// EndpointResolverOptions is the service endpoint resolver options
type EndpointResolverOptions = internalendpoints.Options

// EndpointResolver interface for resolving service endpoints.
type EndpointResolver interface {
	ResolveEndpoint(region string, options EndpointResolverOptions) (aws.Endpoint, error)
}
var _ EndpointResolver = &internalendpoints.Resolver{}

// NewDefaultEndpointResolver constructs a new service endpoint resolver
func NewDefaultEndpointResolver() *internalendpoints.Resolver {
	return internalendpoints.New()
}
// EndpointResolverFunc is a helper utility that wraps a function so it satisfies
// the EndpointResolver interface. This is useful when you want to add additional
// endpoint resolving logic, or stub out specific endpoints with custom values.
type EndpointResolverFunc func(region string, options EndpointResolverOptions) (aws.Endpoint, error)
func (fn EndpointResolverFunc) ResolveEndpoint(region string, options EndpointResolverOptions) (endpoint aws.Endpoint, err error) {
	return fn(region, options)
}

// EndpointResolverFromURL returns an EndpointResolver configured using the
// provided endpoint url. By default, the resolved endpoint resolver uses the
// client region as signing region, and the endpoint source is set to
// EndpointSourceCustom.You can provide functional options to configure endpoint
// values for the resolved endpoint.
func EndpointResolverFromURL(url string, optFns ...func(*aws.Endpoint)) EndpointResolver {
	e := aws.Endpoint{ URL : url, Source : aws.EndpointSourceCustom }
	for _, fn := range optFns { fn(&e) }
	
	return EndpointResolverFunc(
		func(region string, options EndpointResolverOptions) (aws.Endpoint, error) {
		if len(e.SigningRegion) == 0 { e.SigningRegion = region }
		return e, nil },
	)
}
type ResolveEndpoint struct {
	Resolver EndpointResolver
	Options EndpointResolverOptions
}

func (*ResolveEndpoint) ID() string {
	return "ResolveEndpoint"
}

func (m *ResolveEndpoint) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) (
	out middleware.SerializeOutput, metadata middleware.Metadata, err error,
) {
	    if !awsmiddleware.GetRequiresLegacyEndpoints(ctx) {
	        return next.HandleSerialize(ctx, in)
	    }
	
	req, ok := in.Request.(*smithyhttp.Request)
	if !ok {
		return out, metadata, fmt.Errorf("unknown transport type %T", in.Request)
	}
	
	if m.Resolver == nil {
		return out, metadata, fmt.Errorf("expected endpoint resolver to not be nil")
	}
	
	eo := m.Options
	eo.Logger = middleware.GetLogger(ctx)
	
	var endpoint aws.Endpoint
	endpoint, err = m.Resolver.ResolveEndpoint(awsmiddleware.GetRegion(ctx), eo)
	    if err != nil {
	        nf := (&aws.EndpointNotFoundError{})
	        if errors.As(err, &nf) {
	            ctx = awsmiddleware.SetRequiresLegacyEndpoints(ctx, false)
	            return next.HandleSerialize(ctx, in)
	        }
	        return out, metadata, fmt.Errorf("failed to resolve service endpoint, %w", err)
	    }
	
	req.URL, err = url.Parse(endpoint.URL)
	if err != nil {
		return out, metadata, fmt.Errorf("failed to parse endpoint URL: %w", err)
	}
	
	if len(awsmiddleware.GetSigningName(ctx)) == 0 {
		signingName := endpoint.SigningName
		if len(signingName) == 0 {
			signingName = "ecs"
		}
		ctx = awsmiddleware.SetSigningName(ctx, signingName)
	}
	ctx = awsmiddleware.SetEndpointSource(ctx, endpoint.Source)
	ctx = smithyhttp.SetHostnameImmutable(ctx, endpoint.HostnameImmutable)
	ctx = awsmiddleware.SetSigningRegion(ctx, endpoint.SigningRegion)
	ctx = awsmiddleware.SetPartitionID(ctx, endpoint.PartitionID)
	return next.HandleSerialize(ctx, in)
}
func addResolveEndpointMiddleware(stack *middleware.Stack, o Options) error {
	return stack.Serialize.Insert(&ResolveEndpoint{
		Resolver: o.EndpointResolver,
		Options: o.EndpointOptions,
	}, "OperationSerializer", middleware.Before)
}

func removeResolveEndpointMiddleware(stack *middleware.Stack) error {
	_, err := stack.Serialize.Remove((&ResolveEndpoint{}).ID())
	return err
}
type wrappedEndpointResolver struct {
    awsResolver aws.EndpointResolverWithOptions
}

func (w *wrappedEndpointResolver) ResolveEndpoint(region string, options EndpointResolverOptions) (endpoint aws.Endpoint, err error) {
	return w.awsResolver.ResolveEndpoint(ServiceID, region, options)
}

type awsEndpointResolverAdaptor func(service, region string) (aws.Endpoint, error)

func (a awsEndpointResolverAdaptor) ResolveEndpoint(service, region string, options ...interface{}) (aws.Endpoint, error) {
    return a(service, region)
}

var _ aws.EndpointResolverWithOptions = awsEndpointResolverAdaptor(nil)

// withEndpointResolver returns an aws.EndpointResolverWithOptions that first delegates endpoint resolution to the awsResolver.
// If awsResolver returns aws.EndpointNotFoundError error, the v1 resolver middleware will swallow the error,
// and set an appropriate context flag such that fallback will occur when EndpointResolverV2 is invoked
// via its middleware.
//
// If another error (besides aws.EndpointNotFoundError) is returned, then that error will be propagated.
func withEndpointResolver(awsResolver aws.EndpointResolver, awsResolverWithOptions aws.EndpointResolverWithOptions) EndpointResolver {
    var resolver aws.EndpointResolverWithOptions

    if awsResolverWithOptions != nil {
        resolver = awsResolverWithOptions
    } else if awsResolver != nil {
        resolver = awsEndpointResolverAdaptor(awsResolver.ResolveEndpoint)
    }

    return &wrappedEndpointResolver{
        awsResolver: resolver,
    }
}

func finalizeClientEndpointResolverOptions(options *Options) {
	options.EndpointOptions.LogDeprecated = options.ClientLogMode.IsDeprecatedUsage()
	
	if len(options.EndpointOptions.ResolvedRegion) == 0 {
	    const fipsInfix = "-fips-"
	    const fipsPrefix = "fips-"
	    const fipsSuffix = "-fips"
	
	    if (strings.Contains(options.Region, fipsInfix) ||
	        strings.Contains(options.Region, fipsPrefix) ||
	        strings.Contains(options.Region, fipsSuffix)) {
	        options.EndpointOptions.ResolvedRegion = strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(
	            options.Region, fipsInfix, "-"), fipsPrefix, ""), fipsSuffix, "")
	        options.EndpointOptions.UseFIPSEndpoint = aws.FIPSEndpointStateEnabled
	    }
	}
	
}

func resolveEndpointResolverV2(options *Options) {
        if options.EndpointResolverV2 == nil {
            options.EndpointResolverV2 = NewDefaultEndpointResolverV2()
        }
    }

func resolveBaseEndpoint(cfg aws.Config, o *Options) {
        if cfg.BaseEndpoint != nil {
            o.BaseEndpoint = cfg.BaseEndpoint
        }

        _, g := os.LookupEnv("AWS_ENDPOINT_URL")
        _, s := os.LookupEnv("AWS_ENDPOINT_URL_ECS")

        if g && !s  {
            return
        }

        value, found, err := internalConfig.ResolveServiceBaseEndpoint(context.Background(), "ECS", cfg.ConfigSources)
        if found && err == nil {
            o.BaseEndpoint = &value
        }
    }

func bindRegion(region string) *string {
    if region == "" {
        return nil
    }
    return aws.String(endpoints.MapFIPSRegion(region))
}

// EndpointParameters provides the parameters that influence how endpoints are
// resolved.
type EndpointParameters struct {
    // The AWS region used to dispatch the request.
	//
	// Parameter is
	// required.
	//
	// AWS::Region
	Region *string
	
	// When true, use the dual-stack endpoint. If the configured endpoint does not
	// support dual-stack, dispatching the request MAY return an error.
	//
	// Defaults to
	// false if no value is provided.
	//
	// AWS::UseDualStack
	UseDualStack *bool
	
	// When true, send this request to the FIPS-compliant regional endpoint. If the
	// configured endpoint does not have a FIPS compliant endpoint, dispatching the
	// request will return an error.
	//
	// Defaults to false if no value is
	// provided.
	//
	// AWS::UseFIPS
	UseFIPS *bool
	
	// Override the endpoint used to send this request
	//
	// Parameter is
	// required.
	//
	// SDK::Endpoint
	Endpoint *string
}

// ValidateRequired validates required parameters are set.
func (p EndpointParameters) ValidateRequired() error {
	if p.UseDualStack == nil {
	    return fmt.Errorf("parameter UseDualStack is required")
	}
	
	if p.UseFIPS == nil {
	    return fmt.Errorf("parameter UseFIPS is required")
	}
	
	return nil
}
// WithDefaults returns a shallow copy of EndpointParameterswith default values
// applied to members where applicable.
func (p EndpointParameters) WithDefaults() EndpointParameters {
    if p.UseDualStack == nil {
    p.UseDualStack = ptr.Bool(false)
}

if p.UseFIPS == nil {
    p.UseFIPS = ptr.Bool(false)
}
    return p
}

type stringSlice []string

func (s stringSlice) Get(i int) *string {
    if i < 0 || i >= len(s) {
        return nil
    }

    v := s[i]
    return &v
}

// EndpointResolverV2 provides the interface for resolving service endpoints.
type EndpointResolverV2 interface {
    // ResolveEndpoint attempts to resolve the endpoint with the provided options,
// returning the endpoint if found. Otherwise an error is returned.
    ResolveEndpoint(ctx context.Context, params EndpointParameters) (
        smithyendpoints.Endpoint, error,
    )
}

// resolver provides the implementation for resolving endpoints.
type resolver struct{}

func NewDefaultEndpointResolverV2() EndpointResolverV2 {
    return &resolver{}
}

// ResolveEndpoint attempts to resolve the endpoint with the provided options,
// returning the endpoint if found. Otherwise an error is returned.
func (r *resolver) ResolveEndpoint(
    ctx context.Context, params EndpointParameters,
) (
    endpoint smithyendpoints.Endpoint, err error,
) {
    params = params.WithDefaults()
    if err = params.ValidateRequired(); err != nil {
        return endpoint, fmt.Errorf("endpoint parameters are not valid, %w", err)
    }
    _UseDualStack := *params.UseDualStack
_UseFIPS := *params.UseFIPS

    if exprVal := params.Endpoint; exprVal != nil {
    _Endpoint := *exprVal
    _ = _Endpoint
    if _UseFIPS == true {
    return endpoint, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: FIPS and custom endpoint are not supported")
}
if _UseDualStack == true {
    return endpoint, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: Dualstack and custom endpoint are not supported")
}
uriString := _Endpoint

uri, err := url.Parse(uriString)
if err != nil {
    return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}

return smithyendpoints.Endpoint{
    URI: *uri,
    Headers: http.Header{},

}, nil
}
if exprVal := params.Region; exprVal != nil {
    _Region := *exprVal
    _ = _Region
    if exprVal := awsrulesfn.GetPartition(_Region); exprVal != nil {
    _PartitionResult := *exprVal
    _ = _PartitionResult
    if _UseFIPS == true {
    if _UseDualStack == true {
    if true == _PartitionResult.SupportsFIPS {
    if true == _PartitionResult.SupportsDualStack {
    uriString := func() string {
    var out strings.Builder
out.WriteString("https://ecs-fips.")
out.WriteString(_Region)
out.WriteString(".")
out.WriteString(_PartitionResult.DualStackDnsSuffix)
return out.String()
}()

uri, err := url.Parse(uriString)
if err != nil {
    return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}

return smithyendpoints.Endpoint{
    URI: *uri,
    Headers: http.Header{},

}, nil
}
}
return endpoint, fmt.Errorf("endpoint rule error, %s", "FIPS and DualStack are enabled, but this partition does not support one or both")
}
}
if _UseFIPS == true {
    if _PartitionResult.SupportsFIPS == true {
    uriString := func() string {
    var out strings.Builder
out.WriteString("https://ecs-fips.")
out.WriteString(_Region)
out.WriteString(".")
out.WriteString(_PartitionResult.DnsSuffix)
return out.String()
}()

uri, err := url.Parse(uriString)
if err != nil {
    return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}

return smithyendpoints.Endpoint{
    URI: *uri,
    Headers: http.Header{},

}, nil
}
return endpoint, fmt.Errorf("endpoint rule error, %s", "FIPS is enabled but this partition does not support FIPS")
}
if _UseDualStack == true {
    if true == _PartitionResult.SupportsDualStack {
    uriString := func() string {
    var out strings.Builder
out.WriteString("https://ecs.")
out.WriteString(_Region)
out.WriteString(".")
out.WriteString(_PartitionResult.DualStackDnsSuffix)
return out.String()
}()

uri, err := url.Parse(uriString)
if err != nil {
    return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}

return smithyendpoints.Endpoint{
    URI: *uri,
    Headers: http.Header{},

}, nil
}
return endpoint, fmt.Errorf("endpoint rule error, %s", "DualStack is enabled but this partition does not support DualStack")
}
uriString := func() string {
    var out strings.Builder
out.WriteString("https://ecs.")
out.WriteString(_Region)
out.WriteString(".")
out.WriteString(_PartitionResult.DnsSuffix)
return out.String()
}()

uri, err := url.Parse(uriString)
if err != nil {
    return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
}

return smithyendpoints.Endpoint{
    URI: *uri,
    Headers: http.Header{},

}, nil
}
return endpoint, fmt.Errorf("Endpoint resolution failed. Invalid operation or environment input.")
}
return endpoint, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: Missing Region")
}

type endpointParamsBinder interface {
    bindEndpointParams(*EndpointParameters)
}

func bindEndpointParams(ctx context.Context, input interface{}, options Options) *EndpointParameters {
    params := &EndpointParameters{}

    params.Region = bindRegion(options.Region)
params.UseDualStack = aws.Bool(options.EndpointOptions.UseDualStackEndpoint == aws.DualStackEndpointStateEnabled)
params.UseFIPS = aws.Bool(options.EndpointOptions.UseFIPSEndpoint == aws.FIPSEndpointStateEnabled)
params.Endpoint = options.BaseEndpoint

    if b, ok := input.(endpointParamsBinder); ok {
        b.bindEndpointParams(params)
    }

    return params
}

type resolveEndpointV2Middleware struct {
	options Options
}

func (*resolveEndpointV2Middleware) ID() string {
	return "ResolveEndpointV2"
}

func (m *resolveEndpointV2Middleware) HandleFinalize(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) (
	out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
) {
	_, span := tracing.StartSpan(ctx, "ResolveEndpoint")
	defer span.End()
	
	if awsmiddleware.GetRequiresLegacyEndpoints(ctx) {
	    return next.HandleFinalize(ctx, in)
	}
	
	req, ok := in.Request.(*smithyhttp.Request)
	if !ok {
	    return out, metadata, fmt.Errorf("unknown transport type %T", in.Request)
	}
	
	if m.options.EndpointResolverV2 == nil {
	    return out, metadata, fmt.Errorf("expected endpoint resolver to not be nil")
	}
	
	params := bindEndpointParams(ctx, getOperationInput(ctx), m.options)
	endpt, err := timeOperationMetric(ctx, "client.call.resolve_endpoint_duration",
	    func() (smithyendpoints.Endpoint, error) {
	        return m.options.EndpointResolverV2.ResolveEndpoint(ctx, *params)
	    })
	if err != nil {
	    return out, metadata, fmt.Errorf("failed to resolve service endpoint, %w", err)
	}
	
	span.SetProperty("client.call.resolved_endpoint", endpt.URI.String())
	
	if endpt.URI.RawPath == "" && req.URL.RawPath != "" {
	    endpt.URI.RawPath = endpt.URI.Path
	}
	req.URL.Scheme = endpt.URI.Scheme
	req.URL.Host = endpt.URI.Host
	req.URL.Path = smithyhttp.JoinPath(endpt.URI.Path, req.URL.Path)
	req.URL.RawPath = smithyhttp.JoinPath(endpt.URI.RawPath, req.URL.RawPath)
	for k := range endpt.Headers {
	    req.Header.Set(k, endpt.Headers.Get(k))
	}
	
	rscheme := getResolvedAuthScheme(ctx)
	if rscheme == nil {
	    return out, metadata, fmt.Errorf("no resolved auth scheme")
	}
	
	opts, _ := smithyauth.GetAuthOptions(&endpt.Properties)
	for _, o := range opts {
	    rscheme.SignerProperties.SetAll(&o.SignerProperties)
	}
	
	span.End()
	return next.HandleFinalize(ctx, in)
}
