/* Network-Integrated Multimedia Middleware (NMM)
 * http://www.motama.com/nmm.html
 *  
 * Copyright (C) 2006-2007
 * Motama GmbH, Saarbruecken, Germany
 * http://www.motama.com
 *  
 * This file is part of NMM. 
 * 
 * NMM 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; only version 2 of the License.      
 * 
 * NMM 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 NMM; if not, write to the Free Software Foundation,    
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */
#ifndef NMM_SOCK_HPP
#define NMM_SOCK_HPP NMM_SOCK_HPP

#include "nmm/nmm_prefix.hpp"

#include "SocketHandle.hpp"
#include "NetExceptions.hpp"

#include "nmm/nmm_inttypes.hpp"

#include "visibility.hpp"

using namespace std;

namespace NMM {
  
  class INetAddr;
  
  /** Base class for sockets
   */
  class DLLEXPORT Sock {
  public:
    enum QOS_TAG{DEFAULT, STREAMING_DATA, INBAND_DATA, RMI_DATA };
    /** @name Constructor & Destructor
     */
    //@{
    /** Default constructor.
     */
    Sock() throw();
    
    /** Virtual destructor
     */
    virtual ~Sock() {}
    //@}
    
    /** @name Addresses
     */
    //@{
    /** Set address of peer.
     * This method should only be called by a SockConnector or SockAcceptor.
     * @param addr Pointer to peer address
     */
    virtual void setPeerAddress(const INetAddr& addr) = 0;

    /** Returns the peer address of a socket.
     * @return Peer address of this socket
     */
    virtual const INetAddr& getPeerAddress() const = 0;
    
    /** Returns the local address of the socket.
     * @return Local address of this socket
     */
    virtual INetAddr getLocalAddress() const = 0;
    //@}
    
    /** @name Socket Handling
     */
    //@{
    /** Assigns a new socket. The old socket is closed if Sock is owner of it
     * @param socket The new socket
     * @param owner Specify if Sock is responsible for the new socket
     */
    virtual void setSocket(SocketHandle socket, bool owner = false) = 0;
    
    /** returns the current socket.
     * @return current socket
     */
    virtual SocketHandle getSocket() const = 0;
    
    /** Closes the socket.
     */
    virtual void close() = 0;
    //@}
    
    /** @name Transmission Methods
     */
    //@{
    /** Receive data from a connection.
     *
     * @param buffer Buffer where the received data should be stored
     * @param len Maximum number of bytes to receive
     * @return Actual number of bytes received
     * @exception TransmissionException if the transmission fails or a socket error occurs
     */
    virtual size_t recv(void* buffer, size_t len)
      throw(const TransmissionException&) = 0;
    
    /** Send data over a connection.
     *
     * @param buffer Buffer containing the data to be sent
     * @param len Maximum number of bytes to send
     * @return Actual number of bytes sent
     * @exception TransmissionException if the transmission fails or a socket error occurs
     */
    virtual size_t send(const void* buffer, size_t len)
      throw(const TransmissionException&) = 0;
    //@}
    
    /** @name Socket options.
     */
    //@{
    /** Set buffer size for incoming data.
     *
     *  @param value specifies buffer size for incoming data
     */
    void setRecvBufferSize(const int& value);
    
    /** Get the buffer size for incoming data.
     * 
     * @return buffer size for incoming data 
     */
    int getRecvBufferSize() const;

    /** Set the buffer size for outgoing data.
     * 
     * @param value specifies the buffer size for outgoing data 
     */
    void setSendBufferSize(const int& value);

    /** Get the buffer size for outgoing data.
     * 
     * @return buffer size for outgoing data 
     */
    int getSendBufferSize() const;

	/** Get the current fill level of the TCPSendBuffer
     */
    int getUsedSendBuffer() const;

    /** Set the priority of the data.
     *
     * @param value specifies the priority for outgoing data
     */
    void setPriority(const int& value);
    
    /** Get the used priority to send the data.
     *
     * @return the priority for outgoing data
     */
    int getPriority() const;

    /** Sets a QoS Tag to send the data.
     *
     * @param value QoS tag that should be used to send data 
     */
	void setQoSTag(const Sock::QOS_TAG& value);
  
    /** Returns the current QoS Tag to send the data.
     *
     * @return QoS tag that is used to send data 
     */
    Sock::QOS_TAG getQoSTag();

    /** Specifies the transmission rate in bytes per second 
     *
     * @param transmission_rate specifies the transmission rate in bytes per second 
     */
	void setTransmissionRate(const int& transmission_rate) { __token_rate = transmission_rate; }

    /** Specifies the size of a bucket.
     *
     * @param bucket_size specifies size of a bucket (e.g. a video frame) in bytes per second.
     */
    void setBucketSize(const int& bucket_size) { __token_bucket_size = bucket_size; }

    /** Specifies the max peak of transmission rate in bytes per second 
     *
     * @param peak_bandwidth specifies max peak of transmission rate in bytes per second in bytes per second.
     */
    void setPeakTransmissionRate(const int& peak_bandwidth) { __peak_bandwidth = peak_bandwidth; }

    /** Specifies the max packet size. 
     *
     * @param max_packet_size Specifies the max packet size. This value should be 340 for Windows
     */
     void setMaximumPacketSize(const int& max_packet_size) { __max_sdu_size = max_packet_size; }

     /** Specifies the minimum packet size. This value should be 340 for Windows
      * 
      * @param min_packet_size Specifies the max packet size. This value should be 340 for Windows
      */
     void setMinimumPacketSize(const int& min_packet_size) { __minimum_policed_size = min_packet_size; }
    //@}
    
  protected:
    /** Create exception for setting a socket option.
     *
     * Creates and throws a TransmissionException based on the given
     * errno value.
     *
     * @todo This method doesn't throw an exception yet
     *
     * @param my_errno The errno value after the failed attempt to set socket option
     */
    static void createSetSockOptException(int my_errno) throw();
    
    /** Create TransmissionException for reading.
     *
     * Creates and throws a TransmissionException based on the given
     * errno value.
     *
     * @param my_errno The errno value after the failed attempt to read from a socket
     */
    static void createReadTransmissionException(int my_errno)
      throw(const TransmissionException&);
    
    /** Create TransmissionException for writing.
     *
     * Creates and throws a TransmissionException based on the given
     * errno value.
     *
     * @param my_errno The errno value after the failed attempt to write to a socket
     */
    static void createWriteTransmissionException(int my_errno)
      throw(const TransmissionException&);
    
  private:
    /** Disabled copy constructor.
     */
    Sock(const Sock&) throw() {}
    
    /** Disabled assignment operator.
     */
    Sock& operator=(const Sock&) throw() { return *this; }

    QOS_TAG __current_qos_tag;

	int __token_rate;		 // Specifies transmission rate to send data 
	int __token_bucket_size; // Specifies max buffer size
	int __peak_bandwidth;    // specifies max bandwith that can be used
	int __minimum_policed_size;	// Specifies min packet size
	int __max_sdu_size;      // Specifies max packet size
  };
}

#include "nmm/nmm_suffix.hpp"

#endif
