#!/usr/bin/env python3
import sys
import os
import glob

try:
    """ TIPC C-API library path searching """
    dir_name = os.path.dirname(os.path.abspath(__file__))
    pylib_path = glob.glob('%s%s'%(dir_name,'/../../../pytipc/build/lib*'))[0]
    sys.path.append(pylib_path)
except:
    pass

from tipc import *
import select
import time
import signal
import pdb

def pyapi_client_example():
    RDM_SRV_TYPE     = 18888
    STREAM_SRV_TYPE  = 17777
    SEQPKT_SRV_TYPE  = 16666
    SRV_INST         = 17
    BUF_SZ           = 40

    # polling timeout (seconds)
    TIMEOUT = 3
    READ_ONLY = select.POLLIN | select.POLLHUP

    # global variable
    quite = False

    def die(*args):
        global quite
        """
        TODO:
        """
        # Gracefully shutdown
        if not quite:
            print >>sys.stderr, args
        sys.exit(0)

    def handler(*args):
        global quite
        quite = True
        print("****** TIPC PYTHON API Demo Client Finished ******\n")
        sys.exit(0)

    def rdm_service_demo(tipc_conn, up):
        """
        struct tipc_addr srv = {RDM_SRV_TYPE, SRV_INST, 0};
        char sbuf[BUF_SZ], rmsg[BUF_SZ];
        char msg[BUF_SZ] = {"Hello World"};
        int rc, err;
        """
        msg = "Hello World"
        srv = TipcAddr(RDM_SRV_TYPE, SRV_INST, 0)
        if not up:
            print("Service on SOCK_RDM went down\n")
            return

        print("\n-------------------------------------")
        print("Service on SOCK_RDM came up")
        print("Sending msg: %s on SOCK_RDM -->%s" %(msg, srv))
        ret = tipc_conn.sock_rejectable()
        if ret < 0:
            die("Set rejectable failed\n")
        ret = tipc_conn.sendto(msg, srv)
        if ret != len(msg):
            die("sendto() failed\n")

        ret, rmsg, srv, _, err = tipc_conn.recvfrom(bufsize=BUF_SZ)
        if ret < 0 or err:
            die ("Unexpected response\n")

        print("Received response: %s <-- %s" %(rmsg.decode('utf-8'), srv))
        print("-------------------------------------\n")
        return srv.node

    def rdm_reject_demo(tipc_conn, up, srv_node):
        invalid_dest = TipcAddr(42, 1, srv_node)
        msg = "Hello World"

        if not up:
            return

        print("Sending msg: %s on SOCK_RDM --> %s (non-existing)" %(msg, invalid_dest))
        ret = tipc_conn.sendto(msg, invalid_dest)
        if ret != len(msg):
            print("Client sendto() failed: No route to host")
            return

        rc, rmsg, srv, _, err = tipc_conn.recvfrom(bufsize=BUF_SZ)
        if rc < 0 or err != 0:
            die("Unexpected response\n")

        print("Received rejected msg: %s <-- %s, err %d" %(rmsg.decode('utf-8'), srv, err))
        print("-------------------------------------\n")

    def stream_service_demo(tipc_conn, up):
        srv = TipcAddr(STREAM_SRV_TYPE, SRV_INST, 0)
        msg = "Hello World"

        if not up:
            print("Service on SOCK_STREAM went down\n")
            return

        print("\n-------------------------------------")
        print("Service on SOCK_STREAM came up")
        print("Performing implicit two-way connect with message %s -->%s" %(msg, srv))
        if  tipc_conn.sendto(msg, srv) != len(msg):
            die("send() failed: %d\n" %ret)

        ret, rmsg = tipc_conn.recv(bufsize=BUF_SZ, waitall=False)
        if ret < 0:
            die("Unexpected response\n")

        print("Received response: %s on SOCK_STREAM connection" %rmsg.decode('utf-8'))
        print("SOCK_STREAM connection established --> %s" %srv)
        print("-------------------------------------\n")

    def seqpacket_service_demo(tipc_conn, up):
        srv = TipcAddr(SEQPKT_SRV_TYPE, SRV_INST, 0)
        msg = "Hello World"

        if not up:
            print("Service on SOCK_SEQPACKET went down\n")
            return

        print("\n-------------------------------------")
        print("Service on SOCK_SEQPACKET came up")
        print("Connecting to: -->%s" %srv)
        if tipc_conn.connect(srv) < 0:
            die("connect() failed\n")

        print("Sending msg: %s on connection" %msg)
        if tipc_conn.send(msg) != len(msg):
            die("send() failed\n")

        ret, rmsg = tipc_conn.recv(bufsize=BUF_SZ, waitall=False)
        if ret < 0:
            die("Unexpected response\n")

        print("Received response: %s on SOCK_SEQPACKET connection" %rmsg.decode('utf-8'))
        print("-------------------------------------\n")

    # Handling Ctrl+C
    signal.signal(signal.SIGINT, handler)

    srv = TipcAddr(RDM_SRV_TYPE, SRV_INST)
    buf = "Hello World!!!"

    print("****** TIPC PYTHON API Demo Client Started ******\n")

    print("Waiting for Service %s" %srv)
    srv_wait(srv, -1)

    # Create Tipc socket objects
    rdm_conn = TipcConn(SOCK_RDM)
    stream_conn = TipcConn(SOCK_STREAM)
    seq_conn = TipcConn(SOCK_SEQPACKET)

    # Set up the poller
    poller = select.poll()
    poller.register(rdm_conn.get_fd(), READ_ONLY)
    poller.register(stream_conn.get_fd(), READ_ONLY)
    poller.register(seq_conn.get_fd(), READ_ONLY)

    """
    Subscribe for service events
    """
    topsrv = TopSrvConn(0)
    poller.register(topsrv.get_fd(), READ_ONLY)

    if topsrv.srv_subscr(RDM_SRV_TYPE, 0, ~0, False, -1):
        die("subscribe for RDM server failed\n")
    if topsrv.srv_subscr(STREAM_SRV_TYPE, 0, ~0, False, -1):
        die("subscribe for STREAM server failed\n")
    if topsrv.srv_subscr(SEQPKT_SRV_TYPE, 0, ~0, False, -1):
        die("subscribe for SEQPACKET server failed\n")

    while not quite:
        try:
            events = poller.poll(TIMEOUT * 1000000)
            for fd, flag in events:
                if flag & select.POLLHUP:
                    if fd == stream_conn.get_fd():
                        sock_str = "SOCK_STREAM"
                        poller.unregister(fd)
                        stream_conn.close()
                        stream_conn = TipcConn(SOCK_STREAM)
                        poller.register(stream_conn.get_fd(), READ_ONLY)
                    else:
                        if fd == seq_conn.get_fd():
                            sock_str = "SOCK_SEQPACKET"
                            poller.unregister(fd)
                            seq_conn.close()
                            seq_conn = TipcConn(SOCK_SEQPACKET)
                            poller.register(seq_conn.get_fd(), READ_ONLY)

                    print("%s connection hangup!" %sock_str)
                else:
                    if flag & select.POLLIN:
                        err, srv, _, up, _ = topsrv.srv_evt()
                        if err:
                            die("reception of service event failed\n")

                        if srv.srv_type == RDM_SRV_TYPE:
                            srv_node = rdm_service_demo(rdm_conn, up)
                            rdm_reject_demo(rdm_conn, up, srv_node)

                        if srv.srv_type == STREAM_SRV_TYPE:
                            stream_service_demo(stream_conn, up)

                        if srv.srv_type == SEQPKT_SRV_TYPE:
                            seqpacket_service_demo(seq_conn, up)
        except IOError:
            break
        except Exception:
            break
if __name__== "__main__":
    try:
        pyapi_client_example()
    except:
        pass
