/* Publisher interface
Copyright (C) 2020 Jonathan Hanks

This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

#ifndef PUB_SUB2_PUB_HH
#define PUB_SUB2_PUB_HH

#include <functional>
#include <memory>
#include <string>

#include <cds-pubsub/common.hh>
#include <cds-pubsub/pub_plugin.hh>

namespace pub_sub
{

    namespace detail
    {
        struct PublisherIntl;
    }

    /*!
     * @brief The publisher component of pub_sub.
     * @details A move only type that opens up and manages a server connection.
     * It listens to and manages client subscription requests.  Each message
     * submitted to the publisher is sent out to the subscribing clients.
     *
     * @note The publisher starts and controls a single background thread
     * which manages all connections and I/O.
     *
     * @note The publisher may hold onto Messages for several message sending
     * cycles to allow a client to 'catch up' after an issue.
     */
    class Publisher
    {
    public:
        /*!
         * @brief create a publisher with no destination
         * @param debug
         */
        explicit Publisher( PubDebugNotices* debug = nullptr );
        /*!
         * @brief create a publisher and configure it to publish to a
         * destination
         * @param address The publishing destination
         * @param debug
         */
        explicit Publisher( const std::string& address,
                            PubDebugNotices*   debug = nullptr );
        ~Publisher( );

        Publisher( const Publisher& ) = delete;
        Publisher( Publisher&& ) = default;
        Publisher& operator=( const Publisher& ) = delete;
        Publisher& operator=( Publisher&& ) = default;

        /*!
         * @brief Make a publishing plugin available to this publisher.
         * @param plugin The plugin api object
         */
        void load_plugin(
            std::shared_ptr< pub_sub::plugins::PublisherPluginApi > plugin );

        /*!
         * @brief Add a new address to publish data through
         * @param address The address to publish through
         */
        void add_destination( const std::string& address );

        /*!
         * @brief Publish a Message object
         * @param key The application key value to identify the message
         * @param msg The Message to send
         * no longer required.
         */
        void publish( KeyType key, Message msg );

    private:
        std::unique_ptr< detail::PublisherIntl > p_;
    };

} // namespace pub_sub

#endif // PUB_SUB2_PUB_HH
