""" Wrapper tipc from libtipc """
from _pylibtipc import own_node as pylib_own_node
from _pylibtipc import srv_wait as pylib_srv_wait
from _pylibtipc import link_name as pylib_link_name

from _pylibtipc import socket as pylib_socket
from _pylibtipc import sock_non_block as pylib_sock_non_block
from _pylibtipc import sock_rejectable as pylib_sock_rejectable
from _pylibtipc import sock_importance as pylib_sock_importance
from _pylibtipc import bind as pylib_bind
from _pylibtipc import unbind as pylib_unbind
from _pylibtipc import close as pylib_close
from _pylibtipc import sockaddr as pylib_sockaddr
from _pylibtipc import connect as pylib_connect
from _pylibtipc import listen as pylib_listen
from _pylibtipc import accept as pylib_accept
from _pylibtipc import join as pylib_join
from _pylibtipc import leave as pylib_leave
from _pylibtipc import recvfrom as pylib_recvfrom
from _pylibtipc import recv as pylib_recv
from _pylibtipc import send as pylib_send
from _pylibtipc import sendto as pylib_sendto
from _pylibtipc import mcast as pylib_send_mcast

from _pylibtipc import topsrv_conn as pylib_topsrv_conn
from _pylibtipc import srv_subscr as pylib_srv_subscr
from _pylibtipc import srv_evt as pylib_srv_evt
from _pylibtipc import link_evt as pylib_link_evt

from _pylibtipc import TIPC_LOW_IMPORTANCE, \
    TIPC_MEDIUM_IMPORTANCE, TIPC_HIGH_IMPORTANCE, \
    TIPC_CRITICAL_IMPORTANCE, \
    SOCK_STREAM, SOCK_DGRAM, SOCK_RDM, SOCK_SEQPACKET, \
    TIPC_NODE_STATE, TIPC_LINK_STATE, TIPC_WAIT_FOREVER

MSG_LEVELS = [TIPC_LOW_IMPORTANCE, \
              TIPC_MEDIUM_IMPORTANCE, \
              TIPC_HIGH_IMPORTANCE, \
              TIPC_CRITICAL_IMPORTANCE]

SOCK_TYPES = [SOCK_STREAM, SOCK_DGRAM, SOCK_RDM, SOCK_SEQPACKET]

class TipcAddr(object):
    """
    TODO:
        Attributes:
    """

    def __init__(self, srv_type=0, instance=0, node=0):
        """ TODO: """
        self.srv_type = srv_type
        self.srv_instance = instance
        self.node = node

    def __repr__(self):
        """ TODO: """
        return "tipc.TipcAddr"

    def __str__(self):
        """ TODO: """
        if self.srv_type != 0:
            return "%u:%u@%x" %(self.srv_type, self.srv_instance, self.node)
        return "0:%010u@%x" %(self.srv_instance, self.node)

    def string(self):
        """ TODO: """
        return self.__str__()

    def is_equal(self, item):
        """ TODO: """
        if not isinstance(item, TipcAddr):
            return False

        return ((self.srv_type == item.srv_type) and
                (self.srv_instance == item.srv_instance) and
                (self.node == item.node))

class TipcServiceRange(object):
    """
    TODO:
        Attributes:
    """

    def __init__(self, srv_type=0, lower=0, upper=0, node=0):
        """ TODO: """
        self.srv_type = srv_type
        self.lower = lower
        self.upper = upper
        self.node = node

    def __repr__(self):
        """ TODO: """
        return "tipc.TipcServiceRange"

    def __str__(self):
        """ TODO: """
        return "%u:%u:%u@%x" %(self.srv_type, self.lower, self.upper, self.node)

    def string(self):
        """ TODO: """
        return self.__str__()

    def is_equal(self, item):
        """ TODO: """
        if not isinstance(item, TipcAddr):
            return False

        return ((self.srv_type == item.srv_type) and
                (self.lower == item.lower) and
                (self.upper == item.upper) and
                (self.node == item.node))

class TipcConn(object):
    """
    TODO:
        Attributes:
    """
    def __init__(self, socktype, fd=0):
        """ TODO: """

        if socktype not in SOCK_TYPES:
            raise ValueError("sock_type should be in range %s "%SOCK_TYPES)

        self.file_fd = fd
        self.sock_type = socktype

        if fd <= 0:
            self.socket(socktype)

    def socket(self, socktype):
        """ Create AF_TIPC socket API """
        self.file_fd = pylib_socket(socktype)

    def get_fd(self):
        """ Return File Description TIPC socket """
        return self.file_fd

    def sock_non_block(self):
        """ Set a TIPC socket to non-block """
        return pylib_sock_non_block(self.file_fd)

    def sock_rejectable(self):
        """ Set messages sent from this socket as rejectable """
        return pylib_sock_rejectable(self.file_fd)

    def sock_priority(self, pri=TIPC_MEDIUM_IMPORTANCE):
        """ Set priority from this socket """
        if pri not in MSG_LEVELS:
            raise ValueError("priority should be in range %s "%MSG_LEVELS)

        return pylib_sock_importance(self.file_fd, pri)

    def bind(self, srv_type, lower, upper, node=0):
        """ Bind a TIPC socket """
        return pylib_bind(self.file_fd, srv_type, lower, upper, node)

    def unbind(self, srv_type, lower, upper):
        """ Unbind a bound address """
        return pylib_unbind(self.file_fd, srv_type, lower, upper)

    def close(self):
        """ Close a TIPC socket """
        return pylib_close(self.file_fd)

    def sockaddr(self):
        """ Get a bound socket information """
        return pylib_sockaddr(self.file_fd)

    def connect(self, addr):
        """ Establish connection to a TIPC socket address (service address) """
        return pylib_connect(self.file_fd, addr)

    def accept(self):
        """ TODO: """
        new_fd, addr = pylib_accept(self.file_fd)
        if new_fd <= 0:
            return None, addr
        return TipcConn(self.sock_type, new_fd), addr

    def listen(self, backlog=0):
        """ TODO: """
        return pylib_listen(self.file_fd, backlog)

    def join(self, member, events=False, loopback=False):
        """ TODO: """
        return pylib_join(self.file_fd, member, events, loopback)

    def leave(self):
        """ TODO: """
        return pylib_leave(self.file_fd)

    def recvfrom(self, bufsize=1024):
        """ TODO: """
        return pylib_recvfrom(self.file_fd, bufsize)

    def recv(self, bufsize=1024, waitall=False):
        """ TODO: """
        return pylib_recv(self.file_fd, bufsize, waitall)

    def send(self, buf):
        """ TODO: """
        if not isinstance(buf, bytearray):
            buf = bytearray(buf, 'utf-8')
        return pylib_send(self.file_fd, buf)

    def sendto(self, buf, dst):
        """ TODO: """
        if not isinstance(buf, bytearray):
            buf = bytearray(buf, 'utf-8')
        return pylib_sendto(self.file_fd, buf, dst)

    def send_mcast(self, buf, dst):
        """ TODO: """
        return pylib_send_mcast(self.file_fd, buf, dst)


class TopSrvConn(object):
    """
    TODO:
        Attributes:
    """

    def __init__(self, topsrv_node):
        """ TODO: """
        self.file_fd = pylib_topsrv_conn(topsrv_node)

    def get_fd(self):
        """ Return File Description TIPC socket """
        return self.file_fd

    def close(self):
        """ TODO: """
        return pylib_close(self.file_fd)

    def srv_subscr(self, srv_type, lower, upper, filter_all=False, expire=1000):
        """ TODO: """
        return pylib_srv_subscr(self.file_fd, srv_type, lower, upper, filter_all, expire)

    def srv_evt(self):
        """ TODO:

            Args:

            Returns:
                err, TipcAddr, TipcAddr, available, expire

            Raises:
                None
        """
        return pylib_srv_evt(self.file_fd)

    def neigh_subscr(self):
        """ TODO: """
        return pylib_srv_subscr(self.file_fd, TIPC_NODE_STATE, 0, ~0, True, TIPC_WAIT_FOREVER)

    def neigh_evt(self):
        """ TODO: """
        (srv, _, available, _) = pylib_srv_evt(self.file_fd)
        return srv.instance, available

    def link_subscr(self):
        """ TODO: """
        return pylib_srv_subscr(self.file_fd, TIPC_LINK_STATE, 0, ~0, True, TIPC_WAIT_FOREVER)

    def link_evt(self):
        """ TODO: """
        return pylib_link_evt(self.file_fd)

def own_node():
    """ TODO: """
    return pylib_own_node()

def srv_wait(srv, expire):
    """ TODO: """
    if pylib_srv_wait(srv, expire) == 1:
        return True
    return False

def link_name(peer, bearerid):
    """ TODO: """
    return pylib_link_name(peer, bearerid)
