/* 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_O_STREAM_HPP
#define NMM_O_STREAM_HPP NMM_O_STREAM_HPP

#include "nmm/nmm_prefix.hpp"

#include "SerializedValue.hpp"

#include "nmm/nmm_inttypes.hpp"
#include "nmm/nmm_types.hpp"
#include <string>
#include "visibility.hpp"

using namespace std;

namespace NMM {

  template<typename T> class TValue;

  /** An output stream.
   * A stream defines defines a serialization method for all serializable types.
   * Output streams are used for reading data into variables being serialized.
   * This is the base class of all output stream classes.
   *
   * An output stream defines a serialization operator '>>' for every basic serializable type.
   * For other types, free serialization operators can be defined.
   *
   * Streams can have partner streams for layered serialization.
   * This allows the creation of serialization stacks.
   * This class provides an interface for setting and managing partner streams.
   *
   * @see IStream
   */
  class DLLEXPORT OStream
    : public SerializedValue
  {
  public:
    /** @name Constructor & Destructor
     */
    //@{
    /** Copy constructor.
     *
     * @param stream Stream object to copy from
     */
    OStream(const OStream& stream);

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

    /** Assignment operator.
     *
     * @param stream Stream object to assign from
     * @return *this
     */
    OStream& operator=(const OStream& stream);

    /** Virtual destructor.
     */
    virtual ~OStream();
    //@}

    /** @name Serialization Operator
     */
    //@{
    /** Output serialization operator.
     * This is the abstract output serialization operator for a basic type.
     * It must be implemented by subclasses.
     * Subclass implementations must have covariant return types.
     *
     * @param value Reference to variable to be serialized
     * @return *this 
     */
    virtual OStream& operator<<(const string& value) = 0;

    /** Output serialization operator.
     * This is the abstract output serialization operator for a basic type.
     * It must be implemented by subclasses.
     * Subclass implementations must have covariant return types.
     *
     * @param value Reference to variable to be serialized
     * @return *this 
     */
    virtual OStream& operator<<(const nmm_uint16& value) = 0;

    /** Output serialization operator.
     * This is the abstract output serialization operator for a basic type.
     * It must be implemented by subclasses.
     * Subclass implementations must have covariant return types.
     *
     * @param value Reference to variable to be serialized
     * @return *this
     */
    virtual OStream& operator<<(const nmm_int16& value) = 0;

    /** Output serialization operator.
     * This is the abstract output serialization operator for a basic type.
     * It must be implemented by subclasses.
     * Subclass implementations must have covariant return types.
     *
     * @param value Reference to variable to be serialized
     * @return *this 
     */
    virtual OStream& operator<<(const nmm_uint32& value) = 0;

    /** Output serialization operator.
     * This is the abstract output serialization operator for a basic type.
     * It must be implemented by subclasses.
     * Subclass implementations must have covariant return types.
     *
     * @param value Reference to variable to be serialized
     * @return *this 
     */
    virtual OStream& operator<<(const nmm_int32& value) = 0;

    /** Output serialization operator.
     * This is the abstract output serialization operator for a basic type.
     * It must be implemented by subclasses.
     * Subclass implementations must have covariant return types.
     *
     * @param value Reference to variable to be serialized
     * @return *this 
     */
    virtual OStream& operator<<(const nmm_uint64& value) = 0;

    /** Output serialization operator.
     * This is the abstract output serialization operator for a basic type.
     * It must be implemented by subclasses.
     * Subclass implementations must have covariant return types.
     *
     * @param value Reference to variable to be serialized
     * @return *this
     */
    virtual OStream& operator<<(const nmm_int64& value) = 0;

    /** Output serialization operator.
     * This is the abstract output serialization operator for a basic type.
     * It must be implemented by subclasses.
     * Subclass implementations must have covariant return types.
     *
     * @param value Reference to variable to be serialized
     * @return *this 
     */
    virtual OStream& operator<<(const nmm_bool& value) = 0;

    /** Output serialization operator.
     * This is the abstract output serialization operator for a basic type.
     * It must be implemented by subclasses.
     * Subclass implementations must have covariant return types.
     *
     * @param value Reference to variable to be serialized
     * @return *this 
     */
    virtual OStream& operator<<(const nmm_double& value) = 0;

    /** Output serialization operator.
     * This is the abstract output serialization operator for a basic type.
     * It must be implemented by subclasses.
     * Subclass implementations must have covariant return types.
     *
     * @param value Reference to variable to be serialized
     * @return *this 
     */ 
    virtual OStream& operator<<(const nmm_float& value) = 0;

    /** Output serialization operator.
     * This is the abstract output serialization operator for a basic type.
     * It must be implemented by subclasses.
     * Subclass implementations must have covariant return types.
     *
     * @param value Reference to variable to be serialized
     * @return *this
     */
    virtual OStream& operator<<(const nmm_char& value) = 0;

    /** Output serialization operator.
     * This is the abstract output serialization operator for a basic type.
     * It must be implemented by subclasses.
     * Subclass implementations must have covariant return types.
     *
     * @param value Reference to variable to be serialized
     * @return *this
     */
    virtual OStream& operator<<(const nmm_uchar& value) = 0;

    /** Write serialized data.
     * This method must be called after all data has been serialized.
     * It flushes written data internally.
     */
    virtual void writeData() {};
    //@}

    /** @name Buffer Writing
     */
    //@{
    /** Write a line of text to this stream.
     * This method writes a line of raw text to the stream.
     *
     * @param value String to write to this stream
     */
    virtual void writeLine(const string& value);

    /** Write raw data to this stream.
     * This method writes the given number of raw bytes from the buffer to the stream.
     *
     * @param buffer Pointer to buffer that stores the data to be written
     * @param size Number of bytes to write
     */
    virtual void writeBuffer(const char* buffer, nmm_uint32 size) = 0;

    /** Write raw data to this stream.
     * This method writes the given number of raw bytes from the buffer to the stream.
     *
     * @param buffer Pointer to buffer that stores the data to be written
     * @param size Number of bytes to write
     */
    virtual void writeBuffer(const unsigned char* buffer, nmm_uint32 size) = 0;
    //@}

    /** @name Partner Streams
     */
    //@{
    /** Set the output partner stream.
     * This method sets the output partner stream of this stream.
     * This stream only stores a reference to the given partner stream (shallow copy).
     * The partner stream is not destroyed if this stream is destroyed.
     * It must not be destroyed while it is set as partner stream of this stream.
     *
     * @param partner_stream Pointer to the partner stream
     */
    void setOPartnerStream(OStream* partner_stream);

    /** Set the output partner stream.
     * This method sets the output partner stream of this stream.
     * This stream stores a deep copy of given partner stream as partner stream.
     * The copy is destroyed when this stream is destroyed.
     * The stream object passed to this method is only used as a source object for copying.
     *
     * @param partner_stream Pointer to a partner stream template
     */
    void setOPartnerStreamDeepCopy(const OStream* partner_stream);

    /** Get the output partner stream.
     * This method gets the output partner stream of this stream.
     * This method only returns a reference to the stream. The caller must not delete it.
     *
     * @return Pointer to output partner stream
     */
    OStream* getOPartnerStream();

    /** Get the output partner stream.
     * This method gets the output partner stream of this stream.
     * This method only returns a reference to the stream. The caller must not delete it.
     *
     * @return Pointer to output partner stream
     */
    const OStream* getOPartnerStream() const;
    //@}
  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
     */
    OStream(const TypeInfo& ti);
  
    /** Assignment.
     * This method implements the assignment operator.
     * It is used by the assignment operator and the copy constructor.
     */
    void assign(const OStream& stream);

    /** Register attributes for serialization.
     */
    void registerAttributes();

  private:
    bool     __own_partner_stream;          ///< Partner stream is a deep copy
    TValue<OStream*>* __partner_stream;     ///< Output partner stream
  };

}

#include "nmm/nmm_suffix.hpp"

#endif
