// Copyright (C) 2001-2015 Federico Montesino Pouzols <fedemp@altern.org>.
//
// 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 2 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 Lesser General Public License
// along with GNU ccRTP.  If not, see <http://www.gnu.org/licenses/>.
//
// As a special exception, you may use this file as part of a free software
// library without restriction.  Specifically, if other files instantiate
// templates or use macros or inline functions from this file, or you compile
// this file and link it with other files to produce an executable, this
// file does not by itself cause the resulting executable to be covered by
// the GNU General Public License.  This exception does not however
// invalidate any other reasons why the executable file might be covered by
// the GNU General Public License.
//
// This exception applies only to the code released under the name GNU
// ccRTP.  If you copy code from other releases into a copy of GNU
// ccRTP, as the General Public License permits, the exception does
// not apply to the code that you add in this way.  To avoid misleading
// anyone as to the status of such modified files, you must delete
// this exception notice from them.
//
// If you write modifications of your own for GNU ccRTP, it is your choice
// whether to permit this exception to apply to your modifications.
// If you do not wish that, delete this exception notice.
//

/**
 * @file sources.h
 *
 * @short Sources of synchronization and participants related clases.
 **/

#ifndef CCXX_RTP_SOURCES_H_
#define CCXX_RTP_SOURCES_H_

#include <string>
#include <ccrtp/rtcppkt.h>

NAMESPACE_COMMONCPP

/**
 * @defgroup sources Participants and synchronization sources.
 * @{
 **/

/**
 * @class SDESItemsHolder
 *
 * Holds the SDES items and related information from a participant in
 * an RTP application. This is a base class for participant classes.
 *
 * @author Federico Montesino Pouzols <fedemp@altern.org>
 **/
class __EXPORT SDESItemsHolder
{
public:
    const std::string&
    getItem(SDESItemType type) const;

    inline const std::string&
    getPRIVPrefix() const
    { return sdesItems[SDESItemTypeEND]; }

    void
    setItem(SDESItemType item, const std::string& val);

    inline void
    setPRIVPrefix(const std::string& val)
    { sdesItems[SDESItemTypeEND] = val; }

protected:
    SDESItemsHolder()
    { }

    inline virtual ~SDESItemsHolder()
    { }

private:
    // SDES items for a participant.
    // sdesItems[0] (== sdesItems[SDESItemTypeEND]) holds the prefix
    // value for the PRIV item. The rest of entries hold the
    // correponding SDES item value.
    std::string sdesItems[SDESItemTypeLast + 1];
};

/**
 * @class Participant
 * @short A class of objects representing remote participants (RTP
 * applications) in a multimedia session.
 *
 * Any RTP socket/queue class that directly or indirectly inherits
 * from QueueRTCPManager (and hence has RTCP support) will represent
 * participants from which any RTP or RTCP packet has been received
 * through a Participant object.  These Participant objects are
 * entities such as end systems (user applications, monitors, etc),
 * RTP mixers and RTP translators.
 *
 * Participant objects are identified by a CNAME and provide access to
 * all known data about the source of RTP/RTCP packets, such as the
 * CNAME and any other SDES item. Each participant object is related
 * to one or more synchronization objects (@see SyncSource).
 *
 * If an RTP application based on ccRTP receives packets from itself
 * (for instance, it is included in the destination list), there will
 * be a Participant object that corresponds to the "local participant"
 * (RTPApplication) object.
 *
 * @author Federico Montesino Pouzols <fedemp@altern.org>
 *
 * @todo implement reference counting from sources, so that when a
 * source is destroyed, we know if the Participant should be
 * destroyed.
 **/
class __EXPORT Participant : private SDESItemsHolder
{
public:
    /**
     * Get the value of an SDES item. For instance,
     * getSDESItem(SDESItemTypeCNAME), return the CNAME of this
     * Participant.
     *
     * @param type type of SDES item to get value of.
     *
     * @return value of the SDES item as a string.
     * @retval empty string when the value is not known (no RTCP
     * packet with the requested SDES item has been received from this
     * source).
     **/
    const std::string&
    getSDESItem(SDESItemType type) const
    { return SDESItemsHolder::getItem(type); }

    /**
     * Get the prefix value for the PRIV SDES item.
     *
     * @return PRIV SDES item prefix as a string.
     * @retval empty string when no PRIV SDES item has been
     * received from this source.
     **/
    inline const std::string&
    getPRIVPrefix() const
    { return SDESItemsHolder::getPRIVPrefix(); }

    /**
     * Construct a new participant.
     *
     * @param cname Unique CNAME identifier.
     **/
    Participant(const std::string& cname);

    ~Participant();

private:
    friend class ParticipantHandler;

    /**
     * Set the value of a SDES item.
     **/
    inline void
    setSDESItem(SDESItemType item, const std::string& val)
    { SDESItemsHolder::setItem(item,val); }

    /**
     * Set prefix value for the PRIV SDES item.
     **/
    inline void
    setPRIVPrefix(const std::string val)
    { SDESItemsHolder::setPRIVPrefix(val); }
};

/**
 * @class SyncSource
 * @short Synchronization source in an RTP session
 *
 * Each synchronization source in an RTP session is identified by a
 * 32-bit numeric SSRC identifier. Each SyncSource object is related
 * to a Participant object, which can be retrieved through the
 * getParticipant() method.
 *
 * @author Federico Montesino Pouzols <fedemp@altern.org>
 **/
class __EXPORT SyncSource
{
public:
    /**
     * @enum State
     *
     * @short Synchronization source states during an RTP session.
     *
     * In general, new synchronization sources are not considered
     * valid until multiple valid data packets or a valid RTCP
     * compound packet has been received from the new source (@see
     * IncomingDataQueue::setMinValidPacketSequence()). Thus, the
     * source will probably be in statePrevalid before reaching
     * one of the two states that indicate a valid source:
     * stateActive and stateInactive.
     *
     * A valid participant is in stateActive state if RTP and/or
     * RTCP packets are currently being received from it. If,
     * after a small number of RTCP report intervals (see
     * IncomingDataQueue::setSourceExpirationPeriod() ), no
     * packets are received, it will reach the stateInactive
     * state. If, after a small number of RTCP report intervals,
     * no packet is received from an inactive source, it will be
     * deleted.
     *
     * If RTCP is being used, after receiving a BYE RTCP packet
     * from a synchronization source, it will reach the
     * stateLeaving state and will be deleted after a delay (see
     * QueueRTCPManager::setLeavingDelay()).
     *
     * Sources in statePrevalid and stateLeaving are not counted
     * for the number of session members estimation.
     **/
    typedef enum {
        stateUnknown,     ///< No valid packet has been received.
        statePrevalid,    ///< Some packets have been
                  ///received, but source validity not
                  ///yet guaranteed.
        stateActive,      ///< We currently receive packets
                  ///(data or control) from this source.
        stateInactive,    ///< Was active in the near past but
                  ///no packet from this source has
                  ///been received lately.
        stateLeaving      ///< An RTCP BYE has been received
                  ///from the source.
    }       State;

    /**
     * @param ssrc SSRC identifier of the source, unique in each
     * session.
     */
    SyncSource(uint32 ssrc);

    ~SyncSource();

    State
    getState() const
    { return state; }

    /**
     * Whether this source sends RTP data packets.
     **/
    bool isSender() const
    { return activeSender; }

    uint32 getID() const
    { return SSRC; }

    /**
     * Get the participant this synchronization source is
     * asociated to.
     *
     * @retval NULL if the stack has not been yet able to identify
     * the participant this source is associated to.
     **/
    inline Participant*
    getParticipant() const
    { return participant; }

    tpport_t getDataTransportPort() const
    { return dataTransportPort; }

    tpport_t getControlTransportPort() const
    { return controlTransportPort; }

    const InetAddress& getNetworkAddress() const
    { return networkAddress; }

protected:
    /**
     * @param source The RTPSource object being copied
     */
    SyncSource(const SyncSource& source);

    SyncSource&
    operator=(const SyncSource& source);

private:
    friend class SyncSourceHandler;

    inline void
    setState(State st)
    { state = st; }

    /**
     * Mark this source as an active sender.
     **/
    inline void
    setSender(bool active)
    { activeSender = active; }

    inline void
    setParticipant(Participant& p)
    { participant = &p; }

    void setDataTransportPort(tpport_t p)
    { dataTransportPort = p; }

    void setControlTransportPort(tpport_t p)
    { controlTransportPort = p; }

    void setNetworkAddress(InetAddress addr)
    { networkAddress = addr; }

    inline void
    setLink(void *l)
    { link = l; }

    void *getLink() const
    { return link; }

    // validity state of this source
    State state;
    // 32-bit SSRC identifier.
    uint32 SSRC;
    // A valid source not always is active
        bool activeSender;
    // The corresponding participant.
    Participant* participant;

    // Network protocol address for data and control connection
    // (both are assumed to be the same).
    InetAddress networkAddress;
    tpport_t dataTransportPort;
    tpport_t controlTransportPort;

    // Pointer to the SyncSourceLink or similar object in the
    // service queue. Saves a lot of searches in the membership
    // table.
    void* link;
};

/**
 * @class RTPApplication
 * @short An RTP application, holding identifying RTCP SDES item
 * values. Represents local participants.
 *
 * An application in the context of RTP: an entity that has a CNAME
 * (unique identifier in the form of user\@host.domain) as well as
 * other RTCP SDES items (such as NAME or TOOL), and may open a number
 * of RTP sessions. Each application is a different source of
 * synchronization (with a potentially diferent SSRC identifier) in
 * each RTP session it participates. All the sources of
 * synchronization from a participant are tied together by means of
 * the CNAME.
 *
 * The definition of this class allows applications based on ccRTP to
 * implement several "RTP applications" in the same process. Each
 * object of this class represents a local participant.
 *
 * @author Federico Montesino Pouzols <fedemp@altern.org>
 **/
class __EXPORT RTPApplication : private SDESItemsHolder
{
private:
    struct ParticipantLink;

public:
    /**
     * Create a new RTP application. If the CNAME string provided
     * has zero length, it is guessed from the user and machine
     * name.
     *
     * @param cname Local participant canonical name.
     **/
    RTPApplication(const std::string& cname);

    ~RTPApplication();

    inline void
    setSDESItem(SDESItemType item, const std::string& val)
    { SDESItemsHolder::setItem(item,val); }

    inline void
    setPRIVPrefix(const std::string& val)
    { SDESItemsHolder::setPRIVPrefix(val); }

    const std::string&
    getSDESItem(SDESItemType item) const
    { return SDESItemsHolder::getItem(item); }

    inline const std::string&
    getPRIVPrefix() const
    { return SDESItemsHolder::getPRIVPrefix(); }

    /**
     * Iterator through the list of participants in this
     * session. Somehow resembles and standard const_iterator
     **/
    class ParticipantsIterator
    {
    public:
        typedef std::forward_iterator_tag iterator_category;
        typedef Participant value_type;
        typedef std::ptrdiff_t difference_type;
        typedef const Participant* pointer;
        typedef const Participant& reference;

        ParticipantsIterator(ParticipantLink* p = NULL) :
            link(p)
        { }

        ParticipantsIterator(const ParticipantsIterator& pi) :
            link(pi.link)
        { }

        reference operator*() const
        { return *(link->getParticipant()); }

        pointer operator->() const
        { return link->getParticipant(); }

        ParticipantsIterator& operator++() {
            link = link->getNext();
            return *this;
        }

        ParticipantsIterator operator++(int) {
            ParticipantsIterator result(*this);
            ++(*this);
            return result;
        }
        friend bool operator==(const ParticipantsIterator& l,
                       const ParticipantsIterator& r)
        { return l.link == r.link; }

        friend bool operator!=(const ParticipantsIterator& l,
                       const ParticipantsIterator& r)
        { return l.link != r.link; }
    private:
        ParticipantLink *link;
    };

    ParticipantsIterator begin()
    { return ParticipantsIterator(firstPart); }

    ParticipantsIterator end()
    { return ParticipantsIterator(NULL); }

    const Participant*
    getParticipant(const std::string& cname) const;

private:
    friend class ApplicationHandler;

    struct ParticipantLink {
        ParticipantLink(Participant& p,
                ParticipantLink* l) :
            participant(&p), next(l)
        { }
        inline ~ParticipantLink() { delete participant; }
        inline Participant* getParticipant() { return participant; }
        inline ParticipantLink* getPrev() { return prev; }
        inline ParticipantLink* getNext() { return next; }
        inline void setPrev(ParticipantLink* l) { prev = l; }
        inline void setNext(ParticipantLink* l) { next = l; }
        Participant* participant;
        ParticipantLink* next, *prev;
    };

    void
    addParticipant(Participant& part);

    void
    removeParticipant(ParticipantLink* part);

    /**
     * Find out the local CNAME as user\@host and store it as part
     * of the internal state of this class.
     */
    void
    findCNAME();

    /// Hash table with sources of RTP and RTCP packets.
    static const size_t defaultParticipantsNum;
    Participant** participants;
    /// List of participants, ordered from older to newer.
    ParticipantLink* firstPart, * lastPart;
};

/**
 * Get the RTPApplication object for the "default" application (the
 * only one used by common applications -those that only implement one
 * "RTP application"). Note that this application object differs from
 * all the others that may be defined in that it is automatically
 * constructed by the ccRTP stack and its CNAME is automatically
 * assigned (as user\@host), whereas the other application objects'
 * CNAME is provided to its constructor.
 **/
__EXPORT RTPApplication& defaultApplication();

/** @}*/ // sources

END_NAMESPACE

#endif //CCXX_RTP_SOURCES_H_

/** EMACS **
 * Local variables:
 * mode: c++
 * c-basic-offset: 8
 * End:
 */
