def __init__(self, params):
    """ All informations about this node:
    host --> ip if the node, network_port, GUI_port, posX, posY, ar, ca, 
    ori --> a point, 
    exp --> expected number of neighbour, pseudo"""


    # event queue, used for inter-thread communication
    self.events = NotificationQueue()

    # network communication with peers is handled by this object
    netParams = params.getNetParams()
    self.peerConnector = UDPConnector("peer", self.events, netParams)

    controlParams = params.getControlParams()
    self.controlConnector = XMLRPCConnector("control", self.events, controlParams)

    # set the solipsis protocol used
    engineParams = params.getEngineParams()
    self.engine = V0_2_5_Engine(self, engineParams)

    self.controlEngine = ControlEngine(self, engineParams)
    self.internalEngine = InternalEngine(self, engineParams)
    
    position = [params.posX, params.posY]
    
    # call parent class constructor
    Entity.__init__(self, position, params.ori, params.ar, params.caliber,
                  params.pseudo)
    
    self.id = "unknown"
    
    # maximum expected number of neighbours.
    self.exp = params.exp
    
    # our IP address or 'localhost' if not specified in config file
    self.host = params.host
    
    self.alive = True
    self.logger = params.rootLogger
    
    # manage all peers
    peersParams = params.getPeersParams()
    self.peersManager = PeersManager(self, peersParams)

    # set world size in Geometry class
    Geometry.SIZE = params.world_size
    self.params=params
class Node(Entity):
  
  def __init__(self, params):
    """ All informations about this node:
    host --> ip if the node, network_port, GUI_port, posX, posY, ar, ca, 
    ori --> a point, 
    exp --> expected number of neighbour, pseudo"""


    # event queue, used for inter-thread communication
    self.events = NotificationQueue()

    # network communication with peers is handled by this object
    netParams = params.getNetParams()
    self.peerConnector = UDPConnector("peer", self.events, netParams)

    controlParams = params.getControlParams()
    self.controlConnector = XMLRPCConnector("control", self.events, controlParams)

    # set the solipsis protocol used
    engineParams = params.getEngineParams()
    self.engine = V0_2_5_Engine(self, engineParams)

    self.controlEngine = ControlEngine(self, engineParams)
    self.internalEngine = InternalEngine(self, engineParams)
    
    position = [params.posX, params.posY]
    
    # call parent class constructor
    Entity.__init__(self, position, params.ori, params.ar, params.caliber,
                  params.pseudo)
    
    self.id = "unknown"
    
    # maximum expected number of neighbours.
    self.exp = params.exp
    
    # our IP address or 'localhost' if not specified in config file
    self.host = params.host
    
    self.alive = True
    self.logger = params.rootLogger
    
    # manage all peers
    peersParams = params.getPeersParams()
    self.peersManager = PeersManager(self, peersParams)

    # set world size in Geometry class
    Geometry.SIZE = params.world_size
    self.params=params
   
  def getPeersManager(self):
    return self.peersManager

  def updatePosition(self, newPosition):
    """ update the position of the node
    newPosition : the new poition of the node , a list [posX, posY]
    """
    self.node.position = newPosition
    manager = self.getPeersManager()
    # re compute all positions of neighbours
    manager.update()
    

  def send(self, peer, message):
    """
    Send a message to a peer
    message : a solispsis message, e.g. 'HEARTBEAT;10.193.161.35:33363'
    peer    : a Peer object resenting the recipient of the message
    """
    #netEvent = NetworkEvent(message)
    #netEvent.setRecipient(peer.getNetAddress())
    #self.net.send(netEvent)
    self.peerConnector.send(peer, message)

  def sendController(self, message):
    self.controlConnector.send(message)
    
  def enterSolipsis(self):
    """
    Enter Solipsis world, we consider that we have entered solipsis as soon as have
    we are connected to one Solipsis entity
    Raise: SolipsisConnectionError when a timeout expires
    Return : True if the connection succeded
    """
    time_stamp = time.time()
    #message = "KNOCK;SOLIPSIS 0.3"
    message = "HI"
    timeout = self.params.connection_timeout
    
    while True:

      # retrieve peer
      manager = self.getPeersManager()
      peer = manager.getRandomPeer()
            
      # send message  
      self.send(peer, message)      
      time.sleep(0.5)

      # we got an answer, for one of our Hi messages: we have entered Solipsis 
      if not self.events.empty():
        self.alive = True
        return True

      # Time out : impossible to connect
      if time.time() > time_stamp + timeout:
        self.logger.critical("Time out: cannot connect to Solipsis")
        raise SolipsisConnectionError()

  def exit(self):
    """ stop the node and exit
    """
    # stop the network thread
    self.peerConnector.stop()

    # we do not need to stop the controlConnector. The controlConnector
    # stopped after sending us the exit message
    # --> self.controlConnector.stop() not needed !
    
    # wait for the other threads before exiting
    self.peerConnector.join()
    self.controlConnector.join()

    self.alive = False
    
  def mainLoop(self):
    """ Main loop of the program """
    # start control connector
    self.controlConnector.start()
    # start peer connector
    self.peerConnector.start()

    try:
      # enter solipsis : send the first message
      #self.enterSolipsis()
      pass
    except:
      self.logger.critical("cannot enter Solipsis, exiting...")
      self.exit()
      raise

    while self.alive:
      self.events.acquire()
      # no events to process - wait for a notification from other threads
      if self.events.empty():
        self.events.wait()
        
      # We can immediately release the lock: we know that there is an item available
      # because this is the only thread that consumes items from the queue.
      # If other threads can consume item then we must first get the item then
      # release the lock
      self.events.release()
      
      # process one event in queue        
      event = self.events.get()
      
      type = event.type()
      #self.logger.debug("%s - %s - %s ", event.name(), event.type(),
      #                  event.data())
      if( type == Event.PEER ):
        self.engine.process(event)
      elif( type == Event.CONTROL):
        self.controlEngine.process(event)
      elif type == Event.INTERNAL:
        self.internalEngine.process(event)
      else:
        self.logger.critical("Unknown event type" + type)
                      
    self.logger.debug("end of main loop")
    
  def processPeriodicEvent(self, event):
    """ Process periodic tasks
    Send heartbeat message
    Or check global connectivity
    """
    # TO DO
    self.logger.critical("processPeriodicEvent not implemented")
class Node(Entity):
  
  def __init__(self, params):
    """ All informations about this node:
    host --> ip if the node, network_port, GUI_port, posX, posY, ar, ca, 
    ori --> a point, 
    exp --> expected number of neighbour, pseudo"""


    # event queue, used for inter-thread communication
    self.events = NotificationQueue()

    # network communication with peers is handled by this object
    netParams = params.getNetParams()
    self.peerConnector = UDPConnector("peer", self.events, netParams)

    controlParams = params.getControlParams()
    self.controlConnector = XMLRPCConnector("control", self.events, controlParams)

    intParams =  params.getInternalParams()
    self.internalConnector = InternalConnector('internal', self.events, intParams)
    
    position = Position(params.posX, params.posY)
    
    # call parent class constructor
    Entity.__init__(self, position, params.ori, params.ar, params.caliber,
                  params.pseudo)
    
    self.id = "unknown"
    
    # maximum expected number of neighbours.
    self.exp = params.exp
    
    # our IP address or 'localhost' if not specified in config file
    self.host = params.host
    
    self.alive = True
    self.logger = params.rootLogger
    
    # manage all peers
    peersParams = params.getPeersParams()
    self.peersManager = PeersManager(self, peersParams)

    # set world size in Geometry class
    Geometry.SIZE = params.world_size
    self.params=params

    self.state = None
    self.setState('NotConnected')
    
  def getPeersManager(self):
    return self.peersManager

  def setState(self, stateClass):
    stmt = 'state.' + stateClass + '(self, self.logger)'
    try:
      self.state = eval(stmt)
    except:
      raise SolipsisInternalError('unknown state ' + stateClass)

  def fire(self, event):
    """ Send an event.
    event : the event to send.
    """
    connector = None
    type = event.getType()
    if type == 'peer':
      connector = self.peerConnector
    elif type == 'control':
      connector = self.controlConnector
    elif type == 'internal':
      connector = self.internalConnector
    else:
      raise SolipsisInternalError('Unknown event type ' + type )
    
    connector.send(event)
    
  def exit(self):
    """ stop the node and exit
    """
    # stop the network thread
    self.peerConnector.stop()
    self.internalConnector.stop()    
    # we do not need to stop the controlConnector. The controlConnector
    # stopped after sending us the exit message
    # --> self.controlConnector.stop() not needed !
    
    # wait for the other threads before exiting
    self.peerConnector.join()
    self.controlConnector.join()
    self.internalConnector.join()
    self.alive = False
    
  def mainLoop(self):
    """ Main loop of the program """
    # start control connector
    self.controlConnector.start()
    # start peer connector
    self.peerConnector.start()
    # start internal connected : needed for periodic tasks
    self.internalConnector.start()
    

    while self.alive:
      self.events.acquire()
      # no events to process - wait for a notification from other threads
      if self.events.empty():
        self.events.wait()
        
      # We can immediately release the lock: we know that there is an item available
      # because this is the only thread that consumes items from the queue.
      # If other threads can consume item then we must first get the item then
      # release the lock
      self.events.release()
      
      # process one event in queue        
      event = self.events.get()
      request = event.getRequest()

      try:
        # process this request according to our current state
        # e.g.: stmt='self.state.NEAREST(event)'
        stmt = 'self.state.' + request + '(event)'
        eval(stmt)
      except:
        self.logger.debug(sys.exc_info()[0])
        self.logger.debug(sys.exc_info()[1])
        self.logger.debug("unknown request "+ stmt)
                                 
    self.logger.debug("end of main loop")