from __future__ import division, with_statement

from contextlib import closing
import json
import os
import sys
import time
import tarfile
from urllib.request import urlopen
import http.server
import socketserver
from threading import Thread
import subprocess
import webbrowser


PORT = 9841
if getattr(sys, 'frozen', False):
    static_dir = os.path.dirname(sys.executable)
else:
    static_dir = os.path.dirname(os.path.realpath(__file__))
static_dir = os.path.abspath(static_dir)

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
        if platform.architecture()[0] == '64bit':
            name = 'linux64'
        else:
            name = 'linux32'
    return name

class Handler(http.server.SimpleHTTPRequestHandler):
    def do_OPTIONS(self):
        self.send_response(200, 'OK')
        self.send_header('Allow', 'GET, POST, OPTIONS')
        self.send_header('Access-Control-Allow-Origin', '*')
        self.send_header('Access-Control-Allow-Headers', 'X-Requested-With')
        self.send_header('Content-Length', '0')
        self.end_headers()

    def do_GET(self):

        if self.path == '/status':
            content = json.dumps(self.server.install.status).encode()
            self.send_response(200, 'OK')
        else:
            path = os.path.join(static_dir, 'index.html' if self.path == '/' else self.path[1:])
            if os.path.exists(path):
                with open(path, 'rb') as fd:
                    content = fd.read()
                self.send_response(200, 'OK')
                content_type = {
                    'html': 'text/html',
                    'png': 'image/png',
                    'svg': 'image/svg+xml',
                    'txt': 'text/plain',
                }.get(path.split('.')[-1], 'txt')
                self.send_header('Content-Type', content_type)
            else:
                self.send_response(404, 'not found')
                content = b'404 not found'
        self.send_header('Access-Control-Allow-Origin', '*')
        self.send_header('Content-Length', str(len(content)))
        self.end_headers()
        self.wfile.write(content)

    def log_message(self, format, *args):
        pass

class Install(Thread):

    release_url = "http://downloads.openmedialibrary.com/release.json"
    status = {
        'step': 'Downloading...'
    }

    def __init__(self, target, httpd):
        target = os.path.normpath(os.path.join(os.path.abspath(target)))
        self.target = target
        self.httpd = httpd
        Thread.__init__(self)
        self.daemon = True
        self.start()

    def run(self):
        webbrowser.open('http://127.0.0.1:%s'%PORT)
        target = self.target
        makedirs(target)
        os.chdir(target)
        self.status["step"] = 'Downloading...'
        release = self.get_release()
        self.status["release"] = release
        self.status["progress"] = 0
        platform = get_platform()
        for module in sorted(release['modules']):
            if release['modules'][module].get('platform', platform) == platform:
                package_tar = release['modules'][module]['name']
                url = self.release_url.replace('release.json', package_tar)
                self.download(url, package_tar)
        self.status["step"] = 'Installing...'
        for module in sorted(release['modules']):
            if release['modules'][module].get('platform', platform) == platform:
                package_tar = release['modules'][module]['name']
                tar = tarfile.open(package_tar)
                tar.extractall()
                tar.close()
                os.unlink(package_tar)
        makedirs('data')
        with open('data/release.json', 'w') as fd:
            json.dump(release, fd, indent=2)
        self.status = {"relaunch": True}
        open_oml(target)
        time.sleep(5)
        self.httpd.shutdown()

    def download(self, url, filename):
        dirname = os.path.dirname(filename)
        if dirname:
            makedirs(dirname)
        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)
                    f.write(data)
                    data = u.read(4096)

    def get_release(self):
        with closing(urlopen(self.release_url)) as u:
            data = json.loads(u.read().decode())
        return data

class Server(socketserver.ThreadingMixIn, socketserver.TCPServer):
    allow_reuse_address = True

class InstallServer(Thread):
    def __init__(self, target):
        self.target = target
        Thread.__init__(self)
        self.daemon = True
        self.start()

    def run(self):
        httpd = Server(("127.0.0.1", PORT), Handler)
        install = Install(self.target, httpd)
        httpd.install = install
        httpd.serve_forever()

def open_oml(base):
    python = os.path.join(base, 'platform_win32', 'pythonw.exe')
    pid = os.path.join(base, 'data', 'openmedialibrary.pid')
    oml = os.path.join(base, 'openmedialibrary')
    subprocess.Popen([python, 'oml', 'server', pid], cwd=oml, start_new_session=True)

def run(target):
    return InstallServer(target)
