#!/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 signal
import time

def pyapi_server_example():
    RDM_SRV_TYPE     = 18888
    STREAM_SRV_TYPE  = 17777
    SEQPKT_SRV_TYPE  = 16666
    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 Server Finished ******\n")

    def bind_service(srv_type, scope, sktype, sk_str):
        """
        TODO
        """
        srv_conn = TipcConn(sktype)
        if srv_conn.get_fd() <= 0:
            die("failed to create %s socket" %sk_str)

        if srv_conn.bind(srv_type, 0, ~0, scope) != 0:
            die("failed to bind %s socket" %sk_str)

        print("Bound %s socket %s to %s" %(sk_str, srv_conn.sockaddr(), TipcServiceRange(srv_type, 0, ~0, scope)))
        return srv_conn

    def recv_rdm_msg(tipc_conn):
        print("\n-------------------------------------")

        ret, msg, memberid, socketid, err = tipc_conn.recvfrom(bufsize=BUF_SZ)
        if ret <= 0:
            die("unexpected message on RDM socket\n")

        print("Received msg: %s on SOCK_RDM <-- %s" %(msg.decode('utf-8'), memberid))
        outbuf = "Huh?"
        if tipc_conn.sendto(outbuf, memberid) <= 0:
            die("Server: failed to send\n")

        print("Responding with: %s --> %s" %(outbuf, memberid))
        print("-------------------------------------\n")

    def recv_stream_setup(tipc_conn):
        print("\n-------------------------------------")
        tipc_conn.listen(32)

        new_conn, peer_addr = tipc_conn.accept()
        if new_conn is None or new_conn.get_fd() <= 0:
            die("accept on SOCK_STREAM failed\n")

        print("SOCK_STREAM connection established --> %s" %peer_addr)
        ret, msg = new_conn.recv(bufsize=BUF_SZ, waitall=False)
        if ret <= 0:
            die("unexpected message on STREAM socket")

        print("Received msg: %s on STREAM connection" %msg.decode('utf-8'))
        msg = "Huh?"
        print("Responding with: %s" %msg)
        if new_conn.send(msg) <= 0:
            die("failed to respond\n")
        print("-------------------------------------\n")
        return new_conn

    def recv_seqpacket_setup(tipc_conn):
        print("\n-------------------------------------")

        tipc_conn.listen(32)
        new_conn, peer_addr = tipc_conn.accept()

        if new_conn.get_fd() <= 0:
            die("accept on SOCK_SEQPACKET failed\n")

        print("SOCK_SEQPACKET connection established <-- %s" %peer_addr)
        ret, msg = new_conn.recv(bufsize=BUF_SZ, waitall=False)
        if ret <= 0:
            die("unexpected message on STREAM socket\n")

        print("Received msg: %s on SOCK_SEQPACKET connection" %msg.decode('utf-8'))
        msg = "Huh?"
        print("Responding with: %s" %msg)
        if new_conn.send(msg) <= 0:
            die("failed to respond\n")
        print("-------------------------------------\n")
        return new_conn

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

    print("****** TIPC PYTHON API Demo Server Started ******\n")
    rdmsd = bind_service(RDM_SRV_TYPE, 0, SOCK_RDM, "RDM")
    strsd = bind_service(STREAM_SRV_TYPE, 0, SOCK_STREAM, "STREAM")
    pktsd = bind_service(SEQPKT_SRV_TYPE, 0, SOCK_SEQPACKET, "SEQPACKET")

    while not quite:
        try:
            recv_rdm_msg(rdmsd)
            client_conn_stream = recv_stream_setup(strsd)
            client_conn_seq = recv_seqpacket_setup(pktsd)

            # Set up the poller
            poller = select.poll()
            poller.register(client_conn_stream.get_fd(), READ_ONLY)
            poller.register(client_conn_seq.get_fd(), READ_ONLY)

            events = poller.poll(TIMEOUT * 1000000)
            for fd, flag in events:
                if not flag & select.POLLHUP:
                    continue

                print("-------------------------------------")
                sock_str = ''
                if fd == client_conn_stream.get_fd():
                    sock_str = "SOCK_STREAM"
                    poller.unregister(fd)
                    client_conn_stream.close()
                else:
                    if fd == client_conn_seq.get_fd():
                        sock_str = "SOCK_SEQPACKET"
                        poller.unregister(fd)
                        client_conn_seq.close()

                print("%s connection hangup" %sock_str)
        except IOError:
            break
        except Exception:
            break

if __name__== "__main__":
    try:
        pyapi_server_example()
    except:
        pass
