/* 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_T_TS_FACTORY_REGISTRATOR_HPP
#define NMM_T_TS_FACTORY_REGISTRATOR_HPP NMM_T_TS_FACTORY_REGISTRATOR_HPP

#include "nmm/nmm_prefix.hpp"

#include "TSFactory.hpp"
#include "DefaultTSFormatList.hpp"
#include "LocalAddress.hpp"

#include "visibility.hpp"

namespace NMM {
  
  class TSFormatList;
  class ConnectorAcceptor;
  
  /** Empty base class for TTSFactoryRegistrator.
   *
   * This class is needed for creating static constructor lists which
   * are needed for linking against static constructors when building
   * static libraries.
   *
   * @see TTSFactoryRegistrator
   */
  class DLLEXPORT TSFactoryRegistrator {
  public:

    /** Default Destructor.
     */
    virtual ~TSFactoryRegistrator() {}

    /** Dummy method.
     */
    virtual void dummy() {}
  };
  
  /** Transport strategy registration object.
   *
   * This object is a wrapper for an instance of a subclass of
   * TSFactoryObject. It is responsible for construction,
   * registration, deregistration and destruction of the
   * TSFactoryObject.  Using this wrapper, we make sure that
   * registered objects are always fully constructed.
   */
  template<class T>
  class TTSFactoryRegistrator : public TSFactoryRegistrator {
  public:
    /** @name Constructor & Destructor
     */
    //@{
    /** Constructor.
     *
     * @param strategy_type Typename of strategy
     * @param interfaces Interface flags of this %TransportStrategy
     * @param capabilities Capabilities of this %TransportStrategy
     * @param format_list List of supported formats
     */
    TTSFactoryRegistrator(const std::string& strategy_type, unsigned int interfaces, unsigned int capabilities,
                          const TSFormatList& format_list = DefaultTSFormatList());
    
    /** Constructor.
     *
     * @param strategy_type Typename of strategy
     * @param connector_acceptor %ConnectorAcceptor to register with this strategy. Must be allocated with @c new
     * @param interfaces Interface flags of this %TransportStrategy
     * @param capabilities Capabilities of this %TransportStrategy
     * @param format_list List of supported formats
     */
    TTSFactoryRegistrator(const std::string& strategy_type, ConnectorAcceptor* connector_acceptor,
                          unsigned int interfaces, unsigned int capabilities,
                          const TSFormatList& format_list = DefaultTSFormatList());
    
    /** Destructor.
     */
    ~TTSFactoryRegistrator();
    //@}

  private:
    /** Registers TSFactoryObject at TSFactory.
     *
     * @param strategy_type type of TransportStrategy
     * @param interfaces Interfaces of this transport strategy
     * @param capabilities Capabilities of this transport strategy
     * @param format_list List of supported formats
    */
    void registerTSFactoryObject(const std::string& strategy_type, unsigned int interfaces, unsigned int capabilities, const TSFormatList& format_list);
    
  private:
    std::string __strategy_type;       ///< Strategy typename
    unsigned int __interfaces;
    unsigned int __capabilities;
    T __factory_object;           ///< Wrapped factory object
  };
  
  template<class T>
  void TTSFactoryRegistrator<T>::registerTSFactoryObject(const std::string& strategy_type,
                                                         unsigned int interfaces, unsigned int capabilities, const TSFormatList& format_list)
  {
    /* Register the transport strategy */
    STSFactory::getInstance().registerStrategy(__factory_object, strategy_type, interfaces, format_list.getFormatList(), capabilities);
    
    if (strategy_type == "LocalStrategy") {
      /* Add default LocalAddress for LocalStrategy */
      STSFactory::getInstance().setDefaultAddress("LocalStrategy", new LocalAddress());
    }
    if (!(capabilities & TSDescription::TS_RELIABLE_CONNECT)) {
      /* Add default ConnectorAddress for strategy without reliable connection setup */
      STSFactory::getInstance().addConnectorAddress(strategy_type);
    }
  }
  
  template<class T>
  TTSFactoryRegistrator<T>::TTSFactoryRegistrator(const std::string& strategy_type, unsigned int interfaces, unsigned int capabilities, 
                                                  const TSFormatList& format_list /*= DefaultTSFormatList()*/)
    : __strategy_type(strategy_type),
      __interfaces(interfaces),
      __capabilities(capabilities),
      __factory_object()
  {
    registerTSFactoryObject(strategy_type, interfaces, capabilities, format_list);
  }
  
  template<class T>
  TTSFactoryRegistrator<T>::TTSFactoryRegistrator(const std::string& strategy_type, ConnectorAcceptor* connector_acceptor,
                                                  unsigned int interfaces, unsigned int capabilities,
                                                  const TSFormatList& format_list /*= DefaultTSFormatList()*/)
    : __strategy_type(strategy_type),
      __interfaces(interfaces),
      __capabilities(capabilities),
      __factory_object(connector_acceptor)
  {
    registerTSFactoryObject(strategy_type, interfaces, capabilities, format_list);
  }
  
  template<class T>
  TTSFactoryRegistrator<T>::~TTSFactoryRegistrator() {
    STSFactory::getInstance().unregisterStrategy(__strategy_type, __interfaces, __capabilities);
  }
  
}

#include "nmm/nmm_suffix.hpp"

#endif
