#!/usr/bin/env python3
import socket
import sys
import re
from subprocess import check_output
from ast import literal_eval

rack_hosts = {k.lower(): v for k, v in
    literal_eval(check_output('config/json_racklist').decode()).items()}

def get_ip(host):
    """given a host name, return ip as list of str(int) or None when not found"""
    try:
        for info in  socket.getaddrinfo(host, 0, 0, socket.SOCK_STREAM):
            ip = info[4][0].split('.')
            if len(ip) == 4:
                return ip
    except socket.gaierror:
        pass
    return None

def get_host(ip):
    """given ip as list of str(int), return host or None when not found"""
    try:
        return socket.gethostbyaddr('.'.join(ip))[0]
    except socket.herror:
        return None

def subnet(ip_subnet):
    """try to find subnet"""
    ip = list(ip_subnet)
    if ip[0:2] != ['172', '28']:
        return 'office'
    ip[3] = '60'  # assume instrument computer is at address 172.38.*.60
    return get_host(ip).split('.')[0]

def get_rack(rack_name=None):
    myip = get_ip(socket.gethostname())
    if not myip:
        return '! no own ip'

    if rack_name:
        rack_name = rack_name.lower()
        rack_host = rack_hosts.get(rack_name)
        if not rack_host:
            return '%s is no known rack (see sea/tcl/config/rack.list)' % rack_name
        rack_ip = get_ip(rack_host)
        if not rack_ip:
            return '! %s not found' % rack_name
        if subnet(rack_ip) == 'office' or subnet(rack_ip) == subnet(myip):
            return rack_name  # given rack is accessible
        return '! %s (%s) is in %s net' % (rack_name, '.'.join(rack_ip), subnet(rack_ip))

    other_racks = []
    found_racks = []
    for rack, host in rack_hosts.items():
        if rack == rack_name:
            continue
        ip = get_ip(host)
        if ip:
            if subnet(ip) == subnet(myip):
                found_racks.append(rack)
            else:
                other_racks.append(rack)
    if found_racks:
        return ' '.join(found_racks)
    if subnet(myip) == 'office':
        other_racks = []
    if other_racks:
        return ' '.join(other_racks)
    return "! no racks accessible"


if len(sys.argv) > 2:
    print('Usage: cc_rack [<guessed rack>]')
else:
    if len(sys.argv) == 2:
        rack_name = sys.argv[1].lower()
    else:
        rack_name = None
    print(get_rack(rack_name))

