#!/usr/bin/env python3

import os
import sys
import socket
import json
import time
from socket import socket, AF_INET, SOCK_DGRAM
from copy import deepcopy

MY_PORT = 5999
CONTROLLER_PORT = 1500

def dict_compare(d1, d2):
    d1_keys = set(d1.keys())
    d2_keys = set(d2.keys())
    shared_keys = d1_keys.intersection(d2_keys)
    added = d2_keys - d1_keys
    removed = d1_keys - d2_keys
    modified = {o : (d1[o], d2[o]) for o in shared_keys if d1[o] != d2[o]}
    same = set(o for o in shared_keys if d1[o] == d2[o])
    return added, removed, modified, same

def getMyIPaddress():
    sx = socket(AF_INET, SOCK_DGRAM)
    sx.connect(("8.8.8.8", 80))
    return sx.getsockname()[0]

def sendMessage(ip, port, data):
    """ send any message to an ip+port tuple
    """
    print(ip, port, data)
    send_socket = socket(AF_INET,SOCK_DGRAM)
    send_socket.sendto(data.encode('utf8'), (ip, port))

def getModuleList(target_ip):
    """ send a MODULE_LIST_REQ message
        wait for MODULE_INFO messages
        replies with list of tuples (modulename,port) or None
    """
    result = {}
    MSG_MODULE_LIST_REQ =  '{"MessageType":"MODULE_LIST_REQ", "IP":"%s", "Port":"%d", "Unfiltered":1 }'
    reply_to_ip = getMyIPaddress()
    recv_socket = socket(AF_INET,SOCK_DGRAM)
    recv_socket.bind(('', MY_PORT))
    msg = MSG_MODULE_LIST_REQ % (reply_to_ip, MY_PORT)
    sendMessage(target_ip, CONTROLLER_PORT, msg)
    while True:
        try:
            recv_socket.settimeout(5)
            msg, addr = recv_socket.recvfrom(32768)
            msgAsString = msg.decode('utf8')
            msgAsJson = json.loads(msgAsString)
            normal_eof = msgAsJson.get("EOF", "0")
            if normal_eof == "1":
                break
            name = msgAsJson.get("MODULE", None)
            port = msgAsJson.get("PORT", None)
            if name and port:
                result[name] = port
        except Exception as e:
            print ("getModuleList: Exception:%s" %(e,))
            break
    return result

def main():
    """ simple test
    """
    # Argument check
    if len(sys.argv)<2:
        sys.stderr.write('usage:' + sys.argv[0] + ' htc_ip_address\n')
        sys.exit(2)
    target_ip_address = sys.argv[1]    

    # Do the work
    first = getModuleList(target_ip_address)
    print(first)

    while True:
        time.sleep(60)
        second = getModuleList(target_ip_address)
        print(len(second))
        added, removed, modified, same = dict_compare(first, second)
        if len(added) or len(removed) or len(modified):
            print(time.time())
            os.system("aplay alarm.wav")
            print(second)
            first = deepcopy(second)
            
        

if __name__ == "__main__":
    main()
