#!/usr/bin/env python
"""A simple Communicator class that has N,E,S,W neighbors connected via 0MQ PEER sockets"""
 
import socket
 
import zmq
 
from IPython.parallel.util import disambiguate_url
 
class EngineCommunicator(object):
    """An object that connects Engines to each other.
    north and east sockets listen, while south and west sockets connect.
 
    This class is useful in cases where there is a set of nodes that
    must communicate only with their nearest neighbors.
    """
 
    def __init__(self, interface='tcp://*', identity=None):
        self._ctx = zmq.Context()
        self.north = self._ctx.socket(zmq.PAIR)
        self.west = self._ctx.socket(zmq.PAIR)
        self.south = self._ctx.socket(zmq.PAIR)
        self.east = self._ctx.socket(zmq.PAIR)
 
        # bind to ports
        northport = self.north.bind_to_random_port(interface)
        eastport = self.east.bind_to_random_port(interface)
 
        self.north_url = interface+":%i"%northport
        self.east_url = interface+":%i"%eastport
 
        # guess first public IP from socket
        self.location = socket.gethostbyname_ex(socket.gethostname())[-1][0]
 
    def __del__(self):
        self.north.close()
        self.south.close()
        self.east.close()
        self.west.close()
        self._ctx.term()
 
    @property
    def info(self):
        """return the connection info for this object's sockets."""
        return (self.location, self.north_url, self.east_url)
 
    def connect(self, south_peer=None, west_peer=None):
        """connect to peers.  `peers` will be a 3-tuples, of the form:
        (location, north_addr, east_addr)
        as produced by
        """
        if south_peer is not None:
            location, url, _ = south_peer
            self.south.connect(disambiguate_url(url, location))
        if west_peer is not None:
            location, _, url = west_peer
            self.west.connect(disambiguate_url(url, location))