/**
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0.
 */

#pragma once
#include <aws/core/client/AWSClient.h>
#include <aws/core/client/AWSClientAsyncCRTP.h>
#include <aws/core/client/ClientConfiguration.h>
#include <aws/core/utils/json/JsonSerializer.h>
#include <aws/firehose/FirehosePaginationBase.h>
#include <aws/firehose/FirehoseServiceClientModel.h>
#include <aws/firehose/FirehoseWaiter.h>
#include <aws/firehose/Firehose_EXPORTS.h>

namespace Aws {
namespace Firehose {
/**
 * <fullname>Amazon Data Firehose</fullname>  <p>Amazon Data Firehose was
 * previously known as Amazon Kinesis Data Firehose.</p>  <p>Amazon Data
 * Firehose is a fully managed service that delivers real-time streaming data to
 * destinations such as Amazon Simple Storage Service (Amazon S3), Amazon
 * OpenSearch Service, Amazon Redshift, Splunk, and various other supported
 * destinations.</p>
 */
class AWS_FIREHOSE_API FirehoseClient : public Aws::Client::AWSJsonClient,
                                        public Aws::Client::ClientWithAsyncTemplateMethods<FirehoseClient>,
                                        public FirehosePaginationBase<FirehoseClient>,
                                        public FirehoseWaiter<FirehoseClient> {
 public:
  typedef Aws::Client::AWSJsonClient BASECLASS;
  static const char* GetServiceName();
  static const char* GetAllocationTag();

  typedef FirehoseClientConfiguration ClientConfigurationType;
  typedef FirehoseEndpointProvider EndpointProviderType;

  /**
   * Initializes client to use DefaultCredentialProviderChain, with default http client factory, and optional client config. If client
   * config is not specified, it will be initialized to default values.
   */
  FirehoseClient(const Aws::Firehose::FirehoseClientConfiguration& clientConfiguration = Aws::Firehose::FirehoseClientConfiguration(),
                 std::shared_ptr<FirehoseEndpointProviderBase> endpointProvider = nullptr);

  /**
   * Initializes client to use SimpleAWSCredentialsProvider, with default http client factory, and optional client config. If client config
   * is not specified, it will be initialized to default values.
   */
  FirehoseClient(const Aws::Auth::AWSCredentials& credentials, std::shared_ptr<FirehoseEndpointProviderBase> endpointProvider = nullptr,
                 const Aws::Firehose::FirehoseClientConfiguration& clientConfiguration = Aws::Firehose::FirehoseClientConfiguration());

  /**
   * Initializes client to use specified credentials provider with specified client config. If http client factory is not supplied,
   * the default http client factory will be used
   */
  FirehoseClient(const std::shared_ptr<Aws::Auth::AWSCredentialsProvider>& credentialsProvider,
                 std::shared_ptr<FirehoseEndpointProviderBase> endpointProvider = nullptr,
                 const Aws::Firehose::FirehoseClientConfiguration& clientConfiguration = Aws::Firehose::FirehoseClientConfiguration());

  /* Legacy constructors due deprecation */
  /**
   * Initializes client to use DefaultCredentialProviderChain, with default http client factory, and optional client config. If client
   * config is not specified, it will be initialized to default values.
   */
  FirehoseClient(const Aws::Client::ClientConfiguration& clientConfiguration);

  /**
   * Initializes client to use SimpleAWSCredentialsProvider, with default http client factory, and optional client config. If client config
   * is not specified, it will be initialized to default values.
   */
  FirehoseClient(const Aws::Auth::AWSCredentials& credentials, const Aws::Client::ClientConfiguration& clientConfiguration);

  /**
   * Initializes client to use specified credentials provider with specified client config. If http client factory is not supplied,
   * the default http client factory will be used
   */
  FirehoseClient(const std::shared_ptr<Aws::Auth::AWSCredentialsProvider>& credentialsProvider,
                 const Aws::Client::ClientConfiguration& clientConfiguration);

  /* End of legacy constructors due deprecation */
  virtual ~FirehoseClient();

  /**
   * <p>Creates a Firehose stream.</p> <p>By default, you can create up to 5,000
   * Firehose streams per Amazon Web Services Region.</p> <p>This is an asynchronous
   * operation that immediately returns. The initial status of the Firehose stream is
   * <code>CREATING</code>. After the Firehose stream is created, its status is
   * <code>ACTIVE</code> and it now accepts data. If the Firehose stream creation
   * fails, the status transitions to <code>CREATING_FAILED</code>. Attempts to send
   * data to a delivery stream that is not in the <code>ACTIVE</code> state cause an
   * exception. To check the state of a Firehose stream, use
   * <a>DescribeDeliveryStream</a>.</p> <p>If the status of a Firehose stream is
   * <code>CREATING_FAILED</code>, this status doesn't change, and you can't invoke
   * <code>CreateDeliveryStream</code> again on it. However, you can invoke the
   * <a>DeleteDeliveryStream</a> operation to delete it.</p> <p>A Firehose stream can
   * be configured to receive records directly from providers using <a>PutRecord</a>
   * or <a>PutRecordBatch</a>, or it can be configured to use an existing Kinesis
   * stream as its source. To specify a Kinesis data stream as input, set the
   * <code>DeliveryStreamType</code> parameter to <code>KinesisStreamAsSource</code>,
   * and provide the Kinesis stream Amazon Resource Name (ARN) and role ARN in the
   * <code>KinesisStreamSourceConfiguration</code> parameter.</p> <p>To create a
   * Firehose stream with server-side encryption (SSE) enabled, include
   * <a>DeliveryStreamEncryptionConfigurationInput</a> in your request. This is
   * optional. You can also invoke <a>StartDeliveryStreamEncryption</a> to turn on
   * SSE for an existing Firehose stream that doesn't have SSE enabled.</p> <p>A
   * Firehose stream is configured with a single destination, such as Amazon Simple
   * Storage Service (Amazon S3), Amazon Redshift, Amazon OpenSearch Service, Amazon
   * OpenSearch Serverless, Splunk, and any custom HTTP endpoint or HTTP endpoints
   * owned by or supported by third-party service providers, including Datadog,
   * Dynatrace, LogicMonitor, MongoDB, New Relic, and Sumo Logic. You must specify
   * only one of the following destination configuration parameters:
   * <code>ExtendedS3DestinationConfiguration</code>,
   * <code>S3DestinationConfiguration</code>,
   * <code>ElasticsearchDestinationConfiguration</code>,
   * <code>RedshiftDestinationConfiguration</code>, or
   * <code>SplunkDestinationConfiguration</code>.</p> <p>When you specify
   * <code>S3DestinationConfiguration</code>, you can also provide the following
   * optional values: BufferingHints, <code>EncryptionConfiguration</code>, and
   * <code>CompressionFormat</code>. By default, if no <code>BufferingHints</code>
   * value is provided, Firehose buffers data up to 5 MB or for 5 minutes, whichever
   * condition is satisfied first. <code>BufferingHints</code> is a hint, so there
   * are some cases where the service cannot adhere to these conditions strictly. For
   * example, record boundaries might be such that the size is a little over or under
   * the configured buffering size. By default, no encryption is performed. We
   * strongly recommend that you enable encryption to ensure secure data storage in
   * Amazon S3.</p> <p>A few notes about Amazon Redshift as a destination:</p> <ul>
   * <li> <p>An Amazon Redshift destination requires an S3 bucket as intermediate
   * location. Firehose first delivers data to Amazon S3 and then uses
   * <code>COPY</code> syntax to load data into an Amazon Redshift table. This is
   * specified in the <code>RedshiftDestinationConfiguration.S3Configuration</code>
   * parameter.</p> </li> <li> <p>The compression formats <code>SNAPPY</code> or
   * <code>ZIP</code> cannot be specified in
   * <code>RedshiftDestinationConfiguration.S3Configuration</code> because the Amazon
   * Redshift <code>COPY</code> operation that reads from the S3 bucket doesn't
   * support these compression formats.</p> </li> <li> <p>We strongly recommend that
   * you use the user name and password you provide exclusively with Firehose, and
   * that the permissions for the account are restricted for Amazon Redshift
   * <code>INSERT</code> permissions.</p> </li> </ul> <p>Firehose assumes the IAM
   * role that is configured as part of the destination. The role should allow the
   * Firehose principal to assume the role, and the role should have permissions that
   * allow the service to deliver the data. For more information, see <a
   * href="https://docs.aws.amazon.com/firehose/latest/dev/controlling-access.html#using-iam-s3">Grant
   * Firehose Access to an Amazon S3 Destination</a> in the <i>Amazon Firehose
   * Developer Guide</i>.</p><p><h3>See Also:</h3>   <a
   * href="http://docs.aws.amazon.com/goto/WebAPI/firehose-2015-08-04/CreateDeliveryStream">AWS
   * API Reference</a></p>
   */
  virtual Model::CreateDeliveryStreamOutcome CreateDeliveryStream(const Model::CreateDeliveryStreamRequest& request) const;

  /**
   * A Callable wrapper for CreateDeliveryStream that returns a future to the operation so that it can be executed in parallel to other
   * requests.
   */
  template <typename CreateDeliveryStreamRequestT = Model::CreateDeliveryStreamRequest>
  Model::CreateDeliveryStreamOutcomeCallable CreateDeliveryStreamCallable(const CreateDeliveryStreamRequestT& request) const {
    return SubmitCallable(&FirehoseClient::CreateDeliveryStream, request);
  }

  /**
   * An Async wrapper for CreateDeliveryStream that queues the request into a thread executor and triggers associated callback when
   * operation has finished.
   */
  template <typename CreateDeliveryStreamRequestT = Model::CreateDeliveryStreamRequest>
  void CreateDeliveryStreamAsync(const CreateDeliveryStreamRequestT& request, const CreateDeliveryStreamResponseReceivedHandler& handler,
                                 const std::shared_ptr<const Aws::Client::AsyncCallerContext>& context = nullptr) const {
    return SubmitAsync(&FirehoseClient::CreateDeliveryStream, request, handler, context);
  }

  /**
   * <p>Deletes a Firehose stream and its data.</p> <p>You can delete a Firehose
   * stream only if it is in one of the following states: <code>ACTIVE</code>,
   * <code>DELETING</code>, <code>CREATING_FAILED</code>, or
   * <code>DELETING_FAILED</code>. You can't delete a Firehose stream that is in the
   * <code>CREATING</code> state. To check the state of a Firehose stream, use
   * <a>DescribeDeliveryStream</a>. </p> <p>DeleteDeliveryStream is an asynchronous
   * API. When an API request to DeleteDeliveryStream succeeds, the Firehose stream
   * is marked for deletion, and it goes into the <code>DELETING</code> state.While
   * the Firehose stream is in the <code>DELETING</code> state, the service might
   * continue to accept records, but it doesn't make any guarantees with respect to
   * delivering the data. Therefore, as a best practice, first stop any applications
   * that are sending records before you delete a Firehose stream.</p> <p>Removal of
   * a Firehose stream that is in the <code>DELETING</code> state is a low priority
   * operation for the service. A stream may remain in the <code>DELETING</code>
   * state for several minutes. Therefore, as a best practice, applications should
   * not wait for streams in the <code>DELETING</code> state to be removed.
   * </p><p><h3>See Also:</h3>   <a
   * href="http://docs.aws.amazon.com/goto/WebAPI/firehose-2015-08-04/DeleteDeliveryStream">AWS
   * API Reference</a></p>
   */
  virtual Model::DeleteDeliveryStreamOutcome DeleteDeliveryStream(const Model::DeleteDeliveryStreamRequest& request) const;

  /**
   * A Callable wrapper for DeleteDeliveryStream that returns a future to the operation so that it can be executed in parallel to other
   * requests.
   */
  template <typename DeleteDeliveryStreamRequestT = Model::DeleteDeliveryStreamRequest>
  Model::DeleteDeliveryStreamOutcomeCallable DeleteDeliveryStreamCallable(const DeleteDeliveryStreamRequestT& request) const {
    return SubmitCallable(&FirehoseClient::DeleteDeliveryStream, request);
  }

  /**
   * An Async wrapper for DeleteDeliveryStream that queues the request into a thread executor and triggers associated callback when
   * operation has finished.
   */
  template <typename DeleteDeliveryStreamRequestT = Model::DeleteDeliveryStreamRequest>
  void DeleteDeliveryStreamAsync(const DeleteDeliveryStreamRequestT& request, const DeleteDeliveryStreamResponseReceivedHandler& handler,
                                 const std::shared_ptr<const Aws::Client::AsyncCallerContext>& context = nullptr) const {
    return SubmitAsync(&FirehoseClient::DeleteDeliveryStream, request, handler, context);
  }

  /**
   * <p>Describes the specified Firehose stream and its status. For example, after
   * your Firehose stream is created, call <code>DescribeDeliveryStream</code> to see
   * whether the Firehose stream is <code>ACTIVE</code> and therefore ready for data
   * to be sent to it. </p> <p>If the status of a Firehose stream is
   * <code>CREATING_FAILED</code>, this status doesn't change, and you can't invoke
   * <a>CreateDeliveryStream</a> again on it. However, you can invoke the
   * <a>DeleteDeliveryStream</a> operation to delete it. If the status is
   * <code>DELETING_FAILED</code>, you can force deletion by invoking
   * <a>DeleteDeliveryStream</a> again but with
   * <a>DeleteDeliveryStreamInput$AllowForceDelete</a> set to true.</p><p><h3>See
   * Also:</h3>   <a
   * href="http://docs.aws.amazon.com/goto/WebAPI/firehose-2015-08-04/DescribeDeliveryStream">AWS
   * API Reference</a></p>
   */
  virtual Model::DescribeDeliveryStreamOutcome DescribeDeliveryStream(const Model::DescribeDeliveryStreamRequest& request) const;

  /**
   * A Callable wrapper for DescribeDeliveryStream that returns a future to the operation so that it can be executed in parallel to other
   * requests.
   */
  template <typename DescribeDeliveryStreamRequestT = Model::DescribeDeliveryStreamRequest>
  Model::DescribeDeliveryStreamOutcomeCallable DescribeDeliveryStreamCallable(const DescribeDeliveryStreamRequestT& request) const {
    return SubmitCallable(&FirehoseClient::DescribeDeliveryStream, request);
  }

  /**
   * An Async wrapper for DescribeDeliveryStream that queues the request into a thread executor and triggers associated callback when
   * operation has finished.
   */
  template <typename DescribeDeliveryStreamRequestT = Model::DescribeDeliveryStreamRequest>
  void DescribeDeliveryStreamAsync(const DescribeDeliveryStreamRequestT& request,
                                   const DescribeDeliveryStreamResponseReceivedHandler& handler,
                                   const std::shared_ptr<const Aws::Client::AsyncCallerContext>& context = nullptr) const {
    return SubmitAsync(&FirehoseClient::DescribeDeliveryStream, request, handler, context);
  }

  /**
   * <p>Lists your Firehose streams in alphabetical order of their names.</p> <p>The
   * number of Firehose streams might be too large to return using a single call to
   * <code>ListDeliveryStreams</code>. You can limit the number of Firehose streams
   * returned, using the <code>Limit</code> parameter. To determine whether there are
   * more delivery streams to list, check the value of
   * <code>HasMoreDeliveryStreams</code> in the output. If there are more Firehose
   * streams to list, you can request them by calling this operation again and
   * setting the <code>ExclusiveStartDeliveryStreamName</code> parameter to the name
   * of the last Firehose stream returned in the last call.</p><p><h3>See Also:</h3>
   * <a
   * href="http://docs.aws.amazon.com/goto/WebAPI/firehose-2015-08-04/ListDeliveryStreams">AWS
   * API Reference</a></p>
   */
  virtual Model::ListDeliveryStreamsOutcome ListDeliveryStreams(const Model::ListDeliveryStreamsRequest& request = {}) const;

  /**
   * A Callable wrapper for ListDeliveryStreams that returns a future to the operation so that it can be executed in parallel to other
   * requests.
   */
  template <typename ListDeliveryStreamsRequestT = Model::ListDeliveryStreamsRequest>
  Model::ListDeliveryStreamsOutcomeCallable ListDeliveryStreamsCallable(const ListDeliveryStreamsRequestT& request = {}) const {
    return SubmitCallable(&FirehoseClient::ListDeliveryStreams, request);
  }

  /**
   * An Async wrapper for ListDeliveryStreams that queues the request into a thread executor and triggers associated callback when operation
   * has finished.
   */
  template <typename ListDeliveryStreamsRequestT = Model::ListDeliveryStreamsRequest>
  void ListDeliveryStreamsAsync(const ListDeliveryStreamsResponseReceivedHandler& handler,
                                const std::shared_ptr<const Aws::Client::AsyncCallerContext>& context = nullptr,
                                const ListDeliveryStreamsRequestT& request = {}) const {
    return SubmitAsync(&FirehoseClient::ListDeliveryStreams, request, handler, context);
  }

  /**
   * <p>Lists the tags for the specified Firehose stream. This operation has a limit
   * of five transactions per second per account. </p><p><h3>See Also:</h3>   <a
   * href="http://docs.aws.amazon.com/goto/WebAPI/firehose-2015-08-04/ListTagsForDeliveryStream">AWS
   * API Reference</a></p>
   */
  virtual Model::ListTagsForDeliveryStreamOutcome ListTagsForDeliveryStream(const Model::ListTagsForDeliveryStreamRequest& request) const;

  /**
   * A Callable wrapper for ListTagsForDeliveryStream that returns a future to the operation so that it can be executed in parallel to other
   * requests.
   */
  template <typename ListTagsForDeliveryStreamRequestT = Model::ListTagsForDeliveryStreamRequest>
  Model::ListTagsForDeliveryStreamOutcomeCallable ListTagsForDeliveryStreamCallable(
      const ListTagsForDeliveryStreamRequestT& request) const {
    return SubmitCallable(&FirehoseClient::ListTagsForDeliveryStream, request);
  }

  /**
   * An Async wrapper for ListTagsForDeliveryStream that queues the request into a thread executor and triggers associated callback when
   * operation has finished.
   */
  template <typename ListTagsForDeliveryStreamRequestT = Model::ListTagsForDeliveryStreamRequest>
  void ListTagsForDeliveryStreamAsync(const ListTagsForDeliveryStreamRequestT& request,
                                      const ListTagsForDeliveryStreamResponseReceivedHandler& handler,
                                      const std::shared_ptr<const Aws::Client::AsyncCallerContext>& context = nullptr) const {
    return SubmitAsync(&FirehoseClient::ListTagsForDeliveryStream, request, handler, context);
  }

  /**
   * <p>Writes a single data record into an Firehose stream. To write multiple data
   * records into a Firehose stream, use <a>PutRecordBatch</a>. Applications using
   * these operations are referred to as producers.</p> <p>By default, each Firehose
   * stream can take in up to 2,000 transactions per second, 5,000 records per
   * second, or 5 MB per second. If you use <a>PutRecord</a> and
   * <a>PutRecordBatch</a>, the limits are an aggregate across these two operations
   * for each Firehose stream. For more information about limits and how to request
   * an increase, see <a
   * href="https://docs.aws.amazon.com/firehose/latest/dev/limits.html">Amazon
   * Firehose Limits</a>. </p> <p>Firehose accumulates and publishes a particular
   * metric for a customer account in one minute intervals. It is possible that the
   * bursts of incoming bytes/records ingested to a Firehose stream last only for a
   * few seconds. Due to this, the actual spikes in the traffic might not be fully
   * visible in the customer's 1 minute CloudWatch metrics.</p> <p>You must specify
   * the name of the Firehose stream and the data record when using <a>PutRecord</a>.
   * The data record consists of a data blob that can be up to 1,000 KiB in size, and
   * any kind of data. For example, it can be a segment from a log file, geographic
   * location data, website clickstream data, and so on.</p> <p>For multi record
   * de-aggregation, you can not put more than 500 records even if the data blob
   * length is less than 1000 KiB. If you include more than 500 records, the request
   * succeeds but the record de-aggregation doesn't work as expected and
   * transformation lambda is invoked with the complete base64 encoded data blob
   * instead of de-aggregated base64 decoded records.</p> <p>Firehose buffers records
   * before delivering them to the destination. To disambiguate the data blobs at the
   * destination, a common solution is to use delimiters in the data, such as a
   * newline (<code>\n</code>) or some other character unique within the data. This
   * allows the consumer application to parse individual data items when reading the
   * data from the destination.</p> <p>The <code>PutRecord</code> operation returns a
   * <code>RecordId</code>, which is a unique string assigned to each record.
   * Producer applications can use this ID for purposes such as auditability and
   * investigation.</p> <p>If the <code>PutRecord</code> operation throws a
   * <code>ServiceUnavailableException</code>, the API is automatically reinvoked
   * (retried) 3 times. If the exception persists, it is possible that the throughput
   * limits have been exceeded for the Firehose stream. </p> <p>Re-invoking the Put
   * API operations (for example, PutRecord and PutRecordBatch) can result in data
   * duplicates. For larger data assets, allow for a longer time out before retrying
   * Put API operations.</p> <p>Data records sent to Firehose are stored for 24 hours
   * from the time they are added to a Firehose stream as it tries to send the
   * records to the destination. If the destination is unreachable for more than 24
   * hours, the data is no longer available.</p>  <p>Don't concatenate two
   * or more base64 strings to form the data fields of your records. Instead,
   * concatenate the raw data, then perform base64 encoding.</p>
   * <p><h3>See Also:</h3>   <a
   * href="http://docs.aws.amazon.com/goto/WebAPI/firehose-2015-08-04/PutRecord">AWS
   * API Reference</a></p>
   */
  virtual Model::PutRecordOutcome PutRecord(const Model::PutRecordRequest& request) const;

  /**
   * A Callable wrapper for PutRecord that returns a future to the operation so that it can be executed in parallel to other requests.
   */
  template <typename PutRecordRequestT = Model::PutRecordRequest>
  Model::PutRecordOutcomeCallable PutRecordCallable(const PutRecordRequestT& request) const {
    return SubmitCallable(&FirehoseClient::PutRecord, request);
  }

  /**
   * An Async wrapper for PutRecord that queues the request into a thread executor and triggers associated callback when operation has
   * finished.
   */
  template <typename PutRecordRequestT = Model::PutRecordRequest>
  void PutRecordAsync(const PutRecordRequestT& request, const PutRecordResponseReceivedHandler& handler,
                      const std::shared_ptr<const Aws::Client::AsyncCallerContext>& context = nullptr) const {
    return SubmitAsync(&FirehoseClient::PutRecord, request, handler, context);
  }

  /**
   * <p>Writes multiple data records into a Firehose stream in a single call, which
   * can achieve higher throughput per producer than when writing single records. To
   * write single data records into a Firehose stream, use <a>PutRecord</a>.
   * Applications using these operations are referred to as producers.</p>
   * <p>Firehose accumulates and publishes a particular metric for a customer account
   * in one minute intervals. It is possible that the bursts of incoming
   * bytes/records ingested to a Firehose stream last only for a few seconds. Due to
   * this, the actual spikes in the traffic might not be fully visible in the
   * customer's 1 minute CloudWatch metrics.</p> <p>For information about service
   * quota, see <a
   * href="https://docs.aws.amazon.com/firehose/latest/dev/limits.html">Amazon
   * Firehose Quota</a>.</p> <p>Each <a>PutRecordBatch</a> request supports up to 500
   * records. Each record in the request can be as large as 1,000 KB (before base64
   * encoding), up to a limit of 4 MB for the entire request. These limits cannot be
   * changed.</p> <p>You must specify the name of the Firehose stream and the data
   * record when using <a>PutRecord</a>. The data record consists of a data blob that
   * can be up to 1,000 KB in size, and any kind of data. For example, it could be a
   * segment from a log file, geographic location data, website clickstream data, and
   * so on.</p> <p>For multi record de-aggregation, you can not put more than 500
   * records even if the data blob length is less than 1000 KiB. If you include more
   * than 500 records, the request succeeds but the record de-aggregation doesn't
   * work as expected and transformation lambda is invoked with the complete base64
   * encoded data blob instead of de-aggregated base64 decoded records.</p>
   * <p>Firehose buffers records before delivering them to the destination. To
   * disambiguate the data blobs at the destination, a common solution is to use
   * delimiters in the data, such as a newline (<code>\n</code>) or some other
   * character unique within the data. This allows the consumer application to parse
   * individual data items when reading the data from the destination.</p> <p>The
   * <a>PutRecordBatch</a> response includes a count of failed records,
   * <code>FailedPutCount</code>, and an array of responses,
   * <code>RequestResponses</code>. Even if the <a>PutRecordBatch</a> call succeeds,
   * the value of <code>FailedPutCount</code> may be greater than 0, indicating that
   * there are records for which the operation didn't succeed. Each entry in the
   * <code>RequestResponses</code> array provides additional information about the
   * processed record. It directly correlates with a record in the request array
   * using the same ordering, from the top to the bottom. The response array always
   * includes the same number of records as the request array.
   * <code>RequestResponses</code> includes both successfully and unsuccessfully
   * processed records. Firehose tries to process all records in each
   * <a>PutRecordBatch</a> request. A single record failure does not stop the
   * processing of subsequent records. </p> <p>A successfully processed record
   * includes a <code>RecordId</code> value, which is unique for the record. An
   * unsuccessfully processed record includes <code>ErrorCode</code> and
   * <code>ErrorMessage</code> values. <code>ErrorCode</code> reflects the type of
   * error, and is one of the following values:
   * <code>ServiceUnavailableException</code> or <code>InternalFailure</code>.
   * <code>ErrorMessage</code> provides more detailed information about the
   * error.</p> <p>If there is an internal server error or a timeout, the write might
   * have completed or it might have failed. If <code>FailedPutCount</code> is
   * greater than 0, retry the request, resending only those records that might have
   * failed processing. This minimizes the possible duplicate records and also
   * reduces the total bytes sent (and corresponding charges). We recommend that you
   * handle any duplicates at the destination.</p> <p>If <a>PutRecordBatch</a> throws
   * <code>ServiceUnavailableException</code>, the API is automatically reinvoked
   * (retried) 3 times. If the exception persists, it is possible that the throughput
   * limits have been exceeded for the Firehose stream.</p> <p>Re-invoking the Put
   * API operations (for example, PutRecord and PutRecordBatch) can result in data
   * duplicates. For larger data assets, allow for a longer time out before retrying
   * Put API operations.</p> <p>Data records sent to Firehose are stored for 24 hours
   * from the time they are added to a Firehose stream as it attempts to send the
   * records to the destination. If the destination is unreachable for more than 24
   * hours, the data is no longer available.</p>  <p>Don't concatenate two
   * or more base64 strings to form the data fields of your records. Instead,
   * concatenate the raw data, then perform base64 encoding.</p>
   * <p><h3>See Also:</h3>   <a
   * href="http://docs.aws.amazon.com/goto/WebAPI/firehose-2015-08-04/PutRecordBatch">AWS
   * API Reference</a></p>
   */
  virtual Model::PutRecordBatchOutcome PutRecordBatch(const Model::PutRecordBatchRequest& request) const;

  /**
   * A Callable wrapper for PutRecordBatch that returns a future to the operation so that it can be executed in parallel to other requests.
   */
  template <typename PutRecordBatchRequestT = Model::PutRecordBatchRequest>
  Model::PutRecordBatchOutcomeCallable PutRecordBatchCallable(const PutRecordBatchRequestT& request) const {
    return SubmitCallable(&FirehoseClient::PutRecordBatch, request);
  }

  /**
   * An Async wrapper for PutRecordBatch that queues the request into a thread executor and triggers associated callback when operation has
   * finished.
   */
  template <typename PutRecordBatchRequestT = Model::PutRecordBatchRequest>
  void PutRecordBatchAsync(const PutRecordBatchRequestT& request, const PutRecordBatchResponseReceivedHandler& handler,
                           const std::shared_ptr<const Aws::Client::AsyncCallerContext>& context = nullptr) const {
    return SubmitAsync(&FirehoseClient::PutRecordBatch, request, handler, context);
  }

  /**
   * <p>Enables server-side encryption (SSE) for the Firehose stream. </p> <p>This
   * operation is asynchronous. It returns immediately. When you invoke it, Firehose
   * first sets the encryption status of the stream to <code>ENABLING</code>, and
   * then to <code>ENABLED</code>. The encryption status of a Firehose stream is the
   * <code>Status</code> property in <a>DeliveryStreamEncryptionConfiguration</a>. If
   * the operation fails, the encryption status changes to
   * <code>ENABLING_FAILED</code>. You can continue to read and write data to your
   * Firehose stream while the encryption status is <code>ENABLING</code>, but the
   * data is not encrypted. It can take up to 5 seconds after the encryption status
   * changes to <code>ENABLED</code> before all records written to the Firehose
   * stream are encrypted. To find out whether a record or a batch of records was
   * encrypted, check the response elements <a>PutRecordOutput$Encrypted</a> and
   * <a>PutRecordBatchOutput$Encrypted</a>, respectively.</p> <p>To check the
   * encryption status of a Firehose stream, use <a>DescribeDeliveryStream</a>.</p>
   * <p>Even if encryption is currently enabled for a Firehose stream, you can still
   * invoke this operation on it to change the ARN of the CMK or both its type and
   * ARN. If you invoke this method to change the CMK, and the old CMK is of type
   * <code>CUSTOMER_MANAGED_CMK</code>, Firehose schedules the grant it had on the
   * old CMK for retirement. If the new CMK is of type
   * <code>CUSTOMER_MANAGED_CMK</code>, Firehose creates a grant that enables it to
   * use the new CMK to encrypt and decrypt data and to manage the grant.</p> <p>For
   * the KMS grant creation to be successful, the Firehose API operations
   * <code>StartDeliveryStreamEncryption</code> and <code>CreateDeliveryStream</code>
   * should not be called with session credentials that are more than 6 hours
   * old.</p> <p>If a Firehose stream already has encryption enabled and then you
   * invoke this operation to change the ARN of the CMK or both its type and ARN and
   * you get <code>ENABLING_FAILED</code>, this only means that the attempt to change
   * the CMK failed. In this case, encryption remains enabled with the old CMK.</p>
   * <p>If the encryption status of your Firehose stream is
   * <code>ENABLING_FAILED</code>, you can invoke this operation again with a valid
   * CMK. The CMK must be enabled and the key policy mustn't explicitly deny the
   * permission for Firehose to invoke KMS encrypt and decrypt operations.</p> <p>You
   * can enable SSE for a Firehose stream only if it's a Firehose stream that uses
   * <code>DirectPut</code> as its source. </p> <p>The
   * <code>StartDeliveryStreamEncryption</code> and
   * <code>StopDeliveryStreamEncryption</code> operations have a combined limit of 25
   * calls per Firehose stream per 24 hours. For example, you reach the limit if you
   * call <code>StartDeliveryStreamEncryption</code> 13 times and
   * <code>StopDeliveryStreamEncryption</code> 12 times for the same Firehose stream
   * in a 24-hour period.</p><p><h3>See Also:</h3>   <a
   * href="http://docs.aws.amazon.com/goto/WebAPI/firehose-2015-08-04/StartDeliveryStreamEncryption">AWS
   * API Reference</a></p>
   */
  virtual Model::StartDeliveryStreamEncryptionOutcome StartDeliveryStreamEncryption(
      const Model::StartDeliveryStreamEncryptionRequest& request) const;

  /**
   * A Callable wrapper for StartDeliveryStreamEncryption that returns a future to the operation so that it can be executed in parallel to
   * other requests.
   */
  template <typename StartDeliveryStreamEncryptionRequestT = Model::StartDeliveryStreamEncryptionRequest>
  Model::StartDeliveryStreamEncryptionOutcomeCallable StartDeliveryStreamEncryptionCallable(
      const StartDeliveryStreamEncryptionRequestT& request) const {
    return SubmitCallable(&FirehoseClient::StartDeliveryStreamEncryption, request);
  }

  /**
   * An Async wrapper for StartDeliveryStreamEncryption that queues the request into a thread executor and triggers associated callback when
   * operation has finished.
   */
  template <typename StartDeliveryStreamEncryptionRequestT = Model::StartDeliveryStreamEncryptionRequest>
  void StartDeliveryStreamEncryptionAsync(const StartDeliveryStreamEncryptionRequestT& request,
                                          const StartDeliveryStreamEncryptionResponseReceivedHandler& handler,
                                          const std::shared_ptr<const Aws::Client::AsyncCallerContext>& context = nullptr) const {
    return SubmitAsync(&FirehoseClient::StartDeliveryStreamEncryption, request, handler, context);
  }

  /**
   * <p>Disables server-side encryption (SSE) for the Firehose stream. </p> <p>This
   * operation is asynchronous. It returns immediately. When you invoke it, Firehose
   * first sets the encryption status of the stream to <code>DISABLING</code>, and
   * then to <code>DISABLED</code>. You can continue to read and write data to your
   * stream while its status is <code>DISABLING</code>. It can take up to 5 seconds
   * after the encryption status changes to <code>DISABLED</code> before all records
   * written to the Firehose stream are no longer subject to encryption. To find out
   * whether a record or a batch of records was encrypted, check the response
   * elements <a>PutRecordOutput$Encrypted</a> and
   * <a>PutRecordBatchOutput$Encrypted</a>, respectively.</p> <p>To check the
   * encryption state of a Firehose stream, use <a>DescribeDeliveryStream</a>. </p>
   * <p>If SSE is enabled using a customer managed CMK and then you invoke
   * <code>StopDeliveryStreamEncryption</code>, Firehose schedules the related KMS
   * grant for retirement and then retires it after it ensures that it is finished
   * delivering records to the destination.</p> <p>The
   * <code>StartDeliveryStreamEncryption</code> and
   * <code>StopDeliveryStreamEncryption</code> operations have a combined limit of 25
   * calls per Firehose stream per 24 hours. For example, you reach the limit if you
   * call <code>StartDeliveryStreamEncryption</code> 13 times and
   * <code>StopDeliveryStreamEncryption</code> 12 times for the same Firehose stream
   * in a 24-hour period.</p><p><h3>See Also:</h3>   <a
   * href="http://docs.aws.amazon.com/goto/WebAPI/firehose-2015-08-04/StopDeliveryStreamEncryption">AWS
   * API Reference</a></p>
   */
  virtual Model::StopDeliveryStreamEncryptionOutcome StopDeliveryStreamEncryption(
      const Model::StopDeliveryStreamEncryptionRequest& request) const;

  /**
   * A Callable wrapper for StopDeliveryStreamEncryption that returns a future to the operation so that it can be executed in parallel to
   * other requests.
   */
  template <typename StopDeliveryStreamEncryptionRequestT = Model::StopDeliveryStreamEncryptionRequest>
  Model::StopDeliveryStreamEncryptionOutcomeCallable StopDeliveryStreamEncryptionCallable(
      const StopDeliveryStreamEncryptionRequestT& request) const {
    return SubmitCallable(&FirehoseClient::StopDeliveryStreamEncryption, request);
  }

  /**
   * An Async wrapper for StopDeliveryStreamEncryption that queues the request into a thread executor and triggers associated callback when
   * operation has finished.
   */
  template <typename StopDeliveryStreamEncryptionRequestT = Model::StopDeliveryStreamEncryptionRequest>
  void StopDeliveryStreamEncryptionAsync(const StopDeliveryStreamEncryptionRequestT& request,
                                         const StopDeliveryStreamEncryptionResponseReceivedHandler& handler,
                                         const std::shared_ptr<const Aws::Client::AsyncCallerContext>& context = nullptr) const {
    return SubmitAsync(&FirehoseClient::StopDeliveryStreamEncryption, request, handler, context);
  }

  /**
   * <p>Adds or updates tags for the specified Firehose stream. A tag is a key-value
   * pair that you can define and assign to Amazon Web Services resources. If you
   * specify a tag that already exists, the tag value is replaced with the value that
   * you specify in the request. Tags are metadata. For example, you can add friendly
   * names and descriptions or other types of information that can help you
   * distinguish the Firehose stream. For more information about tags, see <a
   * href="https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/cost-alloc-tags.html">Using
   * Cost Allocation Tags</a> in the <i>Amazon Web Services Billing and Cost
   * Management User Guide</i>. </p> <p>Each Firehose stream can have up to 50 tags.
   * </p> <p>This operation has a limit of five transactions per second per account.
   * </p><p><h3>See Also:</h3>   <a
   * href="http://docs.aws.amazon.com/goto/WebAPI/firehose-2015-08-04/TagDeliveryStream">AWS
   * API Reference</a></p>
   */
  virtual Model::TagDeliveryStreamOutcome TagDeliveryStream(const Model::TagDeliveryStreamRequest& request) const;

  /**
   * A Callable wrapper for TagDeliveryStream that returns a future to the operation so that it can be executed in parallel to other
   * requests.
   */
  template <typename TagDeliveryStreamRequestT = Model::TagDeliveryStreamRequest>
  Model::TagDeliveryStreamOutcomeCallable TagDeliveryStreamCallable(const TagDeliveryStreamRequestT& request) const {
    return SubmitCallable(&FirehoseClient::TagDeliveryStream, request);
  }

  /**
   * An Async wrapper for TagDeliveryStream that queues the request into a thread executor and triggers associated callback when operation
   * has finished.
   */
  template <typename TagDeliveryStreamRequestT = Model::TagDeliveryStreamRequest>
  void TagDeliveryStreamAsync(const TagDeliveryStreamRequestT& request, const TagDeliveryStreamResponseReceivedHandler& handler,
                              const std::shared_ptr<const Aws::Client::AsyncCallerContext>& context = nullptr) const {
    return SubmitAsync(&FirehoseClient::TagDeliveryStream, request, handler, context);
  }

  /**
   * <p>Removes tags from the specified Firehose stream. Removed tags are deleted,
   * and you can't recover them after this operation successfully completes.</p>
   * <p>If you specify a tag that doesn't exist, the operation ignores it.</p>
   * <p>This operation has a limit of five transactions per second per account.
   * </p><p><h3>See Also:</h3>   <a
   * href="http://docs.aws.amazon.com/goto/WebAPI/firehose-2015-08-04/UntagDeliveryStream">AWS
   * API Reference</a></p>
   */
  virtual Model::UntagDeliveryStreamOutcome UntagDeliveryStream(const Model::UntagDeliveryStreamRequest& request) const;

  /**
   * A Callable wrapper for UntagDeliveryStream that returns a future to the operation so that it can be executed in parallel to other
   * requests.
   */
  template <typename UntagDeliveryStreamRequestT = Model::UntagDeliveryStreamRequest>
  Model::UntagDeliveryStreamOutcomeCallable UntagDeliveryStreamCallable(const UntagDeliveryStreamRequestT& request) const {
    return SubmitCallable(&FirehoseClient::UntagDeliveryStream, request);
  }

  /**
   * An Async wrapper for UntagDeliveryStream that queues the request into a thread executor and triggers associated callback when operation
   * has finished.
   */
  template <typename UntagDeliveryStreamRequestT = Model::UntagDeliveryStreamRequest>
  void UntagDeliveryStreamAsync(const UntagDeliveryStreamRequestT& request, const UntagDeliveryStreamResponseReceivedHandler& handler,
                                const std::shared_ptr<const Aws::Client::AsyncCallerContext>& context = nullptr) const {
    return SubmitAsync(&FirehoseClient::UntagDeliveryStream, request, handler, context);
  }

  /**
   * <p>Updates the specified destination of the specified Firehose stream.</p>
   * <p>Use this operation to change the destination type (for example, to replace
   * the Amazon S3 destination with Amazon Redshift) or change the parameters
   * associated with a destination (for example, to change the bucket name of the
   * Amazon S3 destination). The update might not occur immediately. The target
   * Firehose stream remains active while the configurations are updated, so data
   * writes to the Firehose stream can continue during this process. The updated
   * configurations are usually effective within a few minutes.</p> <p>Switching
   * between Amazon OpenSearch Service and other services is not supported. For an
   * Amazon OpenSearch Service destination, you can only update to another Amazon
   * OpenSearch Service destination.</p> <p>If the destination type is the same,
   * Firehose merges the configuration parameters specified with the destination
   * configuration that already exists on the delivery stream. If any of the
   * parameters are not specified in the call, the existing values are retained. For
   * example, in the Amazon S3 destination, if <a>EncryptionConfiguration</a> is not
   * specified, then the existing <code>EncryptionConfiguration</code> is maintained
   * on the destination.</p> <p>If the destination type is not the same, for example,
   * changing the destination from Amazon S3 to Amazon Redshift, Firehose does not
   * merge any parameters. In this case, all parameters must be specified.</p>
   * <p>Firehose uses <code>CurrentDeliveryStreamVersionId</code> to avoid race
   * conditions and conflicting merges. This is a required field, and the service
   * updates the configuration only if the existing configuration has a version ID
   * that matches. After the update is applied successfully, the version ID is
   * updated, and can be retrieved using <a>DescribeDeliveryStream</a>. Use the new
   * version ID to set <code>CurrentDeliveryStreamVersionId</code> in the next
   * call.</p><p><h3>See Also:</h3>   <a
   * href="http://docs.aws.amazon.com/goto/WebAPI/firehose-2015-08-04/UpdateDestination">AWS
   * API Reference</a></p>
   */
  virtual Model::UpdateDestinationOutcome UpdateDestination(const Model::UpdateDestinationRequest& request) const;

  /**
   * A Callable wrapper for UpdateDestination that returns a future to the operation so that it can be executed in parallel to other
   * requests.
   */
  template <typename UpdateDestinationRequestT = Model::UpdateDestinationRequest>
  Model::UpdateDestinationOutcomeCallable UpdateDestinationCallable(const UpdateDestinationRequestT& request) const {
    return SubmitCallable(&FirehoseClient::UpdateDestination, request);
  }

  /**
   * An Async wrapper for UpdateDestination that queues the request into a thread executor and triggers associated callback when operation
   * has finished.
   */
  template <typename UpdateDestinationRequestT = Model::UpdateDestinationRequest>
  void UpdateDestinationAsync(const UpdateDestinationRequestT& request, const UpdateDestinationResponseReceivedHandler& handler,
                              const std::shared_ptr<const Aws::Client::AsyncCallerContext>& context = nullptr) const {
    return SubmitAsync(&FirehoseClient::UpdateDestination, request, handler, context);
  }

  virtual void OverrideEndpoint(const Aws::String& endpoint);
  virtual std::shared_ptr<FirehoseEndpointProviderBase>& accessEndpointProvider();

 private:
  friend class Aws::Client::ClientWithAsyncTemplateMethods<FirehoseClient>;
  void init(const FirehoseClientConfiguration& clientConfiguration);

  typedef Aws::Utils::Outcome<Aws::AmazonWebServiceResult<RESPONSE>, FirehoseError> InvokeOperationOutcome;

  InvokeOperationOutcome InvokeServiceOperation(const AmazonWebServiceRequest& request, Aws::Http::HttpMethod httpMethod) const;

  FirehoseClientConfiguration m_clientConfiguration;
  std::shared_ptr<FirehoseEndpointProviderBase> m_endpointProvider;
};

}  // namespace Firehose
}  // namespace Aws
