// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// 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.

/**
 * @file ParticipantImpl.h
 *
 */

#ifndef PARTICIPANTIMPL_H_
#define PARTICIPANTIMPL_H_
#ifndef DOXYGEN_SHOULD_SKIP_THIS_PUBLIC
#include <fastdds/rtps/common/Guid.h>
#include <fastdds/rtps/participant/RTPSParticipantListener.h>
#include <fastrtps/attributes/ParticipantAttributes.h>
#include <fastdds/rtps/reader/StatefulReader.h>
#include <fastdds/dds/topic/TopicDataType.hpp>

namespace eprosima {

namespace fastrtps {

namespace rtps {
class RTPSParticipant;
class WriterProxyData;
class ReaderProxyData;
} // namespace rtps



class Participant;
class ParticipantListener;

class Publisher;
class PublisherImpl;
class PublisherAttributes;
class PublisherListener;
class Subscriber;
class SubscriberImpl;
class SubscriberAttributes;
class SubscriberListener;


/**
 * This is the implementation class of the Participant.
 * @ingroup FASTRTPS_MODULE
 */
class ParticipantImpl
{
    friend class Domain;
    typedef std::pair<Publisher*, PublisherImpl*> t_p_PublisherPair;
    typedef std::pair<Subscriber*, SubscriberImpl*> t_p_SubscriberPair;
    typedef std::vector<t_p_PublisherPair> t_v_PublisherPairs;
    typedef std::vector<t_p_SubscriberPair> t_v_SubscriberPairs;

private:

    ParticipantImpl(
            const ParticipantAttributes& patt,
            Participant* pspart,
            ParticipantListener* listen = nullptr);
    virtual ~ParticipantImpl();

public:

    /**
     * Register a type in this participant.
     * @param type Pointer to the TopicDatType.
     * @return True if registered.
     */
    bool registerType(
            fastdds::dds::TopicDataType* type);

    /**
     * Unregister a type in this participant.
     * @param typeName Name of the type
     * @return True if unregistered.
     */
    bool unregisterType(
            const char* typeName);

    /**
     * Create a Publisher in this Participant.
     * @param att Attributes of the Publisher.
     * @param listen Pointer to the listener.
     * @return Pointer to the created Publisher.
     */
    Publisher* createPublisher(
            const PublisherAttributes& att,
            PublisherListener* listen = nullptr);

    /**
     * Create a Subscriber in this Participant.
     * @param att Attributes of the Subscriber
     * @param listen Pointer to the listener.
     * @return Pointer to the created Subscriber.
     */
    Subscriber* createSubscriber(
            const SubscriberAttributes& att,
            SubscriberListener* listen = nullptr);

    /**
     * Remove a Publisher from this participant.
     * @param pub Pointer to the Publisher.
     * @return True if correctly removed.
     */
    bool removePublisher(
            Publisher* pub);

    /**
     * Remove a Subscriber from this participant.
     * @param sub Pointer to the Subscriber.
     * @return True if correctly removed.
     */
    bool removeSubscriber(
            Subscriber* sub);

    /**
     * Get the GUID_t of the associated RTPSParticipant.
     * @return GUID_t.
     */
    const rtps::GUID_t& getGuid() const;

    /**
     * Get the participant attributes
     * @return Participant attributes
     */
    inline const ParticipantAttributes& getAttributes() const
    {
        return m_att;
    }

    std::pair<rtps::StatefulReader*, rtps::StatefulReader*> getEDPReaders();

    std::vector<std::string> getParticipantNames() const;

    /**
     * This method can be used when using a StaticEndpointDiscovery mechanism different that the one
     * included in FastRTPS, for example when communicating with other implementations.
     * It indicates the Participant that an Endpoint from the XML has been discovered and
     * should be activated.
     * @param partguid Participant GUID_t.
     * @param userId User defined ID as shown in the XML file.
     * @param kind EndpointKind (WRITER or READER)
     * @return True if correctly found and activated.
     */
    bool newRemoteEndpointDiscovered(
            const rtps::GUID_t& partguid,
            uint16_t userId,
            rtps::EndpointKind_t kind);

    rtps::ResourceEvent& get_resource_event() const;

    /**
     * @brief Asserts liveliness of manual by participant readers
     */
    void assert_liveliness();

    const Participant* get_participant() const;

    const rtps::RTPSParticipant* rtps_participant() const
    {
        return mp_rtpsParticipant;
    }

    rtps::RTPSParticipant* rtps_participant()
    {
        return mp_rtpsParticipant;
    }

private:

    //!Participant Attributes
    ParticipantAttributes m_att;
    //!RTPSParticipant
    rtps::RTPSParticipant* mp_rtpsParticipant;
    //!Participant*
    Participant* mp_participant;
    //!Participant Listener
    ParticipantListener* mp_listener;
    //!Publisher Vector
    t_v_PublisherPairs m_publishers;
    //!Subscriber Vector
    t_v_SubscriberPairs m_subscribers;
    //!TOpicDatType vector
    std::vector<fastdds::dds::TopicDataType*> m_types;

    bool getRegisteredType(
            const char* typeName,
            fastdds::dds::TopicDataType** type);

    class MyRTPSParticipantListener : public rtps::RTPSParticipantListener
    {
    public:

        MyRTPSParticipantListener(
                ParticipantImpl* impl)
            : mp_participantimpl(impl)
        {
        }

        virtual ~MyRTPSParticipantListener()
        {
        }

        void onParticipantDiscovery(
                rtps::RTPSParticipant* participant,
                rtps::ParticipantDiscoveryInfo&& info) override;

#if HAVE_SECURITY
        void onParticipantAuthentication(
                rtps::RTPSParticipant* participant,
                rtps::ParticipantAuthenticationInfo&& info) override;
#endif // if HAVE_SECURITY

        void onReaderDiscovery(
                rtps::RTPSParticipant* participant,
                rtps::ReaderDiscoveryInfo&& info) override;

        void onWriterDiscovery(
                rtps::RTPSParticipant* participant,
                rtps::WriterDiscoveryInfo&& info) override;

        ParticipantImpl* mp_participantimpl;

    private:

        using rtps::RTPSParticipantListener::onParticipantDiscovery;
        using rtps::RTPSParticipantListener::onReaderDiscovery;
        using rtps::RTPSParticipantListener::onWriterDiscovery;

    }
    m_rtps_listener;

};

} /* namespace  */
} /* namespace eprosima */
#endif // ifndef DOXYGEN_SHOULD_SKIP_THIS_PUBLIC
#endif /* PARTICIPANTIMPL_H_ */
