from pymasep.communication import Server, SocketHandler
import socket
import time
import struct


def test_init():
    port = 50002
    server = Server(ident='server',
                    host='localhost',
                    port=port,
                    max_connection=1,
                    socket_handler_class=SocketHandler,
                    socket_handler_args=tuple())

    assert server.id == 'server'
    assert server.max_connection == 1
    assert server.socket_handler_class == SocketHandler
    assert server.socket_handler_args == tuple()
    assert server.socket is not None


# Thanks https://stackoverflow.com/questions/166506/finding-local-ip-addresses-using-pythons-stdlib
def _get_ip():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.settimeout(0)
    try:
        # doesn't even have to be reachable
        s.connect(('10.254.254.254', 1))
        ip = s.getsockname()[0]
    except Exception:
        ip = '127.0.0.1'
    finally:
        s.close()
    return ip


def _send_multicast():
    message = b'pymasep server?'
    multicast_group = ('224.3.29.71', 10000)

    # Create the datagram socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    # Set a timeout so the socket does not block indefinitely when trying
    # to receive data.
    sock.settimeout(0.2)

    # Set the time-to-live for messages to 1 so they do not go past the
    # local network segment.
    ttl = struct.pack('b', 1)
    sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl)
    sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 1)

    data = 0
    try:

        # Send data to the multicast group
        print('C : sending ', message)
        _ = sock.sendto(message, multicast_group)

        # Look for responses from all recipients
        while True:
            print('C : waiting to receive')
            try:
                data, server = sock.recvfrom(1024)
            except socket.timeout:
                print('C: timed out, no more responses')
                break
            else:
                print('C : received', (data, server))

    finally:
        print('C : closing socket')
        sock.close()
    return data


# https://pymotw.com/2/socket/multicast.html
def test_listen_announcement():
    port = 50003
    server = Server(ident='server',
                    host='localhost',
                    port=port,
                    max_connection=1,
                    socket_handler_class=SocketHandler,
                    socket_handler_args=tuple(),
                    wait_announcement=True)
    server.wait_announcement()
    # wait for accepting client connection
    time.sleep(0.5)

    data_received = _send_multicast()

    server.stop_wait_announcement()
    server.wait_announcement_thread.join()

    local_ip = _get_ip()
    assert data_received == str.encode(local_ip) + b':' + str.encode(str(port))
