from threading import Lock 
from time import time

from host_systems_apis.api_linux.whois_caller import get_whois_data_via_bash
from packet_queue import Protocol
from host_systems_apis.host_system_api import determine_operating_system
from ips_to_ignore import add_colons_to_IPv6_addr

"""
Not using socket.gethostbyaddr() because it proved unreliable
e.g. No domain was returned for one of google's IPv6 addresses

Not using python's whois modules (whois.whois, python-whois)
because these proved unreliable: no longer able to query the
whois server(s) after a limited number of queries
also cannot query by IP address (see above note on getting a domain)

The most reliable way found is the whois command in bash
"""

os_type = determine_operating_system()

# Local cache (dictionary) of whois data
# key = IP address, e.g. "1.2.3.4" or "2002::1"
# value = WhoIsData object
whois_dict = {}
whois_dict_mutex = Lock()  # accessed by maintenance and validator threads

WHOIS_EXPIRATION_SEC = 172800  # 2 days


class WhoIsData:
    def __init__(self):
        self.last_updated = None  # epoch seconds at last whois lookup
        self.org_name = None
        self.address = None
        self.country = None


def get_whois_data(ip_addr, protocol):
    """
    arg: IP address: string such as "1.2.3.4" or "2002::1"
    arg: protocol: packet_queue's Protocol class
    return: WhoIsData instance
    """
    ip_to_lookup = ip_addr
    if ip_addr not in whois_dict.keys():
        if protocol == Protocol.IPv6:
            # add in the colons for the whois lookup to work
            ip_to_lookup = add_colons_to_IPv6_addr(ip_addr)
        if os_type.linux:            
            whois_data_obj = get_whois_data_via_bash(ip_to_lookup)
            whois_data_obj.last_updated = time()
        elif os_type.windows:
            pass  # @TODO complete this
        else:
            raise Exception("Operating system '%s' not recognized!" % os_type)

        whois_dict_mutex.acquire()
        whois_dict[ip_addr] = whois_data_obj
        whois_dict_mutex.release()

    else:  # whois data already known
        whois_dict_mutex.acquire()
        whois_data_obj = whois_dict[ip_addr]
        whois_dict_mutex.release()

    return whois_data_obj


def flush_expired_whois_data():
    """ Delete whois_dict values whose whois data is expired """
    whois_dict_mutex.acquire()
    for key in whois_dict.keys():
        if time() > (whois_dict[key].last_updated + WHOIS_EXPIRATION_SEC):
            del whois_dict[key]
    whois_dict_mutex.release()
