/* 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_I_NET_STREAM_HPP
#define NMM_I_NET_STREAM_HPP NMM_I_NET_STREAM_HPP

#include "nmm/nmm_prefix.hpp"

#include "nmm/comm/serialize/IStream.hpp"

#include "visibility.hpp"

namespace NMM {

  class Sock;

  /** A network input stream.
   * This class is an input stream which reads data from a network socket.
   * The actual socket read operation, including buffering strategies, is implemented in subclasses.
   */
  class DLLEXPORT INetStream
    : public IStream
  {
  public:
    /** @name Constructor & Destructor
     */
    //@{
    /** Constructor.
     */
    INetStream();

    /** Copy constructor.
     *
     * @param other Object to copy from
     */
    INetStream(const INetStream& other);

    /** Virtual destructor.
     */
    virtual ~INetStream();

    /** virtual copy constructor.
     *
     * @return A copy of this object which has the same type
     */
    virtual INetStream* copy() const = 0;
    //@}

    /** @name Serialization Operator
     */
    //@{
    /** Input serialization operator.
     * This is the input serialization operator for a basic type.
     * This implementation invokes the socket read method and converts binary data into a value.
     *
     * @param value Reference to variable to be serialized
     * @return *this 
     */
    virtual INetStream& operator>>(nmm_uint16& value)       ;

    /** Input serialization operator.
     * This is the input serialization operator for a basic type.
     * This implementation invokes the socket read method and converts binary data into a value.
     *
     * @param value Reference to variable to be serialized
     * @return *this 
     */
    virtual INetStream& operator>>(nmm_int16& value)         ;

    /** Input serialization operator.
     * This is the input serialization operator for a basic type.
     * This implementation invokes the socket read method and converts binary data into a value.
     *
     * @param value Reference to variable to be serialized
     * @return *this
     */
    virtual INetStream& operator>>(nmm_uint32& value)     ;

    /** Input serialization operator.
     * This is the input serialization operator for a basic type.
     * This implementation invokes the socket read method and converts binary data into a value.
     *
     * @param value Reference to variable to be serialized
     * @return *this
     */
    virtual INetStream& operator>>(nmm_int32& value)       ;

    /** Input serialization operator.
     * This is the input serialization operator for a basic type.
     * This implementation invokes the socket read method and converts binary data into a value.
     *
     * @param value Reference to variable to be serialized
     * @return *this 
     */
    virtual INetStream& operator>>(nmm_uint64& value)     ;

    /** Input serialization operator.
     * This is the input serialization operator for a basic type.
     * This implementation invokes the socket read method and converts binary data into a value.
     *
     * @param value Reference to variable to be serialized
     * @return *this 
     */
    virtual INetStream& operator>>(nmm_int64& value)       ;

    /** Input serialization operator.
     * This is the input serialization operator for a basic type.
     * This implementation invokes the socket read method and converts binary data into a value.
     *
     * @param value Reference to variable to be serialized
     * @return *this
     */
    virtual INetStream& operator>>(nmm_bool& value)          ;

    /** Input serialization operator.
     * This is the input serialization operator for a basic type.
     * This implementation invokes the socket read method and converts binary data into a value.
     *
     * @param value Reference to variable to be serialized
     * @return *this 
     */
    virtual INetStream& operator>>(nmm_double& value)         ;

    /** Input serialization operator.
     * This is the input serialization operator for a basic type.
     * This implementation invokes the socket read method and converts binary data into a value.
     *
     * @param value Reference to variable to be serialized
     * @return *this 
     */
    virtual INetStream& operator>>(nmm_float& value)          ;

    /** Input serialization operator.
     * This is the input serialization operator for a basic type.
     * This implementation invokes the socket read method and converts binary data into a value.
     *
     * @param value Reference to variable to be serialized
     * @return *this
     */
    virtual INetStream& operator>>(nmm_char& value)           ;

    /** Input serialization operator.
     * This is the input serialization operator for a basic type.
     * This implementation invokes the socket read method and converts binary data into a value.
     *
     * @param value Reference to variable to be serialized
     * @return *this
     */
    virtual INetStream& operator>>(nmm_uchar& value)   ;

    /** Input serialization operator.
     * This is the input serialization operator for a basic type.
     * This implementation invokes the socket read method and converts binary data into a value.
     *
     * @param value Reference to variable to be serialized
     * @return *this
     */
    virtual INetStream& operator>>(string& value)          ;
    //@}

    /** @name Buffer Reading
     */
    //@{
    /** Read raw data from this stream.
     * This method reads exactly the given number of raw bytes from the stream
     * and stores the read data in a buffer.
     *
     * @param buffer Pointer to buffer that stores the read data
     * @param size Number of bytes to read
     */
    virtual void readBuffer(char* buffer, nmm_uint32 size)           ;

    /** Read raw data from this stream.
     * This method reads exactly the given number of raw bytes from the stream
     * and stores the read data in a buffer.
     *
     * @param buffer Pointer to buffer that stores the read data
     * @param size Number of bytes to read
     */
    virtual void readBuffer(unsigned char* buffer, nmm_uint32 size);
    //@}
    
    /** @name Network Stream Methods
     */
    //@{
    /** Set the socket this stream reads from.
     * This method sets the socket this stream writes to.
     * The stream stores a pointer to the socket. The socket must not be destroyed
     * as long as this stream is using it.
     *
     * @param sock A pointer to a socket that is usable by this stream
     */
    void setSock(Sock* sock) {
      __sock = sock;
    }

    /** Get the socket this stream reads from.
     * This method gets the socket this stream reads from.
     * The returned pointer must not be deleted.
     *
     * @return A pointer to the socket that is used by this stream
     */
    Sock* getSock() {
      return __sock;
    }

    /** Get the socket this stream writes to.
     * This method gets the socket this stream reads from.
     * The returned pointer must not be deleted.
     *
     * @return A pointer to the socket that is used by this stream
     */
    const Sock* getSock() const {
      return __sock;
    }

    /** Handle incoming data.
     * This method notifies the stream that data can be read from the socket.
     * The stream internally analyzes the data and checks if there is any actual data that can be read.
     * This method can be used for implementing streams that do additional processing, such as packetizing
     * of data, between the serialization layer and the socket transport layer.
     * The result of this method indicates whether there is any data to read from the sream.
     * The default implementation always returns @c true.
     *
     * @return @c true if there is data to read, @c false otherwise
     */
    virtual bool receivePacket();
    //@}

    /** @name Quality of Service
     */
    //@{
    /** Reset the read counter.
     * This method resets the counter which counts the number of bytes read from the socket to zero.
     */
    inline void resetReadCounter()                { __read_counter = 0; }

    /** Count read bytes.
     * This method increases the counter which counts the number of bytes read from the socket
     * by the given amount. Subclasses call this method in their implementation of the socket read
     * method.
     *
     * @param count Number of read bytes
     */
    inline void countReadBytes(u_int32_t count)   { __read_counter += count; }

    /** Get number of read bytes.
     *
     * @return Total number of read bytes since last reset of the counter
     */
    inline u_int32_t getReadCounter()             { return __read_counter; }
    //@}

  protected:
    /** Subclass constructor.
     * This constructor must be used by subclasses when initializing the base class.
     * Every subclass must also define this subclass constructor as a protected constructor.
     *
     * @param ti Type information for this object
     */
    INetStream(const TypeInfo& ti);

    /** Socket read method.
     * This method performs the actual socket read operation. It is invoked by the implementation
     * of the serialization operators. Subclasses must implement this method.
     *
     * @param data Binary data to be serialized
     * @param size Size of binary data to serialize (in bytes)
     */
    virtual void readValue(void* data, size_t size) = 0;

  private:
    Sock*         __sock;             ///< Socket to read to read from
    u_int32_t     __read_counter;     ///< Total read bytes
  };

}

#include "nmm/nmm_suffix.hpp"

#endif
