

import logging
import os
import os.path
import subprocess

from .. import util

logger = logging.getLogger(__name__)

class Wifi:

    def __init__(self, root):
        self.root = root

    def get_interface(self):
        ifcs = [ i for i in os.listdir('/sys/class/net/') if i.startswith('w')]
        if not ifcs:
            logger.error("No wifi interface found")
            return
        return ifcs[0]

    def reset_interface(self, interface):
        subprocess.check_call(["sudo", "ip", "link", "set", "dev", interface, "down"])
        subprocess.check_call(["sudo", "ip", "link", "set", "dev", interface, "up"])
        subprocess.call(["sudo", "killall", "wpa_supplicant"])

    def pw2network(self, pw, ssid):
        lines = pw.splitlines()
        if len(lines) < 2:
            return subprocess.check_output(["wpa_passphrase", ssid, pw]).decode('UTF-8')
        else:
            return 'network={\n  %s\n}\n\n' % ('\n  '.join(lines[1:-1]))

    def do_init(self):
        """ Write netctl config files for known networks into /etc/netctl/. """
        os.umask(0o077)  # NOTE: allow 0600
        with util.tempdir() as tmpdir:
            for d in util.get_dict_by_name(self.root, 'netctl'):
                if d.get('netctl', 'false').lower() == 'true':
                    fn      = d.get('name', None)
                    ssid    = d.get('SSID', fn)
                    pw      = d.get('password', None)
                    hidden  = d.get('hidden', 'no')
                    if fn and ssid and pw:
                        logger.debug("Writing netctl file %s for: %s", fn, ssid)
                        tmpfile = os.path.join(tmpdir, fn)
                        with open(tmpfile, "w") as f:
                            f.write('# generated by vault\n')
                            f.write("ESSID='%s'\n" % ssid)
                            f.write("Key='%s'\n" % pw)
                            f.write("Hidden=%s\n" % hidden)
                            f.write("Connection=wireless\n")
                            f.write("Security=wpa\n")
                            f.write("IP=dhcp\n")
                            f.write('Interface=$(ls /sys/class/net/ | grep "^w" | head -1)\n')
                        subprocess.check_call(["sudo", "mv", tmpfile, "/etc/netctl/" + fn])
                        subprocess.check_call(["sudo", "chown", "root:root", "/etc/netctl/" + fn])
        return

    def do_wifi(self, name=None):
        interface = self.get_interface()
        entry = None
        if name:
            for e in util.get_dict_by_name(self.root, 'SSID'):
                if e.get('name', None) == name:
                    entry = e
                    break
            else:
                logger.error("No configuration for wifi %s found.", name)
                return
        else:
            confs = { e.get('SSID') : e for e in util.get_dict_by_name(self.root, 'SSID') }
            cells = []
            quality = 0
            try:
                scan_result = subprocess.check_output(["sudo", "iwlist", interface, "scan"])
            except subprocess.CalledProcessError as e:
                self.reset_interface()
                scan_result = subprocess.check_output(["sudo", "iwlist", interface, "scan"])
            for line in scan_result.decode('UTF-8').splitlines():
                if line.strip().startswith('Quality'):
                    cur,_,max = line.split()[0].split('=')[1].partition('/')
                    quality = float(cur) / float(max)
                elif line.strip().startswith('ESSID'):
                    _,_,ssid = line.partition(':')
                    ssid = ssid.strip().strip('"')
                    if ssid in confs:
                        logger.debug("Found Cell %s [%f]", ssid, quality)
                        cells.append((quality, confs.get(ssid)))
            if not cells:
                logger.error("No wifi with matching configuration found")
                return
            _,entry = sorted(cells)[-1]
            logger.info("Connecting to %s", entry.get('SSID'))
        interface = entry.get('interface', interface)
        fn        = entry.get('name', None)
        ssid      = entry.get('SSID', fn)
        pw        = entry.get('password', None)
        if interface and fn and ssid and pw:
            with util.tempdir() as tmpdir:
                network_conf = self.pw2network(pw, ssid)
                tmpfile = os.path.join(tmpdir, fn)
                with open(tmpfile, "w") as f:
                    f.write( network_conf )
                self.reset_interface(interface)
                subprocess.check_call(["sudo", "wpa_supplicant", "-B", "-D", "nl80211,wext", "-i", interface, "-c", tmpfile])
                subprocess.call(["sudo", "dhcpcd", interface])
        return

    def do_wifid(self):
        """ Let wpa_supplicant choose from all available WiFis. """
        interface = self.get_interface()
        networks = list( util.get_dict_by_name(self.root, 'SSID') )
        if not interface or not networks:
            return
        with util.tempdir() as tmpdir:
            tmpfile = os.path.join(tmpdir, "wpa_supplicant.conf")
            with open(tmpfile, "w") as f:
                f.write("ctrl_interface=/run/wpa_supplicant\n")
                f.write("ctrl_interface_group=wheel\n\n")
                for network in networks:
                    if network.get("interface") and (network.get("interface") != interface):
                        continue
                    ssid = network.get('SSID') or network.get('name')
                    pw   = network.get('password')
                    if not (ssid and pw):
                        continue
                    f.write( self.pw2network(pw, ssid) )
            self.reset_interface(interface)
            subprocess.check_call(["sudo", "wpa_supplicant", "-B", "-D", "nl80211,wext", "-i", interface, "-c", tmpfile])
            subprocess.call(["sudo", "dhcpcd", interface])
        return


