/* 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_INSTREAM_CHANNEL_HPP
#define NMM_INSTREAM_CHANNEL_HPP NMM_INSTREAM_CHANNEL_HPP

#include "nmm/nmm_prefix.hpp"

#include "CommunicationChannel.hpp"

#include "TSAddress.hpp"
#include "nmm/comm/serialize/SequenceValue.hpp"
#include "nmm/comm/messaging/Message.hpp"

#include "visibility.hpp"

namespace NMM {
  
  class ITransportStrategy;
  class IInstreamCompositeStrategy;
  class IJack;
  class IInputJack;
  class IOutputJack;
  class Interface;
  
  /** This %CommunicationChannel represents the connection between two Jacks.
   * An instream communication channel represents the connection between an %InputJack and an %OutputJack.
   * Both jacks must have the same %Format for instream buffers. The channel determines and manages a set of
   * suitable transport strategies and their interfaces. The interfaces of a %TransportStrategy may be
   * limited by the channel (for example if the strategy doesn't support the format of the jacks, it can not
   * be used for instream buffer communication).
   *
   * The configuration of an instream channel is a vector of selected transport strategies and their mapping to
   * four communication roles: downstream buffers, downstream events, upstream buffers and upstream events.
   *
   * @todo Access to interfaces of TransportStrategies
   * @todo Setting the ValueStream
   */
  class DLLEXPORT InstreamChannel :
    public CommunicationChannel
  {
  public:
    /** Communication roles for sub-bindings.
     */
    enum CommunicationRole {
      DOWNSTREAM_BUFFER = 1,                                       ///< Role for downstream buffers.
      DOWNSTREAM_CEVENT = 2,                                       ///< Role for downstream events.
      UPSTREAM_BUFFER   = 4,                                       ///< Role for upstream buffers.
      UPSTREAM_CEVENT   = 8,                                       ///< Role for upstream events.
      
      DOWNSTREAM        = DOWNSTREAM_BUFFER | DOWNSTREAM_CEVENT,   ///< All downstream roles.
      UPSTREAM          = UPSTREAM_BUFFER   | UPSTREAM_CEVENT,     ///< All upstream roles.
      INSTREAM_BUFFER   = DOWNSTREAM_BUFFER | UPSTREAM_BUFFER,     ///< All %Buffer roles.
      INSTREAM_CEVENT   = DOWNSTREAM_CEVENT | UPSTREAM_CEVENT,     ///< All %CEvent roles.
      
      INSTREAM          = INSTREAM_BUFFER | INSTREAM_CEVENT        ///< All roles.
    };
    
  public:
    /** @name Constructor & Destructor
     */
    //@{
    /** Constructs an %InstreamChannel.
     */
    InstreamChannel();
    
    /** Constructs an %InstreamChannel which connects the given jacks.

     * @param input_jack The jack at the downstream side of the channel
     * @param output_jack The jack at the upstream side of the channel
     * @exception BindingException if the jacks can not be connected
     */
    InstreamChannel(IInputJack& input_jack, IOutputJack& output_jack)
      throw(const BindingException&);
    
    /** Copy constructor.
     *
     * @param ic InstreamChannel to copy
     */
    InstreamChannel(const InstreamChannel& ic);
    
    /** Virtual Copy constructor.
     *
     * @return pointer to copy of this InstreamChannel
     */
    virtual InstreamChannel* copy() const;
    
    /** Virtual destructor.
     */
    virtual ~InstreamChannel();
    //@}
    
    /** @name Configuration
     */
    //@{
    /** Returns a list of all TransportStrategies availble for the connection.
     */
    virtual list<string> getStrategyList() const;
    
    /** This method returns a list of all TransportStrategies with the given interfaces.
     *
     * Possible flags for interfaces are defined in class TSFactory.
     *
     * @param upstream_interfaces Requested interfaces at the upstream side.
     * @param downstream_interfaces Requested interfaces at the downstream side.
     * @return A list of suitable strategies
     */
    virtual list<string> getStrategyList(unsigned int upstream_interfaces, unsigned int downstream_interfaces) const;
    
    /** This method returns a list of all TransportStrategies which can be used for the given combination of roles.
     *
     * @param roles Requested roles
     * @return A list of suitable strategies
     */
    virtual list<string> getStrategyList(unsigned int roles) const;
    
    /**  Adds a %TransportStrategy to the configuration.
     *
     * This method adds a new %TransportStrategy to the configuration. No %TransportStrategy is actually created unless
     * the method @c establishBinding is called. The strategy will be used for all given roles simultaneously.
     * If the capabilities of the %TransportStrategy don't allow the given combination of roles, a %BindingException is thrown.
     * If any roles are unset when establishBinding is called, then this strategy may be reused for unset roles.
     *
     * @param strategy_type Type of %TransportStrategy to use
     * @param upstream_interfaces Interfaces at the upstream side
     * @param downstream_interfaces Interfaces at the downstream side
     * @exception BindingException if the configuration is invalid
     */
    virtual void addTransportStrategy(const string& strategy_type, unsigned int upstream_interfaces, unsigned int downstream_interfaces)
      throw(const BindingException&);
    
    /** Adds a %TransportStrategy to the configuration.
     *
     * This method adds a new %TransportStrategy to the configuration. No %TransportStrategy is actually created unless
     * the method @c establishBinding is called. The strategy will be used for all given roles simultaneously.
     * If the capabilities of the %TransportStrategy don't allow the given combination of roles, a %BindingException is thrown.
     * If any roles are unset when establishBinding is called, then this strategy may be reused for unset roles.
     *
     * @param strategy_type Type of %TransportStrategy to use
     * @param roles Combination of rules to use the strategy for
     * @exception BindingException if the configuration is invalid
     */
    virtual void addTransportStrategy(const string& strategy_type, unsigned int roles)
      throw(const BindingException&);

    /** Adds a %TransportStrategy to the configuration and disallow reuse.
     *
     * This method adds a new %TransportStrategy to the configuration. No %TransportStrategy is actually created unless
     * the method @c establishBinding is called. The strategy will be used for all given roles simultaneously.
     * If the capabilities of the %TransportStrategy don't allow the given combination of roles, a %BindingException is thrown.
     *
     * @param strategy_type Type of %TransportStrategy to use
     * @param upstream_interfaces Interfaces at the upstream side
     * @param downstream_interfaces Interfaces at the downstream side
     * @exception BindingException if the configuration is invalid
     */
    virtual void addExplicitTransportStrategy(const string& strategy_type, unsigned int upstream_interfaces, unsigned int downstream_interfaces)
      throw(const BindingException&);
    
    /** Adds a %TransportStrategy to the configuration and disallow reuse.
     *
     * This method adds a new %TransportStrategy to the configuration. No %TransportStrategy is actually created unless
     * the method @c establishBinding is called. The strategy will be used for all given roles simultaneously.
     * If the capabilities of the %TransportStrategy don't allow the given combination of roles, a %BindingException is thrown.
     *
     * @param strategy_type Type of %TransportStrategy to use
     * @param roles Combination of rules to use the strategy for
     * @exception BindingException if the configuration is invalid
     */
    virtual void addExplicitTransportStrategy(const string& strategy_type, unsigned int roles)
      throw(const BindingException&);
    
    /** Establishes the binding.
     *
     * This method must be called when the configuration of the channel is finished. After calling this method, no more strategies
     * may be added.
     *
     * If not all roles have been assigned a %TransportStrategy yet, then this method will complete the configuration automatically.
     * If any strategies have been added with addExplicitTransportStrategy, then this method will first try to use them for unset roles.
     * Otherwise default strategies will be added.
     * @exception BindingException if the binding could not be established
     */
    virtual void establishBinding() throw(const BindingException&);
    
    /** Unsets all transport strategies.
     *
     * This method destroys all transport strategies and resets the configuration.
     */
    virtual void unsetTransportStrategy();
    
    /** Sets the value stream by type.
     *
     * This method sets the type of %ValueStream for data
     * serialization.
     *
     * This method only sets the top-level value stream, which is
     * created by the factory from the value stream type.
     *
     * @param roles Combination of flags from %CommunicationRole specifying the communication roles to set the value stream for.
     * @param i_value_stream_type Type name of input value stream.
     * @param o_value_stream_type Type name of output value stream.
     * @exception BindingException if a %ValueStream of the specified type isn't available
     */
    virtual void setValueStream(unsigned int roles,
                                const string& i_value_stream_type,
                                const string& o_value_stream_type)
      throw(const BindingException&);
    
    /** Sets the value stream stack.
     *
     * This method sets a %ValueStream stack for data serialization.
     *
     * This method should be used for setting the complete value
     * stream stack, including all configuration parameters of all
     * stream objects.
     *
     * @param roles Combination of flags from %CommunicationRole specifying the communication roles to set the value stream for.
     * @param i_value_stream Type name of input value stream.
     * @param o_value_stream Type name of output value stream.
     */
    virtual void setValueStreamStack(unsigned int roles,
                                     const IValueStream* i_value_stream,
                                     const OValueStream* o_value_stream);
    //@}
    
    /** @name Access Communication Channel information
     */
    //@{
    /** Returns input jack interface.
     *
     * @return An interface to the input jack
     */
    IInputJack* getInputJack() const;

    /** Returns output jack interface.
     *
     * @return An interface to the output jack
     */
    IOutputJack* getOutputJack() const;
    
    /** Returns input jack %TransportStrategy.
     *
     * @return The %TransportStrategy which is connected to the input jack (may be 0 if jacks are local to each other)
     */
    IInstreamCompositeStrategy* getInputJackStrategy() const;
    
    /** Returns output jack %TransportStrategy.
     *
     * @return The %TransportStrategy which is connected to the output jack (may be 0 if jacks are local to each other)
     */
    IInstreamCompositeStrategy* getOutputJackStrategy() const;
    
    /** Returns input jack leaf %TransportStrategy.
     *
     * @param role Communication role
     * @return The %TransportStrategy which is connected to the input jack (may be 0 if jacks are local to each other)
     */
    ITransportStrategy* getInputJackStrategy(CommunicationRole role) const;
    
    /** Returns output jack leaf %TransportStrategy.
     *
     * @param role Communication role
     * @return The %TransportStrategy which is connected to the output jack (may be 0 if jacks are local to each other)
     */
    ITransportStrategy* getOutputJackStrategy(CommunicationRole role) const;
    //@}

    /** @name Access the TransportStrategy Interfaces
     */
    //@{
    /** Returns an interface to the top-level %TransportStrategy of the %InputJack.
     *
     * This template method returns a pointer to the Interface of type T or NULL if this interface
     * is not supported by this object. The interface is from the InputJack.
     * The use of this method is:
     * \code
     * CommunicationChannel channel;
     * const ITCPControl* i_tcp = channel.getInterface<ITCPControl>();
     * if (i_tcp)
     *   cout << "ITCPControl Interface supported" << endl;
     * else
     *   cout << "ITCPControl Interface not supported" << endl;
     * \endcode
     */
    template<class T>
    T* getDownstreamInterface();
    
    /** Returns an interface to the top-level %TransportStrategy of the %InputJack.
     *
     * This template method returns a pointer to the Interface of type T or NULL if this interface
     * is not supported by this object. The interface is from the InputJack.
     * The use of this method is:
     * \code
     * CommunicationChannel channel;
     * const ITCPControl* i_tcp = channel.getInterface<ITCPControl>();
     * if (i_tcp)
     *   cout << "ITCPControl Interface supported" << endl;
     * else
     *   cout << "ITCPControl Interface not supported" << endl;
     * \endcode
     */
    template<class T>
    const T* getDownstreamInterface() const;
    
    /** Returns an interface to the top-level %TransportStrategy of the %OutputJack.
     *
     * This template method returns a pointer to the Interface of type T or NULL if this interface
     * is not supported by this object. The interface is from the OutputJack.
     * The use of this method is:
     * \code
     * CommunicationChannel channel;
     * const ITCPControl* i_tcp = channel.getInterface<ITCPControl>();
     * if (i_tcp)
     *   cout << "ITCPControl Interface supported" << endl;
     * else
     *   cout << "ITCPControl Interface not supported" << endl;
     * \endcode
     */
    template<class T>
    T* getUpstreamInterface();
    
    /** Returns an interface to the top-level %TransportStrategy of the %OutputJack.
     *
     * This template method returns a pointer to the Interface of type T or NULL if this interface
     * is not supported by this object. The interface is from the OutputJack.
     * The use of this method is:
     * \code
     * CommunicationChannel channel;
     * const ITCPControl* i_tcp = channel.getInterface<ITCPControl>();
     * if (i_tcp)
     *   cout << "ITCPControl Interface supported" << endl;
     * else
     *   cout << "ITCPControl Interface not supported" << endl;
     * \endcode
     */
    template<class T>
    const T* getUpstreamInterface()   const;

    /** Returns an interface to the leaf %TransportStrategy of the %InputJack with the given communication role.
     *
     * This template method returns a pointer to the Interface of type T or NULL if this interface
     * is not supported by this object. The interface is from the InputJack.
     * The use of this method is:
     * \code
     * CommunicationChannel channel;
     * const ITCPControl* i_tcp = channel.getInterface<ITCPControl>();
     * if (i_tcp)
     *   cout << "ITCPControl Interface supported" << endl;
     * else
     *   cout << "ITCPControl Interface not supported" << endl;
     * \endcode
     */
    template<class T>
    T* getDownstreamInterface(CommunicationRole role);
    
    /** Returns an interface to the leaf %TransportStrategy of the %InputJack with the given communication role.
     *
     * This template method returns a pointer to the Interface of type T or NULL if this interface
     * is not supported by this object. The interface is from the InputJack.
     * The use of this method is:
     * \code
     * CommunicationChannel channel;
     * const ITCPControl* i_tcp = channel.getInterface<ITCPControl>();
     * if (i_tcp)
     *   cout << "ITCPControl Interface supported" << endl;
     * else
     *   cout << "ITCPControl Interface not supported" << endl;
     * \endcode
     */
    template<class T>
    const T* getDownstreamInterface(CommunicationRole role) const;
    
    /** Returns an interface to the leaf %TransportStrategy of the %OutputJack with the given communication role.
     *
     * This template method returns a pointer to the Interface of type T or NULL if this interface
     * is not supported by this object. The interface is from the OutputJack.
     * The use of this method is:
     * \code
     * CommunicationChannel channel;
     * const ITCPControl* i_tcp = channel.getInterface<ITCPControl>();
     * if (i_tcp)
     *   cout << "ITCPControl Interface supported" << endl;
     * else
     *   cout << "ITCPControl Interface not supported" << endl;
     * \endcode
     */
    template<class T>
    T* getUpstreamInterface(CommunicationRole role);
    
    /** Returns an interface to the leaf %TransportStrategy of the %OutputJack with the given communication role.
     *
     * This template method returns a pointer to the Interface of type T or NULL if this interface
     * is not supported by this object. The interface is from the OutputJack.
     * The use of this method is:
     * \code
     * CommunicationChannel channel;
     * const ITCPControl* i_tcp = channel.getInterface<ITCPControl>();
     * if (i_tcp)
     *   cout << "ITCPControl Interface supported" << endl;
     * else
     *   cout << "ITCPControl Interface not supported" << endl;
     * \endcode
     */
    template<class T>
    const T* getUpstreamInterface(CommunicationRole role)   const;
    
    /** This method returns a list of all Interfaces to the top-level TransportStrategy of the %InputJack.
     *
     * @return  a list of all Interfaces to the top-level TransportStrategy of the %InputJack
     */
    virtual list<Interface*>& getDownstreamInterfaceList();
    
    /** This method returns a list of all Interfaces to the top-level
     * TransportStrategy of the %OutputJack.
     */
    virtual list<Interface*>& getUpstreamInterfaceList();
    
    /** This method returns a list of all Interfaces to the leaf TransportStrategy of the %InputJack with the given communication role.
     *
     * @param role Communication role
     * @return list of all Interfaces to leaf TransportStrategy of %InputJack with given communication role
     */
    virtual list<Interface*>& getDownstreamInterfaceList(CommunicationRole role);
    
    /** This method returns a list of all Interfaces to the leaf TransportStrategy of the %OutputJack with the given communication role.
     *
     * @param role Communication role
     * @return a list of all Interfaces to leaf TransportStrategy of %OutputJack with given communication role
     */
    virtual list<Interface*>& getUpstreamInterfaceList(CommunicationRole role);
    //@}
    
  protected:
    /** Updates attributes after serialization.
     */
    virtual void updateAttributes();
    
  private:
    /** Creates list of strategies..
     *
     * This method is called whenever the strategy list is requested and has not been created yet.
     */
    void createStrategyList() const;
    
    /** This method registers all strategies with the given binding type.
     *
     * @param binding_type BindingType of strategies to register
     */
    void registerStrategyType(TSAddress::BindingType binding_type) const;
    
    /** This method registers all strategies with the given binding type.
     *
     * This method registers all strategies with the given binding
     * type using the given list of default addresses for one endpoint
     * and supported strategies for the other endpoint. The message
     * direction is given to determine the interface names.
     *
     * @param binding_type BindingType of strategies to register
     * @param address_list list of default addresses for one endpoint
     * @param strategy_list supported strategies for the other endpoint
     * @param direction message direction
     */
    void registerStrategyType(TSAddress::BindingType binding_type, const SequenceValue<TSAddress>& address_list,
                              const list<TSDescription>& strategy_list, Message::Direction direction) const;
    
    /** This method registers a strategy defined by the given strategy descriptions for upstream and downstream endpoints. 
     *
     * If and only if matching instream interface pairs are found, and these
     * interfaces are usable for instream communication, then the
     * strategy is considered usable and added to the strategy list.
     *
     * @param upstream_description upstream strategy description
     * @param downstream_description  downstream strategy description
     */
    void registerStrategy(const TSDescription& upstream_description, const TSDescription& downstream_description) const;
    
    /** Register all attributes of this class for serialization/deserialization.
     */
    void registerAttributes();
    
    /** Tries to reuse an already added strategy with the given interfaces.
     *
     * This method is used by automatic binding configuration to find an already added %TransportStrategy which
     * supports at least the given interfaces. If a strategy is found, it is added to the configuration.
     *
     * @param upstram_interfaces upstream interfaces
     * @param downstream_interfaces downstream interfaces
     * @return @c true if a suitable strategy was found, otherwise @c false
     */
    bool tryReuseStrategy(unsigned int upstream_interfaces, unsigned int downstream_interfaces);
    
    /** Tries to find a suitable strategy with the given interfaces.
     *
     * This method us used by automatic binding configuration to find a new %TransportStrategy which
     * supports at least the given interfaces. If a strategy is found, it is added to the configuration.
     *
     * @param upstream_interfaces upstream interfaces
     * @param downstream_interfaces downstream interfaces
     * @return @c true if a suitable strategy was found, otherwise @c false
     */
    bool findSuitableStrategy(unsigned int upstream_interfaces, unsigned int downstream_interfaces);
    
    /** Returns the interfaces that a transport strategy pair must support to fulfill the given roles.
     *
     * @param roles Roles that must be fulfilled
     * @param upstream_interfaces Returns the set up interfaces on the upstream side
     * @param downstream_interfaces Returns the set up interfaces on the downstream side
     */
    static void getRequiredInterfaces(unsigned int roles, unsigned int& upstream_interfaces, unsigned int& downstream_interfaces);
    
    /** Internal method for adding a transport strategy.
     *
     * @param strategy_type strategy type
     * @param upstream_interfaces upstream interfaces 
     * @param downstream_interfaces downstream interfaces
     * @param is_explicit true if strategy can be reused, false otherwise
     */
    void addTransportStrategyInternal(const string& strategy_type, unsigned int upstream_interfaces, unsigned int downstream_interfaces,
                                      bool is_explicit)
      throw(const BindingException&);
    
    /** Tries to connect two jacks using the configuration of this communication channel.  
     *
     * The given message direction specifies
     * the endpoint which actively initiates the connection.  I.e. the
     * direction is @c DOWNSTREAM if the input jack connects to the
     * output jack, and vice versa.
     *
     * @param jack1 first jack
     * @param jack2 second jack 
     * @param direction specifies the endpoint which actively initiates the connection
     */
    void tryConnectJacks(IJack* jack1, IJack* jack2, Message::Direction direction)
      throw(const BindingException&);
    
    /** Sets value stream for a single communication role.
     *
     * @param role CommuncationRole to specify value stream for
     * @param i_value_stream_type input value stream 
     * @param o_value_stream_type output value stream 
     */
    void setValueStreamInternal(CommunicationRole role,
                                const string& i_value_stream_type,
                                const string& o_value_stream_type)
      throw(const BindingException&);
    
    /** Sets value stream for a single communication role.
     *
     * @param role CommuncationRole to specify value stream for
     * @param i_value_stream input value stream
     * @param o_value_stream output value stream
     */
    void setValueStreamStackInternal(CommunicationRole role,
                                     const IValueStream* i_value_stream,
                                     const OValueStream* o_value_stream);
    
    /** Converts communication role to string.
     *
     * @param role CommunicationRole to convert
     * @return string representation of given CommunicationRole
     */
    static string getRoleName(CommunicationRole role);
    
    /** Converts combination of communication roles to string.
     *
     * @param roles combination of CommunicationRoles to convert
     * @return string representation of given combination of CommunicationRoles
     */
    static string getRoleString(int roles);
    
    /** Converts interface to string.
     *
     * @param iface Interfaces to convert
     * @return string representation of given Interfaces
     */
    static string getInterfaceName(TSDescription::Interfaces iface);
    
    /** Converts combination of interfaces to string.
     *
     * @param interfaces combination of interfaces to convert
     * @return string representation of given combination of interfaces
     */
    static string getInterfaceString(int interfaces);
    
  private:
    /** @name Jack Interfaces
     */
    //@{
    TValue<IInputJack*>            __input_jack;              ///< Interface to the %InputJack
    TValue<IOutputJack*>           __output_jack;             ///< Interface to the %OutputJack
    //@}
    
    /** @name Transport Strategy interfaces (cached)
     */
    mutable IInstreamCompositeStrategy* __input_jack_strategy;     ///< Interface to the %InputJack's %TransportStrategy
    mutable IInstreamCompositeStrategy* __output_jack_strategy;    ///< Interface to the %OutputJack's %TransportStrategy
    mutable bool                        __in_strategy_valid;       ///< Is true if the %InputJack's %TransportStrategy interface is valid
    mutable bool                        __out_strategy_valid;      ///< Is true if the %OutputJack's %TransportStrategy interface is valid
    mutable ITransportStrategy* __input_jack_child_strategy[4];    ///< Interface to the %InputJack's %TransportStrategy
    mutable ITransportStrategy* __output_jack_child_strategy[4];   ///< Interface to the %OutputJack's %TransportStrategy
    mutable bool                __in_child_strategy_valid[4];      ///< Is true if the %InputJack's %TransportStrategy interface is valid
    mutable bool                __out_child_strategy_valid[4];     ///< Is true if the %OutputJack's %TransportStrategy interface is valid
    //@}
    
    /** @name Configuration
     */
    //@{
    /** A matching pair of transport strategies that can be used.
     */
    struct StrategyListEntry {
      string strategy_type;                             ///< Type name of TransportStrategy.
      bool is_explicit;                                 ///< Transport strategy is explicit.
      unsigned int capabilities;                        ///< Capabilities of TransportStrategy.
      unsigned int upstream_interfaces;                 ///< Interfaces on the upstream side.
      unsigned int downstream_interfaces;               ///< Interfaces on the downstream side.
      unsigned int used_upstream_interfaces;            ///< Used interfaces on the upstream side.
      unsigned int used_downstream_interfaces;          ///< Used interfaces on the downstream side.
      
      StrategyListEntry() throw()
        : strategy_type(),
          is_explicit(false),
          capabilities(0),
          upstream_interfaces(0),
          downstream_interfaces(0),
          used_upstream_interfaces(0),
          used_downstream_interfaces(0)
      {}
      
      /** Tests if given StrategyListEntry is equal to this one.
       *
       * @param other StrategyListEntry to compare with this one
       * @return true if StrategyListEntries are equal, false otherwise
       */
      bool operator==(const StrategyListEntry& other) const {
        return strategy_type == other.strategy_type &&
          capabilities == other.capabilities &&
          upstream_interfaces == other.upstream_interfaces &&
          downstream_interfaces == other.downstream_interfaces;
      }
    };
    
    typedef list<StrategyListEntry>       StrategyList; 
    typedef StrategyList::iterator        StrategyIterator;
    typedef StrategyList::const_iterator  StrategyConstIterator;
    
    mutable StrategyList           __strategy_list;           ///< List of available strategies and their capabilities
    mutable bool                   __strategy_list_valid;     ///< Is true if the strategy list is valid
    
    vector<StrategyListEntry>      __strategies;              ///< Selected transport strategies
    //@}
    
  public:
    /** This method returns the TypeInfo for this class.
     */
    static TypeInfo getStaticTypeInfo();
  };
  
  typedef auto_ptr<InstreamChannel> InstreamChannel_var;
  
  template <typename T>
  T* InstreamChannel::getDownstreamInterface() {
    T* iface = 0;
    for (list<Interface*>::iterator it = getDownstreamInterfaceList().begin(); it != getDownstreamInterfaceList().end(); ++it)
      {
        iface = dynamic_cast<T*>(*it);
        if (iface != 0)
          return dynamic_cast<T* >(iface->copy());
      }
    return 0;
  }
  
  template <typename T>
  const T* InstreamChannel::getDownstreamInterface() const {
    const T* iface = 0;
    for (list<Interface*>::const_iterator it = getDownstreamInterfaceList().begin(); it != getDownstreamInterfaceList().end(); ++it)
      {
        iface = dynamic_cast<const T*>(*it);
        if (iface != 0)
          return dynamic_cast<T* >(iface->copy());
      }
    return 0;
  }
  
  template <typename T>
  T* InstreamChannel::getUpstreamInterface() {
    T* iface = 0;
    for (list<Interface*>::iterator it = getUpstreamInterfaceList().begin(); it != getUpstreamInterfaceList().end(); ++it)
      {
        iface = dynamic_cast<T*>(*it);
        if (iface != 0)
          return dynamic_cast<T* >(iface->copy());
      }
    return 0;
  }
  
  template <typename T>
  const T* InstreamChannel::getUpstreamInterface() const {
    const T* iface = 0;
    for (list<Interface*>::const_iterator it = getUpstreamInterfaceList().begin(); it != getUpstreamInterfaceList().end(); ++it)
      {
        iface = dynamic_cast<const T*>(*it);
        if (iface != 0)
          return dynamic_cast<T* >(iface->copy());
      }
    return 0;
  }

  template <typename T>
  T* InstreamChannel::getDownstreamInterface(CommunicationRole role) {
    T* iface = 0;
    for (list<Interface*>::iterator it = getDownstreamInterfaceList(role).begin(); it != getDownstreamInterfaceList(role).end(); ++it)
      {
        iface = dynamic_cast<T*>(*it);
        if (iface != 0)
          return dynamic_cast<T* >(iface->copy());
      }
    return 0;
  }
  
  template <typename T>
  const T* InstreamChannel::getDownstreamInterface(CommunicationRole role) const {
    const T* iface = 0;
    for (list<Interface*>::const_iterator it = getDownstreamInterfaceList(role).begin(); it != getDownstreamInterfaceList(role).end(); ++it)
      {
        iface = dynamic_cast<const T*>(*it);
        if (iface != 0)
          return dynamic_cast<T* >(iface->copy());
      }
    return 0;
  }
  
  template <typename T>
  T* InstreamChannel::getUpstreamInterface(CommunicationRole role) {
    T* iface = 0;
    for (list<Interface*>::iterator it = getUpstreamInterfaceList(role).begin(); it != getUpstreamInterfaceList(role).end(); ++it)
      {
        iface = dynamic_cast<T*>(*it);
        if (iface != 0)
          return dynamic_cast<T* >(iface->copy());
      }
    return 0;
  }
  
  template <typename T>
  const T* InstreamChannel::getUpstreamInterface(CommunicationRole role) const {
    const T* iface = 0;
    for (list<Interface*>::const_iterator it = getUpstreamInterfaceList(role).begin(); it != getUpstreamInterfaceList(role).end(); ++it)
      {
        iface = dynamic_cast<const T*>(*it);
        if (iface != 0)
          return dynamic_cast<T* >(iface->copy());
      }
    return 0;
  }
  
}

#include "nmm/nmm_suffix.hpp"

#endif
