#!/usr/bin/env python

import os
from os import makedirs
import shutil
import sys
import urllib
import urlparse
import tempfile
import tarfile
import zipfile
from os.path import basename, join, isdir, exists, split, splitext
import argparse

def remove(path):
    if exists(path):
        if isdir(path):
            shutil.rmtree(path)
        else:
            os.remove(path)

def copy_dir(src, to):
    path, folder_name = split(src)
    target = join(to, folder_name)
    if exists(target):
        shutil.rmtree(target)
    shutil.copytree(src, target)

def unpack_whl(whl_path):
    unpack_root_dir = tempfile.mkdtemp()
    whl_dir, whl_filename = split(whl_path)
    whl_parts = whl_filename.split('-')
    unpack_dir_name = '%s-%s' % (whl_parts[0], whl_parts[1])
    unpack_dir = join(unpack_root_dir, unpack_dir_name)
    makedirs(unpack_dir)
    with zipfile.ZipFile(whl_path, "r") as z:
        z.extractall(unpack_dir)
    for item in os.listdir(unpack_dir):
        path = join(unpack_dir, item)
        if isdir(path) and item.endswith('.dist-info'):
            remove(path)
    return unpack_dir

def unpack_targz(targz_path):
    unpack_dir = tempfile.mkdtemp()
    tarfile.open(targz_path).extractall(unpack_dir)
    subdirs = os.listdir(unpack_dir)
    if len(subdirs) != 1:
        raise Exception('Package %s is expected to contain one folder inside' % targz_path)
    subdir = subdirs[0]
    package_dir = join(unpack_dir, subdir)
    for item in os.listdir(package_dir):
        path = join(package_dir, item)
        if isdir(path):
            if item.endswith('.egg-info') or item in ['docs', 'tests', 'test']:
                remove(path)
        else:
            item_name, item_ext = os.path.splitext(item)
            if item == 'setup.py' or item_ext not in ['.py', '.pyc', 'pyo', '.pyd', '.dll', '.so']:
                remove(path)
    return package_dir

def get_unpack_function(filename):
    unpack_function = None
    if filename.endswith('.whl'):
        unpack_function = unpack_whl
    if filename.endswith('.tar.gz'):
        unpack_function = unpack_targz
    if unpack_function is None:
        raise Exception('Unknown package type %s' % filename)
    return unpack_function

def download_package(download_dir, package_url):
    filename = basename(urlparse.urlparse(package_url).path)
    download_path = join(download_dir, filename)
    if not exists(download_path):
        urllib.urlretrieve(package_url, filename=download_path)
    return download_path

def get_package_filename(download_dir, package_url_or_path):
    if exists(package_url_or_path):
        return package_url_or_path
    else:
        return download_package(download_dir, package_url_or_path)

def get_parser():
    parser = argparse.ArgumentParser(description='Python Package Copy Installer')
    parser.add_argument('url', help='Package url')
    parser.add_argument('--to', help='Output folder, current working directory by default', default=os.getcwd())
    return parser

if __name__=='__main__':
    parser = get_parser()
    args = parser.parse_args()

    download_dir = join(tempfile.gettempdir(), 'coin.cache')
    if not exists(download_dir):
        makedirs(download_dir)

    package_path = args.url
    if not exists(package_path):
        package_path = download_package(download_dir, args.url)
    print('Package file: %s' % package_path)

    path, filename = split(package_path)

    unpack = get_unpack_function(filename)

    unpack_dir = unpack(package_path)
    print("Unpacked to: %s" % unpack_dir)

    install_to = args.to
    copy_dir(unpack_dir, install_to)
    print("Copied to: %s" % install_to)

