/* 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_TS_FACTORY_HPP
#define NMM_TS_FACTORY_HPP NMM_TS_FACTORY_HPP

#include "nmm/nmm_prefix.hpp"

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

#include <list>
#include <map>

#include "visibility.hpp"

namespace NMM {
  
  class TransportStrategy;
  class ConnectorAcceptor;
  class TSFactoryObject;
  class Format;
  class TSAddress;
  class TSDescription;
  
  /** %TransportStrategy factory.
   *
   * This class is a Factory for TransportStrategies. To create a %TransportStrategy a %TSFactoryObject
   * is used. This Factory can be used to register these objects with the type name of the
   * %TransportStrategy.
   *
   * This class offers so called "default addresses" for TransportStrategies. These addresses
   * can be used to establish a connection. So an NMMObject or other objects, must not allocate
   * ressources, they can use these addresses.
   *
   * When a %TransportStrategy should be created, the application also has to specify which interfaces
   * the %TransportStrategy should support. If the given combination of interfaces is not supported, then
   * the %TransportStrategy can't be created. This is important to prevent the creation of a %TransportStrategy
   * that can not be used, and for creating the corect endpoint of a one-way %TransportStrategy.
   *
   * This class is designed as %Singleton.
   *
   * @see TransportStrategy  ITSOneWayEventSender ITSOneWayEventReceiver ITSOneWayCEventSender ITSOneWayCEventReceiver
   * @see ITSOneWayBufferSender ITSOneWayBufferReceiver ITSRequestReplyEventSender ITSRequestReplyEventReceiver
   */
  class DLLEXPORT TSFactory
    : public NamedObject
  {
    DECLARE_SINGLETON(TSFactory, CreateUsingNew, DefaultLifetime, MultiThreaded);
    friend class CreateUsingNew<TSFactory>;
  public:
    /** @name Factory & Registration methods
     */
    //@{
    /** Registers %TransportStrategy.
     *
     * This method registers an %TSactoryObject that can create a %TransportStrategy with its typename.
     * It also registers the capabilities of the transport strategy and the supported instream formats.
     *
     * @param factory_obj Factory object which creates the instance
     * @param strategy_type Type name of strategy
     * @param interfaces Interfaces of this transport strategy
     * @param format_list List of supported formats
     * @param capabilities Capabilities of this transport strategy
     */
    void registerStrategy(const TSFactoryObject& factory_obj, const std::string& strategy_type, unsigned int interfaces,
                          const std::list<Format>& format_list, unsigned int capabilities);
    
    /** Unregisters %TransportStrategy.
     *
     * This method unregisters the %TSFactoryObject and default address of a %TransportStrategy with the given typename.
     * If the strategy was registered multiple times with different interface flags, all factory objects are removed.
     *
     * @param strategy_type Type name of %TransportStrategy
     */
    void unregisterStrategy(const std::string& strategy_type, unsigned int interfaces, unsigned int capabilities);
    
    /** Creates a %TransportStrategy.
     *
     * This method creates a %TransportStrategy with the given type name and interface flags.
     *
     * @param strategy_type strategy Type of %TransportStrategy to create
     * @param interfaces Interface flags of %TransportStrategy to create
     * @return A pointer to the newly created transport strategy
     */
    TransportStrategy* createTransportStrategy(const std::string& strategy_type, unsigned int interfaces);
    
    /** Sets default address for transport strategy.
     *
     * This method sets an default address for a specific strategy type.
     *
     * @param strategy_type Type name of strategy
     * @param address Default address
     */
    void setDefaultAddress(const std::string& strategy_type, const TSAddress* address);
    //@}
    
    /** @name Access Information
     */
    //@{
    /** Returns default address for a %TransportStrategy.
     *
     * This method returns the default address for the given %TransportStrategy type.
     *
     * @param strategy_type Type name of %TransportStrategy
     * @return default address for a %TransportStrategy
     */
    TSAddress* getDefaultAddress(const std::string& strategy_type) const;
    
    /** Tests if %TransportStrategy available with the given interface flags.
     *
     * This method returns @c true if the given %TransportStrategy type is available with the given interface flags,
     * otherwise @c false.
     *
     * @param strategy_type Type name of %TransportStrategy
     * @param interfaces Interface flags of %TransportStrategy
     * @return true if  given %TransportStrategy type is available with given interface flags, false otherwise
     */
    bool isStrategyAvailable(const std::string& strategy_type, unsigned int interfaces) const;
    
    /** Returns interfaces supported by the given strategy. 
     * If the strategy is registered multiple times with different interface
     * flags, than the result is the union of the supported interfaces
     * of all registered strategies of the given strategy type.
     *
     * @param strategy_type Type name of %TransportStrategy
     * @return Flags specifying the set of interfaces supported by the %TransportStrategy
     */
    unsigned int getInterfaces(const std::string& strategy_type) throw();

    /** Returns capabilies supported by the given strategy.  
     *
     * If the strategy is registered multiple times with different interface
     * flags, than the result is the union of the supported capabilies
     * of all registered strategies of the given strategy type.
     *
     * @param strategy_type Type name of %TransportStrategy
     * @return Flags specifying the set of capabilies supported by the %TransportStrategy
     */
    unsigned int getCapabilities(const std::string& strategy_type) throw();
    
    /** Returns %TransportStrategy list.
     *
     * This method returns a list of all registered %TransportStrategy types.
     *
     * @return list of all registered %TransportStrategy types
     */
    std::list<std::string> getStrategyList() const;
    
    /** Returns a list of all supported transport strategies.
     *
     * @return A list of descriptions of supported strategies.
     */
    std::list<TSDescription> getSupportedStrategies() const throw();
    
    /** Returns a list of all supported transport strategies with the given subset of interfaces.
     *
     * Only the given interface flags are set in the @c interfaces fields of the results.
     * Only transport strategies which have at least one interface flag set are returned.
     *
     * @param max_interfaces The set of interfaces of interest, combination if flags defined in TSDescription::Interfaces
     * @return A list of descriptions of supported strategies.
     */
    std::list<TSDescription> getSupportedStrategies(unsigned int max_interfaces) const throw();

    /** Returns a list of all supported transport strategies with the given subset of interfaces and given capabilities.
     *
     * Only the given interface flags are set in the @c interfaces fields of the results.
     * Only transport strategies which have at least one interface flag set are returned.
     * Only transport strategies are returned which have all the given capabilities.
     *
     * @param max_interfaces The set of interfaces of interest, combination if flags defined in TSDescription::Interfaces
     * @param min_capabilities The set of required capabilities, combination if flags defined in TSDescription::Capabilities
     * @return A list of descriptions of supported strategies.
     */
    std::list<TSDescription> getSupportedStrategies(unsigned int max_interfaces, unsigned int min_capabilities) const throw();
    //@}
    
    /** @name %ConnectorAcceptor Management
     */
    //@{
    /** Requests a %ConnectorAcceptor.
     *
     * This method requests a %ConnectorAcceptor for the given strategy type.
     *
     * @param strategy_type Type name of strategy
     * @return %ConnectorAcceptor for the given strategy type
     */
    ConnectorAcceptor* requestConnectorAcceptor(const std::string& strategy_type) const;
    
    /** Adds a %ConnectorAddress for a %TransportStrategy type.
     *
     * This method registers a %ConnectorAddress as the default address of the given %TransportStrategy type.
     *
     * @param strategy_type Type name of strategy
     */
    void addConnectorAddress(const std::string& strategy_type);
    //@}
    
  private:
    /** @name Constructor & Destructor
     */
    //@{
    /** Creates a %TSFactory.
     */
    TSFactory() ;

    /** Destructor.
     */
    ~TSFactory();

    /** Disabled Copy constructor.
     * 
     * @param tsf TSFactory to copy
     */
    TSFactory(const TSFactory& tsf);
    //@}
    
  private:
    struct InternalStruct {
      InternalStruct()
        : factory_object(NULL),
          default_address(NULL),
          interfaces(0),
          capabilities(0)
      {}
      
      const TSFactoryObject* factory_object;  ///< TSFactoryObject represented by this struct
      TSAddress*             default_address; ///< default address
      unsigned int           interfaces;      ///< flags defining supported interfaces
      unsigned int           capabilities;    ///< flags defining capabilities 
    };
    
    typedef std::multimap<std::string, InternalStruct> InternalMap;
    typedef InternalMap::iterator            InternalIterator;
    typedef InternalMap::const_iterator      InternalConstIterator;
    
    InternalMap __factory_map;          ///< stores the FactoryObjects and registered default addeesses
  };
  
  typedef TSFactory::Singleton STSFactory;
  
}

#include "nmm/nmm_suffix.hpp"

#endif
