/* 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_CONNECTION_MANAGER_HPP
#define NMM_CONNECTION_MANAGER_HPP NMM_CONNECTION_MANAGER_HPP

#include "nmm/nmm_prefix.hpp"

#include "IConnectionManagerImpl.hpp"
#include "TSAddress.hpp"

#include "nmm/utils/NamedObject.hpp"

#include "visibility.hpp"

namespace NMM {
  
  class FormatStrategyMap;
  class ConnectorAddress;
  
  /** Connection Manager is responsible for setting up connections for transport strategies.
   *
   *  The %ConnectionManager is responsible for setting up connections
   *  for transport strategies that can't connect to an Acceptor. The
   *  actual work is done by %ConnectorAcceptor objects that register
   *  themselves at the %ConnectionManager.
   */
  class DLLEXPORT ConnectionManager :
    public NamedObject,
    public IConnectionManagerImpl
  {
    DECLARE_SINGLETON(ConnectionManager, CreateUsingNew, DefaultLifetime, MultiThreaded);
    friend class CreateUsingNew<ConnectionManager>;
  public:
    /**
     *  @name Constructor & Destructor
     */
    //@{
    /** Virtual destructor.
     */
    virtual ~ConnectionManager();
    //@}
    
    /**
     *  @name Methods from NMMObject
     */
    //@{
    /** Returns default address.
     *
     *  As a special exception, the %ConnectionManager must not have a %ConnectorAddress.
     *  This limitation is necessary to prevent cyclic %TSAddress structures.
     *
     * @param strategy_type type of strategy
     * @return default address
     */
    virtual TSAddress* getDefaultAddress(const string& strategy_type) const;
    //@}
    
    /**
     *  @name IConnectionManager interface
     */
    //@{
    /** Handles a connection request from a remote host.
     *
     *  This method checks if a %ConnectorAcceptor object exists for the requested transport strategy type
     *  and forwards the request to this Connector.
     *
     *  @param remote_addr Fully specified address of the remote transport strategy
     *  @param local_addr Returns the fully specified address of the local transport strategy
     *  @exception BindingException if no %ConnectorAcceptor was found or the %ConenctorAcceptor throws a BindingException
     */
    virtual void handleConnect(const TSAddress* remote_addr, TSAddress*& local_addr) const 
      throw(const BindingException&);
    
    /** Reliably send event to partner object.
     *
     *  This method is used to reliably send a configuration event to a partner object via the %ConnectionManager.
     *  The connection manager pretends that the event was sent via the transport strategy.
     *
     *  @param receiver NMM reference of transport strategy which should receive the event
     *  @param e The event
     *  @return The result of the event
     */
    virtual Result sendReliableEvent(const NMMReference& receiver, Event& e) const
      throw(const BindingException&);
    
    /** Reliably send event to partner strategy.
     *
     *  This method is used to reliably send a configuration event to a partner strategy via the %ConnectionManager.
     *
     *  @param receiver NMM Reference of transport strategy which should receive the event
     *  @param e The event
     *  @return The result of the event
     */
    virtual Result sendReliableConfigEvent(const NMMReference& receiver, Event& e) const
      throw(const BindingException&);
    
    /** Reliably send instream message to partner object.
     *
     *  This method is used to reliably send an instream to a partner object via the ConnectionManager.
     *  The connection manager pretends that the message was sent via the transport strategy.
     *
     *  This method is only for debugging and should not be used.
     *
     *  @param receiver NMM Reference of transport strategy which should receive the event
     *  @param message The message
     *  @return The result of the event
     */
    virtual Result sendReliableInstreamMessage(const NMMReference& receiver, CEvent& message) const
      throw(const BindingException&);
    
    /** Returns strategies that support format.
     *
     *  This method returns the list of transport strategies that support the given format.
     *
     *  @param format Format to check
     *  @return List of transport strategies that support the format
     */
    virtual list<TSDescription> getSupportedStrategies(const Format& format) const;
    //@}
    
    /**
     *  @name Local interface
     */
    //@{
    /** Requests a connection.
     *
     *  This method requests a connection to the remote connection manager given by @c remote_icm. The
     *  request is sent by the %ConnectorAcceptor object which is locally registered for the trasport
     *  strategy type of @c local_addr. A corresponding %ConnectorAcceptor at the remote connection manager
     *  handles the request. If no %ConnectorAcceptor is registered at the local or remote %ConnectionManager
     *  or the connection request fails for some reason, a %BindingException is thrown.
     *
     *  The caller must provide a fully specified address in @c local_addr that can be used by the remote host
     *  to configure its transport strategy. The remote host returns the fully specified address of the partner
     *  transport strategy in @c remote_addr if the connection request was successful.
     *
     *  @param local_addr Fully specified address of the local transport strategy
     *  @param remote_addr Returns the fully specified address of the remote transport strategy
     *  @param remote_icm Interface to remote connection manager
     *  @exception BindingException if the connection could not be set up
     */
    void connect(const ConnectorAddress* local_addr, ConnectorAddress*& remote_addr, IConnectionManager* remote_icm) const
      throw(const BindingException&);
    
    /** Requests connection manager interface.
     *
     *  This method requests an interface of a connection manager.
     *  To identify the host, an interface from an object on the host is used.
     *  The interface must contain a %ConnectorAddress.
     *
     *  @param iface Interface to object on host
     *  @return Connection manager interface, if available, otherwise @a NULL
     *  @exception BindingException if the request fails
     */
    IConnectionManager* getConnectionManager(const Interface& iface) const
      throw(const BindingException&);    
    //@}
    
    /** @name Configuration
     */
    //@{
    /** Returns default strategy.
     *
     * This method returns the default transport strategy type for the given type of connection.
     * The type of connection is the type of communication channel and the binding type.
     *
     * @param channel_type Type of communication channel
     * @param binding_type Binding type
     */
    string getDefaultStrategy(const TypeInfo& channel_type, TSAddress::BindingType binding_type) const;
    
    /** Sets default strategy.
     *
     * This method sets the default transport strategy type for the given type of connection.
     * The type of connection is the type of communication channel and the binding type.
     *
     * @param channel_type Type of communication channel
     * @param binding_type Binding type
     & @param strategy_type Strategy type
     */
    void setDefaultStrategy(const TypeInfo& channel_type, TSAddress::BindingType binding_type,
                            const string& strategy_type);
    
    /** Returns format strategy map.
     *
     * This method returns the format strategy map of this connection manager.
     */
    inline const FormatStrategyMap& getFormatStrategyMap() const { return *__format_strategy_map; }

    /** Returns format strategy map.
     *
     * This method returns the format strategy map of this connection manager.
     */
    inline       FormatStrategyMap& getFormatStrategyMap()       { return *__format_strategy_map; }
    //@}
    
    /** @name Helpers
     */
    //@{
    /** Requests service.
     *
     * This method requests an interface of a service. It opens a new connection to the
     * host using the given address and requests the service from the reference manager.
     *
     * @param address Address to use to connect to host
     * @param service name of service
     * @return Interface of requested service
     * @exception BindingException if the request failed
     */
    Interface* getService(const TSAddress& address, const string& service) const
      throw(const BindingException&);

    /** Requests service.
     *
     * This method requests an interface of a service. It opens a new connection to the
     * host using the addresses given in the interface and requests the service from the reference manager.
     *
     * @param iface Interface providing addresses of the host
     * @param service name of service
     * @return Interface of requested service
     * @exception BindingException if the request failed
     */
    Interface* getService(const Interface& iface, const string& service) const
      throw(const BindingException&);
    //@}
    
  private:
    /** @name Constructor & Destructor
     */
    //@{
    /** Default constructor.
     */
    ConnectionManager();
    //@}
    
  private:
    typedef pair<TypeInfo, TSAddress::BindingType> ConnectionType;
    typedef map<ConnectionType, string>            StrategyMap;
    typedef StrategyMap::iterator                  StrategyIterator;
    typedef StrategyMap::const_iterator            StrategyConstIterator;
    StrategyMap  __strategy_map;                                            ///< Default strategy map
    
    FormatStrategyMap* __format_strategy_map; ///< store which format are supported by which TransportStrategy
  };
  
  /** Connection manager singleton.
   */
  typedef ConnectionManager::Singleton SConnectionManager;
}

#include "nmm/nmm_suffix.hpp"

#endif
