#!/usr/bin/env python3
from __future__ import division, with_statement, print_function

import distutils.spawn
from contextlib import closing
import json
import os
import sys
import tarfile
from urllib.request import urlopen
from threading import Thread

def makedirs(dirname):
    if not os.path.exists(dirname):
        os.makedirs(dirname)

def get_platform():
    name = sys.platform
    if name.startswith('darwin'):
        name = 'darwin64'
    elif name.startswith('linux'):
        import platform
        machine = platform.machine()
        if machine == 'armv7l':
            name = 'linux_armv7l'
        elif machine == 'aarch64':
            name = 'linux_aarch64'
        elif machine == 'x86_64':
            name = 'linux64'
        else:
            name = 'linux32'
    return name

class Install(Thread):

    base_url = 'https://downloads.openmedialibrary.com/'
    status = {}
    failed = False

    def __init__(self, target, base_url=None):
        self.target = target
        if base_url:
            self.base_url = base_url
        Thread.__init__(self)
        self.daemon = True
        self.start()

    def run(self):
        if sys.platform.startswith('linux'):
            import platform
            distro = platform.linux_distribution()
            if distro[0] == 'Ubuntu' and distro[1] < '15.10':
                try:
                    from OpenSSL.SSL import TLSv1_2_METHOD
                except:
                    print("To run Open Media Library on versions of Ubuntu before 15.10, you need to manually update pyOpenSSL.")
                    print("To install the current version of pyOpenSSL, run:")
                    print("\tsudo apt-get install python3-pip python3-dev libffi-dev libssl-dev libevent-2.0-5")
                    print("\tsudo pip3 install -U pyOpenSSL")
                    self.failed = True
                    return
            apt_packages = ''
            dnf_packages = ''
            try:
                from PIL import Image
                import lxml
            except:
                apt_packages += ' python3 python3-pil python3-lxml'
                dnf_packages += ' python3-pillow python3-lxml'
            try:
                import gi
                gi.require_version('Gtk', '3.0')
                from gi.repository import Gtk, GLib
            except:
                apt_packages += ' gir1.2-gtk-3.0'
                #dnf_packages += ' webkitgtk4'
            try:
                import OpenSSL
                from OpenSSL.SSL import TLSv1_2_METHOD
            except:
                apt_packages += ' python3-openssl'
                dnf_packages += ' python3-pyOpenSSL'
            try:
                import Crypto
            except:
                apt_packages += ' python3-crypto'
                dnf_packages += ' python3-crypto'

            if not has_bin('pdftocairo'):
                apt_packages += ' poppler-utils'
                dnf_packages += ' poppler-utils'
            apt_packages = apt_packages.strip()
            dnf_packages = dnf_packages.strip()
            if has_bin('apt-get'):
                if apt_packages:
                    print('You need additional packages: %s' % apt_packages)
                    print('run: sudo apt-get install ' + apt_packages)
                    self.failed = True
                    return
            elif has_bin('dnf'):
                if dnf_packages:
                    print('Installing additional packages: %s' % dnf_packages)
                    print('run: sudo dnf install ' + dnf_packages)
                    self.failed = True
                    return
            elif apt_packages:
                print('You need to install Pillow, lxml and pyOpenSSL\ni.e. sudo pip3 install pillow lxml pyOpenSSL')
                if 'poppler' in apt_packages:
                    print('You need to install pdftocairo (part of poppler-utils).')
                print("After installing these packages, run install again.")
                self.failed = True
                return
        target = self.target
        target = os.path.normpath(os.path.abspath(target))
        makedirs(target)
        os.chdir(target)
        release = self.get_release()
        self.status['release'] = release
        print("Installing Open Media Library:")
        platform = get_platform()
        for module in sorted(release['modules']):
            if release['modules'][module].get('platform', platform) == platform:
                self.status['installing'] = module
                self.status['progress'] = 0
                self.status['size'] = 0
                package_tar = release['modules'][module]['name']
                url = self.url(package_tar)
                package_tar = os.path.join(target, package_tar)
                self.download(url, package_tar)
                tar = tarfile.open(package_tar)
                tar.extractall()
                tar.close()
                os.unlink(package_tar)
        os.symlink('openmedialibrary/ctl', 'ctl')
        self.status['progress'] = 0
        self.status['installing'] = 'setup'
        makedirs('updates')
        os.system('./ctl setup')
        release_path = 'data/release.json'
        makedirs('data')
        with open(release_path, 'w') as fd:
            json.dump(release, fd, indent=2)
        if sys.platform.startswith('linux'):
            os.system('./ctl install_launcher')
        self.status['progress'] = 1
        self.status['done'] = True

    def download(self, url, filename):
        makedirs(os.path.dirname(filename))
        print('downloading',os.path.basename(filename))
        with open(filename, 'wb') as f:
            with closing(urlopen(url)) as u:
                size = int(u.headers.get('content-length', 0))
                self.status['size'] = size
                available = 0
                data = u.read(4096)
                while data:
                    if size:
                        available += len(data)
                        self.status['progress'] = available/size
                    f.write(data)
                    data = u.read(4096)

    def get_release(self):
        with closing(urlopen(self.url('release.json'))) as u:
            data = json.loads(u.read().decode('utf-8'))
        return data

    def url(self, url):
        return self.base_url + url

def has_bin(cmd):
    path = distutils.spawn.find_executable(cmd)
    return path != None

if __name__ == '__main__':
    if len(sys.argv) == 1:
        if sys.platform == 'darwin':
            target = os.path.expanduser('~/Library/Application Support/Open Media Libary')
        elif sys.platform.startswith('linux'):
            data_home = os.path.expanduser(os.environ.get('XDG_DATA_HOME', '~/.local/share'))
            target = os.path.join(data_home, 'openmedialibrary')
        else:
            target = os.path.join(os.curdir, 'openmedialibrary')
    elif len(sys.argv) != 2:
        print('usage: %s [target]' % sys.argv[0])
        sys.exit(1)
    else:
        target = sys.argv[1]
    if os.path.exists(target):
        print('%s exists, remove it before re-installing Open Media Library' % target)
        sys.exit(1)


    install = Install(target)
    install.join()
    if not install.failed:
        print("You can launch Open Media Library from the menu or run: %s open"%os.path.join(target, 'ctl'))
        #subprocess.Popen([os.path.join(target, 'ctl'), 'open'])