#!/usr/bin/env nix-shell
#!nix-shell -i python3 -p python3

import os
import re
import json
import urllib.request

from distutils.version import LooseVersion

UPSTREAM_INFO_FILE = os.path.join(
    os.path.dirname(os.path.abspath(__file__)),
    "upstream-info.json"
)


def fetch_latest_version():
    url = "http://download.virtualbox.org/virtualbox/LATEST.TXT"
    return urllib.request.urlopen(url).read().strip().decode()


def load_upstream_info():
    try:
        with open(UPSTREAM_INFO_FILE, 'r') as fp:
            return json.load(fp)
    except FileNotFoundError:
        return {'version': "0"}


def save_upstream_info(contents):
    remark = "Generated using update.py from the same directory."
    contents['__NOTE'] = remark
    data = json.dumps(contents, indent=2, sort_keys=True)
    with open(UPSTREAM_INFO_FILE, 'w') as fp:
        fp.write(data + "\n")


def fetch_file_table(version):
    url = "http://download.virtualbox.org/virtualbox/{}/SHA256SUMS"
    url = url.format(version)
    result = {}
    for line in urllib.request.urlopen(url):
        sha, name = line.rstrip().split()
        result[name.lstrip(b'*').decode()] = sha.decode()
    return result


def update_to_version(version):
    extpack_start = 'Oracle_VM_VirtualBox_Extension_Pack-'
    version_re = version.replace('.', '\\.')
    attribute_map = {
        'extpack': r'^' + extpack_start + r'[^-]+-[^.]+.vbox-extpack$',
        'extpackRev': r'^' + extpack_start + r'[^-]+-([^.]+).vbox-extpack$',
        'main': r'^VirtualBox-' + version_re + r'.tar.bz2$',
        'guest': r'^VBoxGuestAdditions_' + version_re + r'.iso$',
    }
    table = fetch_file_table(version)
    new_attrs = {'version': version}
    for attr, searchexpr in attribute_map.items():
        result = [re.search(searchexpr, key) for key in table.keys()]
        filtered = filter(lambda m: m is not None, result)
        found = [m.groups()[0] if len(m.groups()) > 0 else table[m.group(0)]
                 for m in filtered if m is not None]

        if len(found) == 0:
            msg = "No package found for attribute {}".format(attr)
            raise AssertionError(msg)
        elif len(found) != 1:
            msg = "More than one package found for attribute {}: ".format(attr)
            msg += ', '.join(found)
            raise AssertionError(msg)
        else:
            new_attrs[attr] = found[0]
    return new_attrs


info = load_upstream_info()
latest = fetch_latest_version()
if LooseVersion(info['version']) < LooseVersion(latest):
    print("Updating to version {}...".format(latest), end="", flush=True)
    new_attrs = update_to_version(latest)
    save_upstream_info(new_attrs)
    print(" done.")
else:
    print("Version {} is already the latest one.".format(info['version']))
