// Copyright 2016-2023 Bloomberg Finance L.P.
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// bmqa_confirmeventbuilder.h                                         -*-C++-*-
#ifndef INCLUDED_BMQA_CONFIRMEVENTBUILDER
#define INCLUDED_BMQA_CONFIRMEVENTBUILDER

//@PURPOSE: Provide a builder for batching confirmation messages.
//
//@CLASSES:
//  bmqa::ConfirmEventBuilder: builder for batching confirmation messages.
//
//@DESCRIPTION: This component implements a mechanism,
// 'bmqa::ConfirmEventBuilder', that can be used for batching CONFIRM messages.
// The resulting batch can be sent to the BlazingMQ broker using the
// 'bmqa::Session' (refer to 'bmqa_session' for details).  Wherever possible, a
// BlazingMQ consumer should try to send a batch of CONFIRM messages, which is
// more efficient than confirming messages individually.
//
// The builder holds a batch of CONFIRM messages under construction, and
// provides two flavors of 'addMessageConfirmation' method to add a CONFIRM
// message to the batch.  It also provides a routine to retrieve number of
// CONFIRM messages added to the batch.  Once application is done creating the
// batch, it can retrieve the blob (wire-representation) of the batch and send
// it via 'bmqa::Session'.  See 'Usage' section for more details.
//
///Usage
///-----
//: o An instance of bmqa::ConfirmEventBuilder (the builder) can be used to
//:   create multiple batches of CONFIRM messages.  The recommended approach is
//:   to create one instance of the builder and use it throughout the lifetime
//:   of the task (if the task is multi-threaded, an instance per thread must
//:   be created and maintained).  See usage example #1 for an illustration.
//:
//: o The lifetime of an instance of the builder is bound by the bmqa::Session
//:   from which it was created.  In other words, bmqa::Session instance must
//:   outlive the builder instance.
//
///Example 1 - Basic Usage
///-----------------------
//..
//   // In this snippet, we will send a batch of CONFIRMs for all the
//   // 'bmqa::Message' messages received in a 'bmqa::MessageEvent'.
//
//   // Note that error handling is omitted from the snippet for the sake of
//   // brevity.
//
//   bmqa::Session session;
//       // Session start up logic elided.
//
//   // Create and load an instance of the ConfirmEventBuilder.  Note that in
//   // this example, we are creating the builder on the stack everytime a
//   // message event is received.  Another approach can be to maintain the
//   // builder as a data member and use it everytime.
//
//   bmqa::ConfirmEventBuilder builder;
//   session.loadConfirmEventBuilder(&builder);
//
//   // Assuming that a 'bmqa::MessageEvent' is received.
//
//   bmqa::MessageIterator iter = messageEvent.messageIterator();
//   while (iter.nextMessage()) {
//       const bmqa::Message& msg = iter.message();
//
//       // Business logic for processing 'msg' elided.
//
//       int rc = builder.addMessageConfirmation(msg);
//           // Error handling elided.
//   }
//
//   // All messages in the event have been processed and their corresponding
//   // CONFIRM messages have been batched.  Now its time to send the batch to
//   // the BlazingMQ broker.
//
//   int rc = session.confirmMessages(&builder);
//       // Error handling elided.  Note that in case of success, above method
//       // will also reset the 'builder'.
//..
//
///Thread Safety
///-------------
// This component is *NOT* thread safe.  If it is desired to create a batch of
// CONFIRM messages from multiple threads, an instance of the builder must be
// created and maintained *per* *thread*.


// BMQ
#include <bmqscm_version.h>
#include <bmqa_message.h>
#include <bmqt_resultcode.h>

// BDE
#include <bdlbb_blob.h>
#include <bsls_alignedbuffer.h>

namespace BloombergLP {

// FORWARD DECLARATION
namespace bmqp { class ConfirmEventBuilder; }

namespace bmqa {

                       // ==============================
                       // struct ConfirmEventBuilderImpl
                       // ==============================

struct ConfirmEventBuilderImpl {
    // Component-private class.  Do not use.

    // CONSTANTS
    static const int k_MAX_SIZEOF_BMQP_CONFIRMEVENTBUILDER = 64;
        // Constant representing the maximum size of a
        // 'bmqp::ConfirmEventBuilder' object, so that the below AlignedBuffer
        // is big enough.  Note that since this buffer will hold a
        // 'bmqp::ConfirmEventBuilder' which holds a 'bdlbb::Blob' data member,
        // the size is different on 32 vs 64 bits.

    // PUBLIC DATA
    //   (for convenience)
    bsls::AlignedBuffer<k_MAX_SIZEOF_BMQP_CONFIRMEVENTBUILDER>  d_buffer;

    bmqp::ConfirmEventBuilder                                  *d_builder_p;

    // CREATORS
    ConfirmEventBuilderImpl();

  private:
    // NOT IMPLEMENTED
    ConfirmEventBuilderImpl(const ConfirmEventBuilderImpl&); // = delete
    ConfirmEventBuilderImpl&
    operator=(const ConfirmEventBuilderImpl&);               // = delete
};


                         // =========================
                         // class ConfirmEventBuilder
                         // =========================

class ConfirmEventBuilder {
    // Mechanism to build a batch of CONFIRM messages.

  private:
    // DATA
    ConfirmEventBuilderImpl d_impl;

  private:
    // NOT IMPLEMENTED
    ConfirmEventBuilder(const ConfirmEventBuilder& other); // = delete
    ConfirmEventBuilder&
    operator=(const ConfirmEventBuilder& rhs);             // = delete
        // Copy constructor and assignment operator not implemented

  public:
    // CREATORS
    ConfirmEventBuilder();
        // Create an invalid instance.  Application should not create
        // 'ConfirmEventBuilder' themselves, but ask the 'bmqa::Session' to
        // give them one, by using 'bmqa::Session::loadConfirmEventBuilder'.

    ~ConfirmEventBuilder();
        // Destroy this instance.

    // MANIPULATORS
    bmqt::EventBuilderResult::Enum
    addMessageConfirmation(const Message& message);
        // Append a confirmation message for the specified 'message'.  Return
        // zero on success, and a non-zero value otherwise.  Behavior is
        // undefined unless this instance was obtained using
        // 'bmqa::Session::loadConfirmEventBuilder'.

    bmqt::EventBuilderResult::Enum
    addMessageConfirmation(const MessageConfirmationCookie& cookie);
        // Append a confirmation message for the specified
        // MessageConfirmationCookie 'cookie'.  Return zero on success, and a
        // non-zero value otherwise.  Behavior is undefined unless this
        // instance was obtained using
        // 'bmqa::Session::loadConfirmEventBuilder'.

    void reset();
        // Reset the builder, effectively discarding the batch of confirmation
        // messages under construction.

    // ACCESSORS
    int messageCount() const;
        // Return the number of messages currently in the ConfirmEvent being
        // built.  Behavior is undefined unless this instance was obtained
        // using 'bmqa::Session::loadConfirmEventBuilder'.

    const bdlbb::Blob& blob() const;
        // Return a reference not offering modifiable access to the blob of
        // confirmation messages batch built by this builder.  If no messages
        // were added, this will return an empty blob, i.e., a blob with
        // 'length == 0'.  Behavior is undefined unless this instance was
        // obtained using 'bmqa::Session::loadConfirmEventBuilder'.
};


// ============================================================================
//                             INLINE DEFINITIONS
// ============================================================================

                       // ------------------------------
                       // struct ConfirmEventBuilderImpl
                       // ------------------------------

// CREATORS
inline
ConfirmEventBuilderImpl::ConfirmEventBuilderImpl()
: d_buffer()
, d_builder_p(0)
{
    // NOTHING
}


                         // -------------------------
                         // class ConfirmEventBuilder
                         // -------------------------

// CREATORS
inline
ConfirmEventBuilder::ConfirmEventBuilder()
: d_impl()
{
    // NOTHING
}

// MANIPULATORS
inline
bmqt::EventBuilderResult::Enum
ConfirmEventBuilder::addMessageConfirmation(const Message& message)
{
    return addMessageConfirmation(message.confirmationCookie());
}

}  // close package namespace
}  // close enterprise namespace

#endif