//
// Created by jonathan.hanks on 3/10/20.
//

#ifndef LIBCDS_PUBSUB_SUB_PLUGIN_HH
#define LIBCDS_PUBSUB_SUB_PLUGIN_HH

#include <memory>
#include <stdexcept>
#include <string>

#include <cds-pubsub/common.hh>

namespace pub_sub
{
    namespace plugins
    {
        class Subscription
        {
        public:
            Subscription( ) : id_{ next_sub_id( ) }
            {
            }
            explicit Subscription( SubId id ) : id_{ id_ }
            {
            }
            virtual ~Subscription( ) = default;

            SubId
            sub_id( ) const
            {
                return id_;
            }

            /*!
             * @brief Request that the given subscription be restarted if
             * possible
             * @note  Plugins are free to ignore this request.  The
             * default behavior is to ignore the request.
             */
            virtual void
            reset( )
            {
            }

            virtual void
            filter( pub_sub::SubMessage msg )
            {
                throw std::runtime_error( "filter called on a subscription "
                                          "that cannot act as a filter" );
            }

        protected:
            /*!
             * @brief get a new subscription id
             * @return the subscription id to use
             * @note not thread safe
             */
            static SubId
            next_sub_id( )
            {
                static SubId id = 0;
                return id++;
            }

            SubId id_;
        };

        /*!
         * @brief The base class for the subscription plugin api
         * @details The plugin api exposes new sources to subscribe to messages.
         * Each new source should have a plugin api class which inherits
         * SubscriptionPluginApi
         */
        class SubscriptionPluginApi
        {
        public:
            virtual ~SubscriptionPluginApi( ) = default;

            /*!
             * @brief The prefix (tcp:// or udp:// or ...) of the plugin
             * @return the prefix as a string
             */
            virtual const std::string& prefix( ) const = 0;
            /*!
             * @brief the version of the plugin
             * @return version as a string
             */
            virtual const std::string& version( ) const = 0;
            /*!
             * @brief the name of the plugin
             * @return name as a string
             */
            virtual const std::string& name( ) const = 0;

            /*!
             * @brief check if a plugin is a source or a filter
             * @return return true if it is a source (ie can generate messages
             * on its own)
             */
            virtual bool
            is_source( ) const
            {
                return true;
            }

            /*!
             * @brief The subscription interface.
             * @details the Subcriber object will call this method for each new
             * subscription that is requested where conn_str starts with
             * prefix().  This should create and manage a subscription as
             * requested.
             * @param conn_str The connection string
             * @param debug_hooks
             * @param handler The handler pass messages back to
             * @return A subscription id representing the new subscription
             */
            virtual std::shared_ptr< Subscription >
            subscribe( const std::string&        conn_str,
                       pub_sub::SubDebugNotices& debug_hooks,
                       pub_sub::SubHandler       handler ) = 0;
        };
    } // namespace plugins

} // namespace pub_sub
#endif // LIBCDS_PUBSUB_SUB_PLUGIN_HH
