/* 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_VALUEFACTORY_HPP
#define NMM_VALUEFACTORY_HPP NMM_VALUEFACTORY_HPP

#include "nmm/nmm_prefix.hpp"

#include "nmm/utils/Singleton.hpp"
#include "nmm/utils/NamedObject.hpp"

#include "TypeInfo.hpp"

#include <map>
#include <string>

#include "visibility.hpp"
namespace NMM {
  class Value;
  class IValueStream;
  class OValueStream;
  class ValueStreamConstructor;
  class ValueConstructor;

  template<class T>
  class TValue;

  /** A factory for dynamic value instantiation.
   * This class ia a factory which dynamically instantiates values of arbitrary types.
   * Given the type information of a type, this factory looks up a factory object for the type,
   * which can create the value. This requires that a value constructor is registered for the
   * specific type.
   *
   * The ValueFactory is a Singleton.
   *
   * @see ValueConstructor
   */
  class DLLEXPORT ValueFactory : public NamedObject {
    DECLARE_SINGLETON(ValueFactory, CreateUsingNew, DefaultLifetime, MultiThreaded);
    friend class CreateUsingNew<ValueFactory>;
  public:
    /** @name Registration
     */
    //@{
    /** Register a value constructor.
     * This method registers a ValueConstructor for the given type information.
     *
     * @param vc The ValueConstructor
     * @param type Type name
     * @param ns Type namespace
     */
    void registerValue(const ValueConstructor& vc, const string& type, const string& ns = "");

    /** Register a value constructor.
     * This method registers a ValueConstructor for the given type information.
     *
     * @param vc The ValueConstructor
     * @param t_info Type information
     */
    void registerValue(const ValueConstructor& vc, const TypeInfo& t_info);

    /** Unregister a value constructor.
     * This method unregisters the ValueConstructor registered for the given type information.
     *
     * @param t_info Type information
     */
    void unregisterValue(const TypeInfo& t_info);

    /** Check if a value constructor is registered.
     * This method checks if a value constructor is registered for the given type information.
     *
     * @param type Type name
     * @param ns Type namespace
     * @return @c true if a value constructor is registered, @c false otherwise
     */
    bool isRegisterd(const string& type, const string& ns = "");

    /** Check if a value constructor is registered.
     * This method checks if a value constructor is registered for the given type information.
     *
     * @param t_info Type information
     * @return @c true if a value constructor is registered, @c false otherwise
     */
    bool isRegisterd(const TypeInfo& t_info);

    /** Check if a value constructor is registered.
     * This method checks if a value constructor is registered for the given type information.
     *
     * @param t_info Type information
     * @return @c true if a value constructor is registered, @c false otherwise
     */
    bool isValueAvailable(const TypeInfo& t_info)  const;
    //@}

    /** @name Factory Methods
     */
    //@{
    /** Create a value.
     * This method creates a new object. If no value constructor is available, a null pointer is returned.
     * The caller of this method is responsible for deleting the object.
     *
     * This method always creates a Value object, using a TValue wrapper only if necessary.
     *
     * @param type Type name
     * @param ns Type namespace
     * @return Pointer to the created object or 0
     */
    Value* createValue(const string& type, const string& ns = "");

    /** Create a value.
     * This method creates a new object. If no value constructor is available, a null pointer is returned.
     * The caller of this method is responsible for deleting the object.
     *
     * This method always creates a Value object, using a TValue wrapper only if necessary.
     *
     * @param t_info Type information
     * @return Pointer to the created object or 0
     */
    Value* createValue(const TypeInfo& t_info);

    /** Create a wrapped value.
     * This method creates a new object. If no value constructor is available, a null pointer is returned.
     * The caller of this method is responsible for deleting the object.
     *
     * This method always creates a TValue wrapped object, i.e. the result is of type TValue<S*>.
     *
     * @param type Type name
     * @param ns Type namespace
     * @return Pointer to the created object or 0
     */
    Value* createTValue(const string& type, const string& ns = "");

    /** Create a wrapped value.
     * This method creates a new object. If no value constructor is available, a null pointer is returned.
     * The caller of this method is responsible for deleting the object.
     *
     * This method always creates a TValue wrapped object, i.e. the result is of type TValue<S*>.
     *
     * @param t_info Type information
     * @return Pointer to the created object or 0
     */
    Value* createTValue(const TypeInfo& t_info);

    /** Create a wrapped pointer value.
     * This method creates a new object. If no value constructor is available, a null pointer is returned.
     * The caller of this method is responsible for deleting the object.
     *
     * This method always creates a TValue wrapped pointer to an object, i.e. the result is of type TValue<S*>.
     *
     * @param type Type name
     * @param ns Type namespace
     * @return Pointer to the created object or 0
     */
    Value* createTPointerValue(const string& type, const string& ns = "");

    /** Create a wrapped pointer value.
     * This method creates a new object. If no value constructor is available, a null pointer is returned.
     * The caller of this method is responsible for deleting the object.
     *
     * This method always creates a TValue wrapped pointer to an object, i.e. the result is of type TValue<S*>.
     *
     * @param t_info Type information
     * @return Pointer to the created object or 0
     */
    Value* createTPointerValue(const TypeInfo& t_info);

    /** Create a value.
     * This method creates a new object. If no value constructor is available, a null pointer is returned.
     * The caller of this method is responsible for deleting the object.
     * The result is returned as a pointer of the given type.
     *
     * This method always creates a Value object, using a TValue wrapper only if necessary.
     *
     * @param t_info Type information
     * @return Pointer to the created object or 0
     */
    template<class T>
    T* createType(const TypeInfo& t_info) {
      Value* tmp_value = createValue(t_info);
      T* type = dynamic_cast<T*>(tmp_value);
      if (!type) {
        delete tmp_value;
        return 0;
      }
      return type;
    }

    /** Create a wrapped value.
     * This method creates a new object. If no value constructor is available, a null pointer is returned.
     * The caller of this method is responsible for deleting the object.
     * The result is returned as a pointer of the given type.
     *
     * This method always creates a TValue wrapped object, i.e. the result is of type TValue<S*>.
     *
     * @param t_info Type information
     * @return Pointer to the created object or 0
     */
    template<class T>
    TValue<T>* createTValueType(const TypeInfo& t_info) {
      Value* tmp_value = createTValue(t_info);
      TValue<T>* type = dynamic_cast< TValue<T>* >(tmp_value);
      if (!type) {
        delete tmp_value;
        return 0;
      }
      return type;
    }

    /** Create a wrapped pointer value.
     * This method creates a new object. If no value constructor is available, a null pointer is returned.
     * The caller of this method is responsible for deleting the object.
     * The result is returned as a pointer of the given type.
     *
     * This method always creates a TValue wrapped pointer to an object, i.e. the result is of type TValue<S*>.
     *
     * @param t_info Type information
     * @return Pointer to the created object or 0
     */
    template<class T>
    TValue<T*> * createTPointerValueType(const TypeInfo& t_info) {
      Value* tmp_value = createTPointerValue(t_info);
      TValue<T*> * type = dynamic_cast< TValue<T*>* >(tmp_value);
      if (!type) {
        delete tmp_value;
        return 0;
      }
      return type;
    }

    /** Create an object.
     * This method creates a new object. It must be implemented in a subclass.
     * The caller of this method is responsible for deleting the object.
     * The result is returned as a pointer of the given type.
     *
     * This method creates a plain object of type T.
     *
     * @param t_info Type information
     * @return Pointer to the created object
     */
    template<class T>
    T* createObject(const TypeInfo& t_info) {
      return createObject<T>(t_info.t_name, t_info.t_namespace);
    }

    /** Create an object.
     * This method creates a new object. It must be implemented in a subclass.
     * The caller of this method is responsible for deleting the object.
     *
     * This method creates a plain object of type T.
     *
     * @param type Type name
     * @param ns Type namespace
     * @return Pointer to the created object
     */
    template<class T>
    T* createObject(const string& type, const string& ns = "");
    //@}


    /** @name Factory methods for ValueStreams
     */
    //@{
    /** Create an input value stream.
     * This method creates an instance of the input value stream class of the given stream type.
     * If no value stream constructor was found, a null pointer is returned.
     *
     * @param input_stream_type Type name of input value stream
     * @return A new input value stream or 0
     */
    IValueStream* createIValueStream(const string& input_stream_type);

    /** Create an output value stream.
     * This method creates an instance of the output value stream class of the given stream type.
     * If no value stream constructor was found, a null pointer is returned.
     *
     * @param output_stream_type Type name of output value stream
     * @return A new output value stream or 0
     */
    OValueStream* createOValueStream(const string& output_stream_type);
    //@}

    /** @name Value Stream Constructors
     */
    //@{
    /** Get type of partner value stream.
     * This method returns the type name of the input stream class which corresponds
     * to the the output stream class specified by the given type name.
     *
     * @param input_stream_type Type name of input value stream
     * @return Type name of output value stream
     */
    string getIValueStreamPartner(const string& input_stream_type) const;

    /** Get type of partner value stream.
     * This method returns the type name of the output stream class which corresponds
     * to the the input stream class specified by the given type name.
     *
     * @param output_stream_type Type name of output value stream
     * @return Type name of input value stream
     */
    string getOValueStreamPartner(const string& output_stream_type) const;

    /** Register a value stream class.
     * This method registers a value stream constructor for the given value stream types.
     *
     * @param input_stream_type Type name of input value stream
     * @param output_stream_type Type name of output value stream
     * @param vsc Value stream constructor
     */
    void registerValueStream(const string& input_stream_type, const string& output_stream_type, const ValueStreamConstructor& vsc);
    //@}

  protected:
    /** @name Constructor & Destructor
     */
    //@{
    /** Private Constructor.
     * This constructor is called upon singleton instantiation.
     */
    ValueFactory();

    /** Private Destructor.
     * This destructor is called upon singleton cleanup.
     */
    ~ValueFactory();

    /** Disabled copy constructor.
     * This copy constructor is not accessible.
     *
     * @param vf Unused
     */
    ValueFactory(const ValueFactory& vf);
    //@}

    /** Find a value constructor.
     * This method looks up a registered value constructor for the given type information.
     *
     * @param type Type name
     * @param ns Type namespace
     */
    ValueConstructor* findValueConstructor(const string& type, const string& ns)  ;

  private: //member

    /** Iterator in value constructor type namespace map. */
    typedef map<string, map<string, ValueConstructor*> >::iterator MapIt;

    /** Constant iterator in value constructor type namespace map. */
    typedef map<string, map<string, ValueConstructor*> >::const_iterator CMapIt;

    /** Iterator in value constructor type map. */
    typedef map<string, ValueConstructor*>::iterator InternalIt;

    /** Constant iterator in value constructor type map. */
    typedef map<string, ValueConstructor*>::const_iterator CInternalIt;

    /** Iterator in value stream constructor map. */
    typedef map<string, ValueStreamConstructor*>::iterator ValueStreamIt;

    /** Constant iterator in value stream constructor map. */
    typedef map<string, ValueStreamConstructor*>::const_iterator CValueStreamIt;

    map<string, map<string, ValueConstructor*> > __value_map;        ///< Value constructor namespace map
    map<string, ValueStreamConstructor*>  __i_valuestream_map;       ///< Input value stream constructor map
    map<string, ValueStreamConstructor*>  __o_valuestream_map;       ///< Output value stream constructor map
  };

  /** ValueFactory singleton interface.
   */
  typedef ValueFactory::Singleton SValueFactory;

}

#include "nmm/nmm_suffix.hpp"

#endif
