#@ template language="C#" inherits="BaseGenerator" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#
    AddLicenseHeader();
#>
using System;
using System.Runtime.ExceptionServices;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Net;
using <#=this.Config.Namespace#>.Model;
using <#=this.Config.Namespace#>.Model.Internal.MarshallTransformations;
using <#=this.Config.Namespace#>.Internal;
using Amazon.Runtime;
using Amazon.Runtime.Internal;
using Amazon.Runtime.Internal.Auth;
using Amazon.Runtime.Internal.Transform;
namespace <#=this.Config.Namespace#>
{
<#    this.FormatServiceClientDocumentation(this.Config.ServiceModel.Documentation); #>
    public partial class Amazon<#=this.Config.ClassName#>Client : AmazonServiceClient, IAmazon<#=this.Config.ClassName#>
    {
		private static IServiceMetadata serviceMetadata = new Amazon<#=this.Config.ClassName#>Metadata();
        
<#
    // Generates generic constructors for the service if enabled in the model
    if(this.Config.GenerateConstructors)
    {
        var usesBearerAuth = this.Config.ServiceModel.SignatureVersion == "bearer";
        var fallbackToAnonymousCredentials = usesBearerAuth;
#>
        #region Constructors
        /// 
        /// Constructs Amazon<#=this.Config.ClassName#>Client with the credentials loaded from the application's
        /// default configuration, and if unsuccessful from the Instance Profile service on an EC2 instance.
        /// 
        /// Example App.config with credentials set. 
        /// 
        /// <?xml version="1.0" encoding="utf-8" ?>
        /// <configuration>
        ///     <appSettings>
        ///         <add key="AWSProfileName" value="AWS Default"/>
        ///     </appSettings>
        /// </configuration>
        /// 
        ///
        /// 
        public Amazon<#=this.Config.ClassName#>Client()
            : base(FallbackCredentialsFactory.GetCredentials(<#= fallbackToAnonymousCredentials ? "fallbackToAnonymous: true" : ""#>), new Amazon<#=this.Config.ClassName#>Config()) { }
        /// 
        /// Constructs Amazon<#=this.Config.ClassName#>Client with the credentials loaded from the application's
        /// default configuration, and if unsuccessful from the Instance Profile service on an EC2 instance.
        /// 
        /// Example App.config with credentials set. 
        /// 
        /// <?xml version="1.0" encoding="utf-8" ?>
        /// <configuration>
        ///     <appSettings>
        ///         <add key="AWSProfileName" value="AWS Default"/>
        ///     </appSettings>
        /// </configuration>
        /// 
        ///
        /// 
        /// The region to connect.
        public Amazon<#=this.Config.ClassName#>Client(RegionEndpoint region)
            : base(FallbackCredentialsFactory.GetCredentials(<#= fallbackToAnonymousCredentials ? "fallbackToAnonymous: true" : ""#>), new Amazon<#=this.Config.ClassName#>Config{RegionEndpoint = region}) { }
        /// 
        /// Constructs Amazon<#=this.Config.ClassName#>Client with the credentials loaded from the application's
        /// default configuration, and if unsuccessful from the Instance Profile service on an EC2 instance.
        /// 
        /// Example App.config with credentials set. 
        /// 
        /// <?xml version="1.0" encoding="utf-8" ?>
        /// <configuration>
        ///     <appSettings>
        ///         <add key="AWSProfileName" value="AWS Default"/>
        ///     </appSettings>
        /// </configuration>
        /// 
        ///
        /// 
        /// The Amazon<#=this.Config.ClassName#>Client Configuration Object
        public Amazon<#=this.Config.ClassName#>Client(Amazon<#=this.Config.ClassName#>Config config)
            : base(FallbackCredentialsFactory.GetCredentials(config<#= fallbackToAnonymousCredentials ? ", fallbackToAnonymous: true" : ""#>), config){}
        /// 
        /// Constructs Amazon<#=this.Config.ClassName#>Client with AWS Credentials
        /// 
        /// AWS Credentials
        public Amazon<#=this.Config.ClassName#>Client(AWSCredentials credentials)
            : this(credentials, new Amazon<#=this.Config.ClassName#>Config())
        {
        }
        /// 
        /// Constructs Amazon<#=this.Config.ClassName#>Client with AWS Credentials
        /// 
        /// AWS Credentials
        /// The region to connect.
        public Amazon<#=this.Config.ClassName#>Client(AWSCredentials credentials, RegionEndpoint region)
            : this(credentials, new Amazon<#=this.Config.ClassName#>Config{RegionEndpoint = region})
        {
        }
        /// 
        /// Constructs Amazon<#=this.Config.ClassName#>Client with AWS Credentials and an
        /// Amazon<#=this.Config.ClassName#>Client Configuration object.
        /// 
        /// AWS Credentials
        /// The Amazon<#=this.Config.ClassName#>Client Configuration Object
        public Amazon<#=this.Config.ClassName#>Client(AWSCredentials credentials, Amazon<#=this.Config.ClassName#>Config clientConfig)
            : base(credentials, clientConfig)
        {
        }
        /// 
        /// Constructs Amazon<#=this.Config.ClassName#>Client with AWS Access Key ID and AWS Secret Key
        /// 
        /// AWS Access Key ID
        /// AWS Secret Access Key
        public Amazon<#=this.Config.ClassName#>Client(string awsAccessKeyId, string awsSecretAccessKey)
            : this(awsAccessKeyId, awsSecretAccessKey, new Amazon<#=this.Config.ClassName#>Config())
        {
        }
        /// 
        /// Constructs Amazon<#=this.Config.ClassName#>Client with AWS Access Key ID and AWS Secret Key
        /// 
        /// AWS Access Key ID
        /// AWS Secret Access Key
        /// The region to connect.
        public Amazon<#=this.Config.ClassName#>Client(string awsAccessKeyId, string awsSecretAccessKey, RegionEndpoint region)
            : this(awsAccessKeyId, awsSecretAccessKey, new Amazon<#=this.Config.ClassName#>Config() {RegionEndpoint=region})
        {
        }
        /// 
        /// Constructs Amazon<#=this.Config.ClassName#>Client with AWS Access Key ID, AWS Secret Key and an
        /// Amazon<#=this.Config.ClassName#>Client Configuration object. 
        /// 
        /// AWS Access Key ID
        /// AWS Secret Access Key
        /// The Amazon<#=this.Config.ClassName#>Client Configuration Object
        public Amazon<#=this.Config.ClassName#>Client(string awsAccessKeyId, string awsSecretAccessKey, Amazon<#=this.Config.ClassName#>Config clientConfig)
            : base(awsAccessKeyId, awsSecretAccessKey, clientConfig)
        {
        }
        /// 
        /// Constructs Amazon<#=this.Config.ClassName#>Client with AWS Access Key ID and AWS Secret Key
        /// 
        /// AWS Access Key ID
        /// AWS Secret Access Key
        /// AWS Session Token
        public Amazon<#=this.Config.ClassName#>Client(string awsAccessKeyId, string awsSecretAccessKey, string awsSessionToken)
            : this(awsAccessKeyId, awsSecretAccessKey, awsSessionToken, new Amazon<#=this.Config.ClassName#>Config())
        {
        }
        /// 
        /// Constructs Amazon<#=this.Config.ClassName#>Client with AWS Access Key ID and AWS Secret Key
        /// 
        /// AWS Access Key ID
        /// AWS Secret Access Key
        /// AWS Session Token
        /// The region to connect.
        public Amazon<#=this.Config.ClassName#>Client(string awsAccessKeyId, string awsSecretAccessKey, string awsSessionToken, RegionEndpoint region)
            : this(awsAccessKeyId, awsSecretAccessKey, awsSessionToken, new Amazon<#=this.Config.ClassName#>Config{RegionEndpoint = region})
        {
        }
        /// 
        /// Constructs Amazon<#=this.Config.ClassName#>Client with AWS Access Key ID, AWS Secret Key and an
        /// Amazon<#=this.Config.ClassName#>Client Configuration object. 
        /// 
        /// AWS Access Key ID
        /// AWS Secret Access Key
        /// AWS Session Token
        /// The Amazon<#=this.Config.ClassName#>Client Configuration Object
        public Amazon<#=this.Config.ClassName#>Client(string awsAccessKeyId, string awsSecretAccessKey, string awsSessionToken, Amazon<#=this.Config.ClassName#>Config clientConfig)
            : base(awsAccessKeyId, awsSecretAccessKey, awsSessionToken, clientConfig)
        {
        }
        #endregion
<#
    }
#>
<#
    // Creates paginators for service if available
    if (this.Config.ServiceModel.HasPaginators)
    {
#>
#if AWS_ASYNC_ENUMERABLES_API
        private I<#=this.Config.ServiceNameRoot#>PaginatorFactory _paginators;
        /// 
        /// Paginators for the service
        /// 
        public I<#=this.Config.ServiceNameRoot#>PaginatorFactory Paginators 
        {
            get 
            {
                if (this._paginators == null) 
                {
                    this._paginators = new <#=this.Config.ServiceNameRoot#>PaginatorFactory(this);
                }
                return this._paginators;
            }
        }
#endif
<#
    }
#>
        #region Overrides
		/// 
        /// Creates the signer for the service.
        /// 
        protected override AbstractAWSSigner CreateSigner()
        {
            return new <#=GeneratorHelpers.DetermineSigner(this.Config.ServiceModel.SignatureVersion, this.Config.ClassName)#>();
        } 
<# if(this.Config.ServiceModel.Customizations.PipelineOverride != null || this.Config.EndpointsRuleSet != null) { #>
        /// 
        /// Customizes the runtime pipeline.
        /// 
        /// Runtime pipeline for the current client.
        protected override void CustomizeRuntimePipeline(RuntimePipeline pipeline)
        {
<#
    var pipelineOverrides = this.Config.ServiceModel.Customizations.PipelineOverride;
    if (pipelineOverrides != null)
    {
        foreach(var o in pipelineOverrides.Overrides )
        {
            if(!string.IsNullOrEmpty(o.Condition))
            {
#>
            if(<#=o.Condition#>)
            {
<#
                if(o.OverrideMethod == "remove")
                {
#>
                pipeline.<#=o.FormattedOverrideMethod#>();
<#
                }
                else
                {
#>
                pipeline.<#=o.FormattedOverrideMethod#>(new <#=o.NewType#>(<#=o.ConstructorInput#>));
<#
                }
#>
            }
<#
                }
                else if(o.OverrideMethod == "remove")
                {
#>
            pipeline.<#=o.FormattedOverrideMethod#>();
<#
                }
                else
                {
#>
            pipeline.<#=o.FormattedOverrideMethod#>(new <#=o.NewType#>(<#=o.ConstructorInput#>));
<#
            }
        }
    }
#>
<# if (this.Config.EndpointsRuleSet != null) { #>
            pipeline.RemoveHandler();
            pipeline.AddHandlerAfter(new Amazon<#=this.Config.ClassName#>EndpointResolver());
<# } #>
        }
<#
        }
#>
		/// 
        /// Capture metadata for the service.
        /// 
        protected override IServiceMetadata ServiceMetadata
        {
            get
            {
                return serviceMetadata;
            }
        }
        #endregion
        #region Dispose
		/// 
        /// Disposes the service client.
        /// 
        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
        }
        #endregion
<#
        var endpointOperation = this.Config.ServiceModel.FindEndpointOperation();
        if(endpointOperation != null)
        {
#>
        #region  EndpointOperation Override
        protected override IEnumerable EndpointOperation(EndpointOperationContextBase context)
        {
            return EndpointDiscoveryResolver.ResolveEndpoints(context, () =>
            {
				var request = new <#=endpointOperation.Name#>Request
				{
<#
        if(endpointOperation.RequestHasOperationEndpointOperationMember)
        {
#>
					Operation = context.OperationName,
<#
        }
        if(endpointOperation.RequestHasIdentifiersEndpointOperationMember)
        {
#>
					Identifiers = new Dictionary(context.EndpointDiscoveryData.Identifiers),
<#
        }
#>
				};
				                
				var response = <#=endpointOperation.Name#>(request);
				if(response.HttpStatusCode != HttpStatusCode.OK || response.Endpoints == null)
				{
					return null;
				}
				var endpoints = new List();
				foreach(var endpoint in response.Endpoints)
                {
                    endpoints.Add(new DiscoveryEndpoint(endpoint.Address, endpoint.CachePeriodInMinutes));
                }
            
				return endpoints;
			});
        }
        #endregion
<#
        }
    // Creates the method code for each operation in the model
        foreach(var operation in this.Config.ServiceModel.Operations)
        {
        #>
        #region  <#=operation.Name#>
<#
        if (this.Config.ServiceModel.Customizations.CreateNoArgOverload(operation.Name))
        {
		if(operation.IsDeprecated)
		{
#>
		[Obsolete("<#=operation.DeprecationMessage#>")]
<#		
		}
#>
        internal virtual <#=operation.Name#>Response <#=operation.Name#>()
        {
            return <#=operation.Name#>(new <#=operation.Name#>Request());
        }
<#
        }
		if(operation.IsDeprecated)
		{
#>
		[Obsolete("<#=operation.DeprecationMessage#>")]
<#		
		}
#>
        internal virtual <#=operation.Name#>Response <#=operation.Name#>(<#=operation.Name#>Request request)
        {
            var options = new InvokeOptions();
            options.RequestMarshaller = <#=operation.Name#>RequestMarshaller.Instance;
            options.ResponseUnmarshaller = <#=operation.Name#>ResponseUnmarshaller.Instance;
<#
            if(!operation.IsEndpointOperation && operation.EndpointDiscoveryEnabled)
            {
#>
            options.EndpointDiscoveryMarshaller = <#=operation.Name#>EndpointDiscoveryMarshaller.Instance;
            options.EndpointOperation = EndpointOperation;
<#
            }
#>
            return Invoke<<#=operation.Name#>Response>(request, options);
        }
<#
        // Creates a version of the operation that takes no arguments and passes a request with no set members if specified in the customizations
        if (this.Config.ServiceModel.Customizations.CreateNoArgOverload(operation.Name))
        {
#>
<#
        this.FormatOperationDocumentationAsync(operation, false);
		if(operation.IsDeprecated)
		{
#>
		[Obsolete("<#=operation.DeprecationMessage#>")]
<#		
		}
#>
        public virtual Task<<#=operation.Name#>Response> <#=operation.Name#>Async(System.Threading.CancellationToken cancellationToken = default(CancellationToken))
        {
            return <#=operation.Name#>Async(new <#=operation.Name#>Request(), cancellationToken);
        }
<#
        }
		// Add async simple methods
		AddSimpleClientMethods(operation, false);
#>
<#
		this.FormatOperationDocumentationAsync(operation, true);
		if(operation.IsDeprecated)
		{
#>
		[Obsolete("<#=operation.DeprecationMessage#>")]
<#		
		}
#>
        <#=operation.IsInternal ? "internal" : "public"#> virtual Task<<#=operation.Name#>Response> <#=operation.Name#>Async(<#=operation.Name#>Request request, System.Threading.CancellationToken cancellationToken = default(CancellationToken))
        {
            var options = new InvokeOptions();
            options.RequestMarshaller = <#=operation.Name#>RequestMarshaller.Instance;
            options.ResponseUnmarshaller = <#=operation.Name#>ResponseUnmarshaller.Instance;
<#
            if(!operation.IsEndpointOperation && operation.EndpointDiscoveryEnabled)
            {
#>
            options.EndpointDiscoveryMarshaller = <#=operation.Name#>EndpointDiscoveryMarshaller.Instance;
            options.EndpointOperation = EndpointOperation;
<#
            }
#>
            return InvokeAsync<<#=operation.Name#>Response>(request, options, cancellationToken);
        }
        #endregion
        <#
        }
        #>
    }
}