/* 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_CLIENTREGISTRY_HPP
#define NMM_CLIENTREGISTRY_HPP

#include "nmm/nmm_prefix.hpp"

#include "Response.hpp"
#include "RegistryException.hpp"
#include "RegistryID.hpp"

#include "nmm/utils/NamedObject.hpp"
#include "nmm/utils/thread/ThreadedObject.hpp"
#include "nmm/utils/thread/ThreadCondition.hpp"
#include "nmm/utils/thread/ThreadMutex.hpp"
#include "nmm/utils/time/Time.hpp"
#include "nmm/comm/netstrategy/UDPBroadcaster.hpp"
#include "nmm/comm/messaging/IEventReceiver.hpp"
#include "nmm/comm/messaging/TEDObject.hpp"
#include "IServerRegistry.hpp"

#include "IPluginManager.hpp"
#include "visibility.hpp"

namespace NMM {
class IServerRegistry;
class ISourceSynchronizer;
class ISinkSynchronizer;
class ISession;
class INode;
class Node;
class NodeDescription;
class NodeFactory;
class GraphDescription;
class ProxyObject;
class ObjectDescription;
class Interval;

typedef pair<string, int> RegistryName;
typedef map<RegistryName, list<Response> > ResponseMap;

 /** \class ClientRegistry
  * The ClientRegistry allows an application to access several ServerRegistries and to request, reserve and release Nodes.
  * It performs some optimization if a node is requested from a so called local ServerRegistry running on the same machine 
  * but in a different address space as the application. For example, if a node is requested from a local ServerRegistry, 
  * the ClientRegistry reserves only the corresponding node by the local ServerRegistry and allocates the
  * Node in its own address space to avoid interprocess communication between the application and the node.
  *
  */
class DLLEXPORT ClientRegistry : public NamedObject, public ThreadedObject {
  struct ReservationStruct;

public:
  struct RegistryStruct;
  struct ISessionStruct;


/** @name Constructor & Destructor
  */
//@{
/** Constructor.
  */
  ClientRegistry();

/** Destructor.
  */
  virtual ~ClientRegistry();
//@} 

/** @name Request & Release methods
  */
//@{
/** 
  * These methods allows an application to serach Nodes in ServerRegistries.
  * 
  */
//@{
 /** Searches for Nodes with specified requirements.  
  *
  * This method searches all known ServerRegistries for Nodes that match the 
  * requirements specified in the given NodeDescription.
  *
  * @param nd specifies the properties of a required Node.
  * @return list of Response objects. A response object includes all information to request a Node. 
  */
  virtual  list< Response >  initRequest(const NodeDescription& nd);

 /**  Searches for Nodes with specified requirements on specified host.  
  *
  * This method searches all ServerRegistries on a specific host for Nodes that match and returns the fastest host in hostname.
  *
  * @param nd specifies the properties of a required Node.
  * @param hostname name of the host whose ServerRegistries
  * @return list of Response objects. A response object includes all information to request a Node. 
  */
  virtual  list< Response >  initDistributedRequest(const NodeDescription& nd, string& hostname);

 /** This method searches specific ServerRegistries for Nodes with specific requirements.
  *
  * The requirements are specified in a NodeDescrtiption that is send as first argument.
  * 
  * @param nd NodeDescription with the Node's requirements
  * @param registry_list list with the name of ServerRegistries that should process the request
  * @return an stl map including the list of Response objects from each ServerRegistry specified by the RegistryName 
  */
  map<RegistryName, list<Response> > initRequest(const NodeDescription& nd, const list<RegistryName>& registry_list);
//@}

/** @name Request & Release methods
  */
//@{
 /** This method tries to request one of the nodes in the Response object.
  *
  * The response object contains a list with ObjectID's. This method starts to request the first Node in
  * this list. If this request fails this method tries to request another node in this list in the list's
  * order. If a request is successfully it returns an INode, otherwise a exception is thrown
  * @param resp The response object with list of ObjectID's.
  * @param nd pointer to NodeDescription. If the pointer is not NULL, the given NodeDescription is updated to the 
  *           NodeDescription of the allocated Node. 
  * @return pointer to the INode of the requested Node. The caller of this method is responsible to delete the returned INode.
  */
  virtual INode* requestNode(const Response& resp, NodeDescription* nd = 0)
          throw (const RegistryException& );

 /** This method tries to request one of the nodes in the list of Response objects.
  *
  * This method starts to request a Node by using the first Response object of the list. If this request fails this method 
  * tries to request another node using the successing Response object. If a request is successfully it returns an INode, 
  * otherwise an exception is thrown.
  * 
  * @param resp The response object with list of ObjectID's.
  * @param nd pointer to NodeDescription. If the pointer is not NULL, the given NodeDescription is updated to the 
  *           NodeDescription of the allocated Node. 
  * @return pointer to the INode of the requested Node. The caller of this method is responsible to delete the returned INode.
  */
  virtual INode* requestNode(const list<Response>& resp, NodeDescription* nd = 0)
          throw (const RegistryException& );

 /** This method tries to request a Node from a specific registry. 
  *
  * If the request was successfully it returns an INode, 
  * otherwise an exception is thrown
  *
  * @param reg_id The RegistryID of the registry that maintains the Node
  * @param node_id The node's ObjectID which specifies the Node 
  * @return pointer to the INode of the requested Node. The caller of this method is responsible to delete the returned INode.
  */
  virtual INode* requestNode(const RegistryID& reg_id, const ObjectID& node_id, NodeDescription* = 0)
          throw (const RegistryException& );

 /** Releases a requested node.
  *
  * @param i_node interface of the Node that should be released. 
  */
  virtual void releaseNode(INode& i_node);

 /** Requests an NMMObject from a given ObjectDescription.
  *
  * @param od specifies the NMMObject that should be allocated. 
  * @return pointer to the Interface of the the NMMObject. The caller of this method is responsible to delete the returned Interface.
  */
  virtual Interface* requestNMMObject(const ObjectDescription& od);

 /** Releases a requested NMMObject.
  *
  * @param _interface reference to the Interface of the NMMObject that should be released.
  */
  virtual void releaseNMMObject(const Interface& _interface);

  /** Request a sink synchronizer.
   *
   * This method requests a sink synchronizer of the default sink synchronizer class.
   * It returns an interface to the created synchronizer. The caller is responsible for
   * releasing the synchronizer by calling releaseNMMObject().
   *
   * The sink synchronizer is created in the local address space and is of the default
   * synchronizer class.
   *
   * This is a convenience method which invokes requestNMMObject with a properly set up
   * object description.
   *
   * @return An interface to a sink synchronizer
   * @exception RegistryException if the synchronizer could not be created
   */
  virtual ISinkSynchronizer* requestSinkSynchronizer();

  /** Request a sink synchronizer.
   *
   * This method requests a sink synchronizer.
   * It returns an interface to the created synchronizer. The caller is responsible for
   * releasing the synchronizer by calling releaseNMMObject().
   *
   * By default, the sink synchronizer is created in the local address space and is of
   * the default synchronizer class. This can be changed by setting the object name or
   * the location attribute of the object description.
   *
   * This is a convenience method which invokes requestNMMObject with a properly set up
   * object description.
   *
   * @param desc An objct description that describes the synchronizer
   * @return An interface to a sink synchronizer
   * @exception RegistryException if the synchronizer could not be created
   */
  virtual ISinkSynchronizer* requestSinkSynchronizer(const ObjectDescription& desc);
//@}

 /** @name access control methods
  */
//@{
 /** This method enables the access-control to all ServerRegistries that can be accessed through this
  * ClientRegistry. If the access-control is enabled no other application can access these
  * ServerRegistries. If this method fails, an exception is thrown. 
  */
  virtual void initTransaction()
    throw (const RegistryException&);

 /** This method disables the access-control.
  */
  virtual void releaseTransaction();
//@}

 /** @name get and add ServerRegistries
  */
//@{
 /** This method retuns a map with all ServerRegistries that can be accessed through this ClientRegistry.
  *
  * @return  map with all ServerRegistries that can be accessed through this ClientRegistry
  */
  const map<RegistryName, RegistryStruct>& getRegistryList()     const { return __named_registry; }

 /** This method retuns a map with all ServerRegistries that can be accessed through this ClientRegistry.
  *
  * @return  map with all ServerRegistries that can be accessed through this ClientRegistry
  */
  map<RegistryName, RegistryStruct>& getRegistryList()                 { return __named_registry; }

 /** This method returns an interface to a ServerRegistry located on given host. 
  *
  * The interface is managed by the ClientRegistry. So the caller of this method must not delete it.
  *
  * @param registry_name name of the registry 
  * @return Interface to the ServerRegistry with given name, or NULL pointer if the corresponding ServerRegistry is not available
  */
  IServerRegistry* getServerRegistry(const RegistryName& registry_name);

 /** This method returns an interface to a server registry located on given host. 
  *
  * The interface is managed by the ClientRegistry. So the caller of this method must not delete it.
  *
  * @param registry_name name of the registry 
  * @return Interface to the ServerRegistry with given name, or NULL pointer if the corresponding ServerRegistry is not available
  */
  const IServerRegistry* getServerRegistry(const RegistryName& registry_name) const ;

 /** This method returns the RegistryName, which is the hostname and port of a ServerRegistry, that manages the object
  * of an given interface. 
  *
  * @param reg_interface Interface to the object
  * @return RegistryName of the ServerRegistry that manages the the corresponding object.
  */
  const RegistryName& determineRegistryName(Interface& reg_interface) const;
  
 /** This method returns an interface to the plugin manager of a given host. 
  * 
  * The interface is managed by the ClientRegistry. So the caller of this method must not delete it.
  */
  IPluginManager* getPluginManager(const RegistryName& registry_name);

 /** Tests if local optimization is possible.
  *
  * This method returns true, if Nodes of a ServerRegistry running on the same system
  * but in a different address space should be instantiated by the ClientRegistry to avoid interprocess 
  * communication between the application and a Node.
  *
  * @param is pointer to the interface of the ServerRegistry 
  * @return true if a local optimization is possible. 
  */
  bool isOptimizationAllowed(const IServerRegistry* is) const;

 /** This method enables/disables the local optimization.
  *
  * This method enables/disables the local optimization, which allows a ClientRegistry to create plugins managed by a 
  * ServerRegistry running on the same system but in a different address space to avoid network
  * communication. If the server registry runs on a different host, this flag is ignored.
  * 
  * @param b specifies if local optimization should be enabled(true) or disabled(false)
  * @param registry_name name of the ServerRegistry 
  */
  void setOptimization(bool b, const RegistryName& registry_name = RegistryName("", ClientRegistry::default_port));

 /** This method adds an additional ServerRegistry that should be used by this ClientRegistry.
  *
  * If the ServerRegistry can not be accessed an exception is thrown
  *
  * @param address This argument specifies the address of the ServerRegistry. The NMMReference can
  * be 0. In this case the ClientRegistry tries to find the service "ServerRegistry"
  * @param is_optimization_allowed If this flag is true, the ClientRegistry tries to allocate Nodes
  * in this address space if the ServerRegistry is on the same host
  */
  void addRegistry(const TSAddress& address, bool is_optimization_allowed = false)
    throw (const BindingException&);

 /** This method adds an additional ServerRegistry that should be used by this ClientRegistry.
  *
  * If the ServerRegistry can not be accessed an exception is thrown
  *
  * @param registry_name This argument specifies the address of the ServerRegistry as hostname and port number. 
  * The registry_name is also used to identify the new ServerRegistry in the application.
  * @param is_optimization_allowed If this flag is true, the ClientRegistry tries to allocate Nodes
  * in this address space if the ServerRegistry is on the same host
  */
  void addRegistry(const RegistryName& registry_name, bool is_optimization_allowed = false)
    throw (const BindingException&);
//@}

/** @name node specific methods
  */
//@{
 /** This method returns the NodeDescription of a specifc Node.
  *
  * @param reg_id RegistryID of the ServerRegistry that manages the node.
  * @param node_id ObjectID of the specific Node
  * @return NodeDescription of the Node
  */
  virtual  NodeDescription getNodeDescription(const RegistryID& reg_id, const ObjectID& node_id);
//@}

/** @name reset methods
  */
//@{
 /** This method releases ALL reserved nodes by all ServerRegistries.
  * This method is for debug-reason only!
  */
  virtual void resetInternalReservation();

 /** This method releases ALL reserved nodes of a specific user by all ServerRegistries. 
  * This method is for debug-reason only!
  * 
  * @param user_info UserInfo that specifies the user
  */
  virtual void resetSpecificInternalReservation(const UserInfo& user_info);
//@}


/** @name Methods for requesting system time information
 */
//@{
  
  /** This method determines the offset of the system clock of a server
   *  registry (possibly running on a remote system) to the system clock
   *  of the caller. 
   * \param registry_name the registry to query
   * \param number_of_requests default is 3 (increase to improve accuracy)
   * \return system clock of registy_name minus local system clock
   */
  virtual Interval getSystemTimeOffset(const RegistryName& registry_name, const unsigned int number_of_requests = 3)
    throw (const RegistryException&);

//@}


/** @name GraphDescription specific methods
  */
//@{
 /** Requests an entire flow graph specfied by a GraphDescription. 
  *
  * Within a ServerRegistry this request is represented as a Session. 
  * By default the ServerRegistry manages the Session that provides most of the Nodes for this flow graph. 
  * 
  * @param gd specifies the flow graph that should be requested.
  * @param registry_name specifies the ServerRegistry that manages the corresponding Session. 
  */
  void requestGraph(GraphDescription& gd, const RegistryName& registry_name = RegistryName("", ClientRegistry::default_port))
    throw (const RegistryException&);
        

 /** Requests a flow graph encapsulated into a CompositeNode. 
  *
  * A CompositeNode represents several connected Nodes as single Node. 
  * 
  * @param gd GraphDescription that specifies the Nodes that should be requested and represented by a CompositeNode. 
  * @return Pointer to the INode interface of the CompositeNode that encapsulates the Nodes specified in the GraphDescription
  */
  INode* requestCompositeNode(GraphDescription& gd)
        throw (const RegistryException&);

 /** Releases a flow graph that was requested using a GraphDescription. 
  * 
  * @param gd GraphDescription that should be released and was used to request the flow graph.
  */
  void releaseGraph(GraphDescription& gd);

 /** Manually register a flow graph specified in a GraphDescription by a ServerRegistry
  * 
  * @param gd flow graph
  */
  void registerGraphDescription(GraphDescription& gd)
    throw (const RegistryException&);
//@}

  /** Returns name of given ServerRegistry.
   *
   * @param reg_name name of serverregistry
   */
  RegistryName getRegistryName( const IServerRegistry& reg_name ) const;

/** This mehtod tries to find running ServerRegistries that are listening on a certain port for incoming requests.
  * 
  * @param port The port that is used by running ServerRegistry .
  * @param time The time that this method waits to receive a response from ServerRegistries before it returns 
  *             the list of available serverregistries. 
  * @return list of ServerRegistries that listen for incoming requests on a certain port. 
  */
  list<RegistryName> findServerRegistries(const int& port = ClientRegistry::default_port, const long& time = 50);

public:
  static const int default_port;   ///< Stores the well known port to the ServerRegistry 

protected:
/** This method refreshs reserved nodes and access-control.
  */
  virtual void run();

public: //methods

/* Begin> Some internal typedefs */
  typedef map<RegistryName, RegistryStruct>::iterator         RegistryIt;
  typedef map<RegistryName, RegistryStruct>::const_iterator   CRegistryIt;

  typedef map<NMMObject*, ReservationStruct>::iterator        ReservationIt;
  typedef map<NMMObject*, ReservationStruct>::const_iterator  CReservationIt;

  typedef map<ProxyObject*, ISessionStruct>::iterator         ISessionIt;
  typedef map<ProxyObject*, ISessionStruct>::const_iterator   CISessionIt;
/* End< */

private: //methods
 /** Inits a transaction on a specific ServerRegistry.
  * 
  * @param server_registry pointer to the interface of the ServerRegistry that should be locked. 
  */
  void initTransaction( IServerRegistry* server_registry );
  
 /** This method finds the ServerRegistry that manages a specific child registry (e.g. LocalRegistry) hwith given ID.
  * 
  * @param reg_id ID of the child registry
  * @return return an iterator to the internal handle for the corresponding ServerRegistry
  */
  RegistryIt findRegistryStruct(const RegistryID& reg_id);

 /** Reserves requestet node and instantiates in local address space.
  * This internal method reserves a requested Node by the corresponding ServerRegistry and instantiates the Node in the local 
  * address space of the ClientRegistry.
  * 
  * @param it Reference to the ServerRegistry that provides the Node 
  * @param reg_id ID of the registry that maintaines the Node. 
  * @param node_id ObjectID of the Node. 
  * @param nd NodeDescription that should be updated to the NodeDescription of the requested Node. 
  * @return Pointer to the INode interface of the corrsponding Node.
  */
  INode* createLocalNode(RegistryIt it, const RegistryID& reg_id, const ObjectID& node_id, NodeDescription* nd = 0)
    throw (const RegistryException&);

 /** This method requests a Node and allocates it within the address space of the corresponding ServerRegistry.
  *
  * @param it Reference to the ServerRegistry that provides the Node 
  * @param reg_id ID of the registry that maintaines the Node. 
  * @param node_id ObjectID of the Node. 
  * @param nd NodeDescription that should be updated to the NodeDescription of the requested Node. 
  * @return Pointer to the INode interface of the corrsponding Node.
  */
  INode* createDistributedNode(RegistryIt it, const RegistryID& reg_id, const ObjectID& node_id, NodeDescription* nd = 0)
    throw (const RegistryException&);

 /** Loads a plugin to instantiate a Node in the local address space of the ClientRegistry.
  * 
  * @param ipm pointer to the interface of the corresponding PluginManager. 
  * @param plugin name of the library that must be loaded for a specific Node 
  */
  void loadLocalPlugin(IPluginManager* ipm, const string& plugin)
    throw (const RegistryException& );

 /** Releases a Node that was requested by the ClientRegistry.
  * 
  * @param it internal handle to the ReservationStruct for the Node.
  */
  void releaseLocalNode(ReservationIt& it);

 /** Refresh the reservation of reserved nodes by all ServerRegistries. 
  * 
  * If this is not done, the ServerRegistry will release 
  * requested Nodes by this ClientRegistry
  */
  void refreshNodeReservation();

 /** Refreshes an initiated transaction. 
  * 
  * If this is not done, the ServerRegistry will release  an initiated transaction. 
  */
  void refreshTransactionLock();

 /** Requests and allocates an NMMObject from a given ObjectDescription.
  *
  * @param isd Interface to the ServerRegistry that provides the NMMObject
  * @param od specifies the NMMObject that should be allocated. 
  * @return pointer to the Interface of the the NMMObject. The caller of this method is responsible to delete the returned Interface.
  */
  Interface* allocateNMMObject( IServerRegistry* isr, const ObjectDescription& od);

 /** Requests Nodes that should/can not be requested by the ServerRegistry that maintains the Session for given GraphDescription.
  * 
  * @param gd GraphDescription that specifies the requested flow graph. 
  */
  void requestRemainingNodes(GraphDescription& gd)
    throw (const RegistryException&);

  /** Adds a ServerRegistry running on given hostname und port.
   *
   * @param hostname specifies the hostname where the ServerRegistry is running. 
   * @param port specifies the default port of the ServerRegistry to handle incoming requests. 
   */
  void addServerRegistry(const string& hostname, const nmm_int32& port);


private: //session sharing methods

  /**  Requests a flow graph specified by given GraphDescription that should reuse already running Nodes. 
   *
   * @param gd GraphDescription that specifies the requested flow graph 
   * @param registry_name name of the ServerRegistry that should maintain the Session object
   */
  void requestSharedGraph(GraphDescription& gd, const RegistryName& registry_name)
    throw (const RegistryException&);

  /**  Requests a flow graph specified by given GraphDescription that should reuse already running Nodes. 
   *
   * @param gd GraphDescription that specifies the requested flow graph 
   * @param registry Interface of the ServerRegistry that maintains the Session object
   * @param registry_name name of the ServerRegistry that should maintain the Session object
   */
  void requestSharedGraph(GraphDescription& , IServerRegistry* registry, const RegistryName& registry_name )
    throw (const RegistryException&);
    
  /**  Requests a flow graph specified by given GraphDescription that must not reuse already running Nodes. 
   *
   * @param gd GraphDescription that specifies the requested flow graph 
   * @param registry_name name of the ServerRegistry that should maintain the Session object
   */
  void requestExclusiveGraph(GraphDescription& gd, const RegistryName& registry_name)
    throw (const RegistryException&);

  /** Returns an ordered list of RegistryNames that are suitable to maintain the Session for a given GraphDescription. 
   *
   * The "best" ServerRegistry is the first entry in this list. In this case "best" means that most of the Nodes speciefied 
   * by GraphDescription are running on this ServerRegistry.
   * 
   * @param gd Specifies the flow graph
   * @return Ordered list of RegistryNames that are suitable to maintain the Session for a given GraphDescription. 
   */
  list<RegistryName> getBestRegistry(GraphDescription& gd)
    throw (const RegistryException&);

private:
  /** This struct stores the reserved nodes and all need information to release and refresh the
    * reservation.
    */
  struct ReservationStruct {
    ReservationStruct() : proxy_object(0), node_factory(0), node(0), registry(0), reservation_time(0){}
    RegistryID          registry_id;         ///< Stores the RegistryID from the Registry the ClientRegistry reserves the node
    NMMReference        reference;           ///< Stores the reference of the distributed object
    ProxyObject*        proxy_object;        ///< Stores the pointer of the ProxyObject
    NodeFactory*        node_factory;        ///< Stores the pointer to the NodeFactory. This pointer is only used if the Node is reserved by the local RegistryServer.
    Node*               node;                ///< Pointer to the Node. This pointer is only used if the ClientRegistry allocates the node. This pointer is only used if the Node is reserved by the local RegistryServer
    IServerRegistry*    registry;            ///< Pointer to the IServerRegistry from which we reserved the node
    ObjectID            node_id;             ///< ObjectID of the node
    long                reservation_time;    ///< How long the application can use the node.
  };

public:
  /** This struct stores Interfaces to the ServerRegistries used to reserve nodes and
    * the corresponding IPluginManager.
    */
  struct RegistryStruct {
    /** Constructor. */
    RegistryStruct() : server_registry(0), plugin_manager(0), is_optimization_allowed(false) {}
    IServerRegistry*      server_registry;                  ///< Interface to the ServerRegistry
    IPluginManager*       plugin_manager;                   ///< Interface to the corresponding PluginManager
    bool                  is_optimization_allowed;          ///< is true if the ClientRegistry can allotcate nodes in local address space
  };


  /* Stores all required information about a session */
  struct ISessionStruct {
    /** Constructor. */
    ISessionStruct() : server_registry(0), session(0) {}
    /** Destructor. */
    ~ISessionStruct();
    IServerRegistry*   server_registry;         ///< server registry which manages the session
    ISession*          session;                 ///< pointer to the session
    list<INode*>       node_list;               ///< pointer of self allocated nodes
  };
private:
  class ClientRegistryHandler : public IEventReceiver {
    public:
      /** Constructor. 
       *
       * @param ed event handler object
       */
    ClientRegistryHandler(EDObject& ed) : __handler(ed) { }
    /** Destructor. */
      virtual ~ClientRegistryHandler() { }
    /** Dispatches given event.
     *
     * @param event Event to dispatch
     * @param sender sender of Event
     */
      virtual Result receiveEvent(Event& event, const IEventSender* sender);
    private:
    EDObject& __handler;  ///< event handler 
  };
private:
  map<NMMObject*, ReservationStruct>  __reservation_map;    ///< Map with the reserved nodes.
  map<RegistryName, RegistryStruct>   __named_registry;     ///< Map of used ServerRegistries stored in ResgistryStruct with the corresponding IPluginManager.
  IPluginManager_var                  __internal_p_manager; ///< interface to the local PluginManager
  bool                                __is_running;         ///< is true during the ClientRegistry's thread is running
  bool                                __init_transaction;   ///< is true if initTransaction was called. After closeTransaction it is reset to false
  ThreadMutex                         __condition_mutex;    ///< Mutex for the __condition
  ThreadCondition                     __condition;          ///< Condition variable for the automatic refresh process
  long                                __time_interval;      ///< stores interval the run method is triggerd
  map<IServerRegistry*, long>         __locked_registry;    ///< stores the locked registries and time left for the transaction
  ThreadMutex                         __member_mutex;       ///< This Mutex synchronize the internal thread with the application.

  map<NMMObject*, IServerRegistry*>   __object_map;         ///< stores allocated and reserved objects
  map<ProxyObject*, ISessionStruct>   __session_map;        ///< stores requested sessions
  multimap<uint,RegistryName>         __registry_speeds;    ///< map of ServerRegistrys and their available cpu-speeds
  UDPBroadcaster*                     __broadcaster;        ///< Is used to find ServerRegistries listening on a certain port. 
  TEDObject2<ClientRegistry, string, nmm_int32, void(ClientRegistry::*)(const string&, const nmm_int32&), void> __registry_listener;
  ClientRegistryHandler               __handler;            ///< Handles incoming responses from ServerRegistries
  list<RegistryName>                  __registry_result;    ///< Regsitries that are found by the discovery mechanism

  string                              __synchronizer_name;  ///< Name of default synchronizer class to use
};

inline Result ClientRegistry::ClientRegistryHandler::receiveEvent(Event& event, const IEventSender*) { return __handler.dispatch(event); }

}//end namespace
#include "nmm/nmm_suffix.hpp"

#endif
