// Copyright 2014-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_messageiterator.h                                             -*-C++-*-
#ifndef INCLUDED_BMQA_MESSAGEITERATOR
#define INCLUDED_BMQA_MESSAGEITERATOR

//@PURPOSE: Provide a mechanism to iterate over the messages of a MessageEvent.
//
//@CLASSES:
//  bmqa::MessageIterator: read-only sequential iterator on 'Message' objects
//
//@DESCRIPTION: 'bmqa::MessageIterator' is an iterator-like mechanism providing
// read-only sequential access to messages contained into a MessageEvent.
//
///Usage
///-----
// Typical usage of this iterator should follow the following pattern:
//..
//  while (messageIterator.nextMessage()) {
//    const Message& message = messageIterator.message();
//    // Do something with message
//  }
//..


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

// BDE
#include <ball_log.h>

namespace BloombergLP {

// FORWARD DECLARATION
namespace bmqimp { class Event; }

namespace bmqa {


                         // ==========================
                         // struct MessageIteratorImpl
                         // ==========================

struct MessageIteratorImpl {
    // Struct to hold the impl of the 'MessageIterator'; that is so that we can
    // keep the real impl private and use some special cast to manipulate it,
    // without publicly exposing private members.

    // PUBLIC DATA
    bmqimp::Event *d_event_p; // Raw pointer to the event

    bmqa::Message  d_message; // A 'Message', representing a view to the
                              // current message pointing at by this iterator.
                              // This is so that 'message' can return a 'const
                              // Message&' to clearly indicate the lifetime of
                              // the Message, and so that we only create one
                              // such object per MessageIterator.

    int            d_messageIndex;
                              // Position of 'd_message' in the underlying
                              // message event.
};


                           // =====================
                           // class MessageIterator
                           // =====================

class MessageIterator {
    // An iterator providing read-only sequential access to messages contained
    // into a 'MesssageEvent'.

  private:
    // CLASS-SCOPE CATEGORY
    BALL_LOG_SET_CLASS_CATEGORY("BMQA.MESSAGEITERATOR");

  private:
    // DATA
    MessageIteratorImpl d_impl; // Implementation. Abstracted in its own struct
                                // and private so that we can do some magic to
                                // manipulate it without exposing any
                                // accessors/manipulators (this is wanted since
                                // this class is a public class).

  public:
    // CREATORS
    explicit MessageIterator();
        // Default constructor

    //! MessageIterator(const MessageIterator&) = default;

    //! ~MessageIterator() = default;

    // MANIPULATORS
    //! MessageIterator& operator=(const MessageIterator&) = default;

    bool nextMessage();
        // Advance the position of the iterator to the next message in the
        // event.  Return true if there is a next message and false otherwise.
        // Note that advancing to the next message will invalidate any
        // previously returned bmqa::Message retrieved from the 'message()'
        // call.

    // ACCESSORS
    const Message& message() const;
        // Return the message to which the iterator is pointing, if any;
        // otherwise return an invalid message.  Note that 'nextMessage' must
        // be called before 'message' in order to advance the iterators
        // position to the first message in the event.
};

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

#endif