/* 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_SERIALIZED_VALUE_HPP
#define NMM_SERIALIZED_VALUE_HPP NMM_SERIALIZED_VALUE_HPP

#include "nmm/nmm_prefix.hpp"

#include "Value.hpp"
#include "TypeInfo.hpp"
#include "visibility.hpp"

namespace NMM {

  class IValueStream;
  class OValueStream;

  /** A serializable object.
   * This class is a convenient base class for all serializable objects.
   * Classes whose instances can be serialized should derive from this class.
   * This is not required, but it is the easiest and safest way to define a new serializable class.
   *
   * If a class inherits SerializedValue, it can register its attributes for automatic serialization.
   * This class implements methods that serialize or deserilaize an instance using a ValueStream.
   * All serializable attributes must be a subtype of Value. If the type of an attribute is not a
   * subclass of Value, a TValue wrapper must be used, so it can be registered.
   *
   * An instance of this class stores type information about itself. The type information must be
   * initialized in the constructor by passing a TypeInfo argument to the constructor of SerializedValue.
   * For this reason, subclasses of SerializedValue should always provide a constructor that accepts
   * a TypeInfo argument and has at least protected access. The preferred way is to define a protected
   * subclass constructor which accepts a TypeInfo argument and public constructors which do not accept
   * a TypeInfo argument. Copy constructors must also copy the type info by invoking the copy constructor
   * of SerializedValue.
   *
   * This class supports reconstruction mode for serialization of unknown classes.
   * If an object of an unknown class is instantiated, an instance of SerializedValue is created, and
   * all attributes are stored as TValue wrappers inside the object. If this reconstructed object is
   * serialized and deserialized again in a process where the class is known, no information is lost.
   *
   * Another feature of this class are serialization updates. Some objects store attributes in a format
   * which is not ready for serialization. Two protected methods are provided for converting attribute
   * data into serializable format (prepareAttributes()) and converting serializable data back into a format
   * usable by the object (updateAttributes()). An example of "data in a format usable by the object" are
   * external data structures, such as @c sockaddr.
   */
  class DLLEXPORT SerializedValue : public Value {
  public:
    /** @name Constructor & Destructor
     */
    //@{
    /** Default constructor.
     *
     * @param reconstruction_mode @c true to create a reconstructed object, @c false to create a normal object
     * @param memory_mgm Memory management type
     */
    SerializedValue(bool reconstruction_mode = false, Value::MemoryMgm memory_mgm = INOUTVALUE);

    /** Constructor with type information.
     *
     * @param type_name Type name of the exact type of this object
     * @param ns Type namespace of the exact type of this object
     * @param reconstruction_mode @c true to create a reconstructed object, @c false to create a normal object
     * @param memory_mgm Memory management type
     */
    SerializedValue(const string& type_name , const string& ns , bool reconstruction_mode = false, Value::MemoryMgm memory_mgm = INOUTVALUE);

    /** Constructor with type information.
     *
     * @param ti Type information of the exact type of this object
     * @param reconstruction_mode @c true to create a reconstructed object, @c false to create a normal object
     * @param memory_mgm Memory management type
     */
    SerializedValue(const TypeInfo& ti, bool reconstruction_mode = false, Value::MemoryMgm memory_mgm = INOUTVALUE);

    /** Copy constructor.
     *
     * @param sv Object to copy from
     */
    SerializedValue(const SerializedValue& sv);
    //@}

    /** @name Serialization & Deserialization
     */
    //@{
    /** Assign this value from a stream.
     * This method deserializes an object from given IValueStream.
     * All attributes registered for automatic serialization are deserialized from the value stream
     * using assignFromStream().
     *
     * @param iv Value stream used for serialization
     */
    virtual void assignFromStream(IValueStream& iv);

    /** Assign this value from a stream.
     * This method deserializes an object from given IValueStream.
     * All attributes registered for automatic serialization are deserialized from the value stream
     * using createFromStream().
     *
     * @param iv Value stream used for serialization
     */
    virtual void createFromStream(IValueStream& iv);

    /** Write this value to a stream.
     * This method serializes an object to the given OValueStream.
     * All attributes registered for automatic serialization are serialized to the value stream.
     *
     * @param ov Value stream used for serialization
     */
    virtual void toStream(OValueStream& ov) const;
    //@}

    /** @name Type information
     */
    //@{
    /** Get type information.
     *
     * @return Type name of the type of this object
     */
    inline  const string& getTypeName()           const { return __type_info.t_name; }

    /** Get type information.
     *
     * @return Type namespace of the type of this object
     */
    inline  const string& getNamespace()          const { return __type_info.t_namespace; }

    /** Get type information.
     *
     * @return Type information of the type of this object
     */
    inline  const TypeInfo& getTypeInfo()         const { return __type_info; }
    //@}

    /** @name Memory management
     */
    //@{
    /** Release this value.
     * This method calls releaseValue() on all attributs registered for automatic serialization.
     */
    virtual void releaseValue()                   const;

    /** Virtual copy constructor.
     *
     * @return A copy of this object which has the same type
     */
    virtual SerializedValue* copy()               const { return new SerializedValue(*this); }

    /** Assignment operator.
     *
     * @param iv Object to assign from
     * @return *this
     */
    const SerializedValue& operator=(const SerializedValue& iv);
    //@}

  protected:
    /** @name Attribute Registration and Setting Type Information
     */
    //@{
    /** Register an attribute for automatic serialization.
     * This method registers the given value object, which must be an attribute of this class,
     * for automatic serialization.
     *
     * @param value Value object to register
     */
    inline  void insertArgument(Value* value)           { __arg_array.push_back(value); }

    /** Register an attribute for automatic serialization.
     * This method registers the given value object, which must be an attribute of this class,
     * for automatic serialization.
     *
     * @param value Value object to register
     */
    inline  void registerAttribute(Value* value)        { __arg_array.push_back(value); }

    /** Set type information.
     * This method sets the type information of this object.
     *
     * @param type_name Type name of the type of this object
     */
    inline  void setTypeName(const string& type_name)   { __type_info.t_name = type_name;}

    /** Set type information.
     * This method sets the type information of this object.
     *
     * @param ns Type namespace of the type of this object
     */
    inline  void setNamespace(const string& ns )        { __type_info.t_namespace = ns; }

    /** Set type information.
     * This method sets the type information of this object.
     *
     * @param ti Type information of the type of this object
     */
    inline  void setTypeInfo(const TypeInfo& ti)        { __type_info = ti; }
    //@}

    /** @name Attribute Access
     */
    //@{
    /** Get the number of registered attributes.
     *
     * @return Number of registered attributes
     */
    inline  size_t getSize()                      const { return __arg_array.size(); }

    /** Get an attribute.
     * This method returns a pointer to a registered Value object that represents an attribute
     * registered for automatic serialization. The attribute is identified by its index.
     * The index must be between 0 and getSize()-1 inclusively.
     * The returned object must not be destroyed.
     *
     * @param pos Attribute index
     * @return Pointer to registered value object
     */
    inline        Value* getArgument(size_t pos)        { return __arg_array[pos];}

    /** Get an attribute.
     * This method returns a pointer to a registered Value object that represents an attribute
     * registered for automatic serialization. The attribute is identified by its index.
     * The index must be between 0 and getSize()-1 inclusively.
     * The returned object must not be destroyed.
     *
     * @param pos Attribute index
     * @return Pointer to registered value object
     */
    inline  const Value* getArgument(size_t pos)  const { return __arg_array[pos];}

    /** Get an attribute.
     * This method returns a pointer to a registered Value object that represents an attribute
     * registered for automatic serialization. The attribute is identified by its index.
     * The index must be between 0 and getSize()-1 inclusively.
     * The returned object must not be destroyed.
     *
     * @param pos Attribute index
     * @return Pointer to registered value object
     */
    inline        Value* getAttribute(size_t pos)       { return __arg_array[pos];}

    /** Get an attribute.
     * This method returns a pointer to a registered Value object that represents an attribute
     * registered for automatic serialization. The attribute is identified by its index.
     * The index must be between 0 and getSize()-1 inclusively.
     * The returned object must not be destroyed.
     *
     * @param pos Attribute index
     * @return Pointer to registered value object
     */
    inline  const Value* getAttribute(size_t pos) const { return __arg_array[pos];}
    //@}

    /** @name Serialization Updates
     */
    //@{
    /** Update attributes after deserialization.
     * This method is called after all attributes have been read from a value stream
     * by assignFromStream() or createFromStream().
     * It can be implemented in subclasses to update attributes that depend on the
     * serialized attributes and convert serialized data back in a format usable by the object.
     *
     * The default implementation does nothing. The base class implementation must be called.
     */
    virtual void updateAttributes()                               {};

    /** Prepare attributes for serialization.
     * This method is called before all attributes are written to a value stream
     * by toStream().
     * It can be implemented in subclasses to prepare serialized attributes that depend on
     * attributes which are not serialized and convert data into a serializable format.
     *
     * The default implementation does nothing. The base class implementation must be called.
     */
    virtual void prepareAttributes()                              {};
    //@}

  private: //methods
    /** Assignment.
     * This method implements the assignment operator.
     * It is used by the assignment operator and the copy constructor.
     *
     * @param sv Object to assign from
     * @return *this
     */
    const SerializedValue& assign(const SerializedValue& sv);

  private: //member
    vector<Value*>  __arg_array;              ///< Attributes registered for automatic serialization
    TypeInfo        __type_info;              ///< Type information for the type of this object
    bool            __reconstruction_mode;    ///< This object is a reconstructed object
  };

}

#include "nmm/nmm_suffix.hpp"

#endif
