#!/usr/bin/env python2

import sys
import argparse
import zipfile
import tempfile
from shutil import rmtree, move
from os import listdir, getcwd, chdir, makedirs
from os.path import join, realpath, exists, isdir, expanduser

try:
    from cStringIO import StringIO
except ImportError:
    from StringIO import StringIO

try:
    import requests
except ImportError:
    print 'Garden tool require requests library.'
    print 'Try to "pip install requests" in root'
    sys.exit(1)


garden_system_dir = join(expanduser('~'), '.kivy', 'garden')
garden_app_dir = join(realpath(getcwd()), 'libs', 'garden')


class GardenTool(object):
    '''Garden command-line tool.
    '''

    def main(self, argv):
        parser = argparse.ArgumentParser(description=self.__doc__)
        subparsers = parser.add_subparsers()

        p = subparsers.add_parser('list',
                help='List all the installed garden packages')
        p.add_argument('--app', action='store_true',
                help='Use the local app directory (./libs/garden)')
        p.set_defaults(func=self.cmd_list)

        p = subparsers.add_parser('search',
                help='Search garden package on github')
        p.add_argument('pattern', nargs='?', default='',
                help='Word to search in the package name (optional)')
        p.set_defaults(func=self.cmd_search)

        p = subparsers.add_parser('install',
                help='Install a garden package')
        p.add_argument('--app', action='store_true',
                help='Install in the local app directory (./libs/garden)')
        p.add_argument('--upgrade', action='store_true',
                help='Force the installation')
        p.add_argument('package', nargs=1,
                help='Name of the package to install')
        p.set_defaults(func=self.cmd_install)

        p = subparsers.add_parser('uninstall',
                help='Uninstall a garden package')
        p.add_argument('--app', action='store_true',
                help='Use the local app directory (./libs/garden)')
        p.add_argument('package', nargs=1,
                help='Name of the package to uninstall')
        p.set_defaults(func=self.cmd_uninstall)

        self.options = options = parser.parse_args(argv)

        options.func()

    def cmd_list(self):
        directory = garden_app_dir if self.options.app else garden_system_dir
        if not exists(directory):
            return

        for filename in listdir(directory):
            fullname = join(directory, filename)
            if filename.startswith('garden.') and isdir(fullname):
                print filename.split('.', 1)[-1]

    def cmd_search(self):
        r = requests.get('https://api.github.com/users/kivy-garden/repos')
        pattern = self.options.pattern
        data = r.json()
        for repo in data:
            if not repo['name'].startswith('garden.'):
                continue
            name = repo['name'].split('.', 1)[-1]
            if pattern and pattern not in name:
                continue
            print name, '-', repo['description'].splitlines()[0]

    def cmd_install(self):
        opts = self.options
        opts.package = self.gardenify(opts.package[0])

        garden_dir = garden_app_dir if self.options.app else garden_system_dir
        dest_dir = join(garden_dir, opts.package)

        if exists(dest_dir) and not opts.upgrade:
            print 'Garden package already installed in {}'.format(dest_dir)
            print 'Use --upgrade to upgrade.'
            sys.exit(0)

        fd = self.download(opts.package)
        tempdir = tempfile.mkdtemp(prefix='garden-')
        try:
            self.extract(fd, tempdir)

            if not exists(garden_dir):
                makedirs(garden_dir)

            if exists(dest_dir):
                print 'Removing old version...'
                rmtree(dest_dir)

            source_directory = join(tempdir, '{}-master'.format(opts.package))

            print 'Installing new version...'
            move(source_directory, dest_dir)

            print 'Done! {} is installed at: {}'.format(opts.package,
                    dest_dir)

        finally:
            print 'Cleaning...'
            if exists(tempdir):
                rmtree(tempdir, ignore_errors=True)

    def cmd_uninstall(self):
        opts = self.options
        opts.package = self.gardenify(opts.package[0])
        garden_dir = garden_app_dir if self.options.app else garden_system_dir
        d = join(garden_dir, opts.package)
        if not exists(d):
            print 'Package {} not installed, nothing to uninstall.'.format(
                    opts.package)
            sys.exit(0)

        print 'Deleting {}...'.format(d)
        rmtree(d)


    def gardenify(self, package):
        if not package.startswith('garden.'):
            return 'garden.' + package
        return package

    def download(self, package):
        url = 'http://github.com/kivy-garden/{}/archive/master.zip'.format(
                package)

        print 'Downloading {} ...'.format(url)
        r = requests.get(url)#, prefetch=False)
        if r.status_code != 200:
            print 'Unable to found the garden package. (error={})'.format(
                r.status_code)
            sys.exit(1)

        animation = '\\|/-'
        index = 0
        count = 0
        data = ''
        for buf in r.iter_content(1024):
            index += 1
            data += buf
            count += len(buf)
            print 'Progression', count, animation[index % len(animation)], '\r',
            sys.stdout.flush()
        print 'Download done ({} downloaded)'.format(count)

        return StringIO(data)

    def extract(self, fd, directory):
        print 'Extracting...'
        z = zipfile.ZipFile(fd)
        curdir = getcwd()
        chdir(directory)
        z.extractall()
        chdir(curdir)



if __name__ == '__main__':
    GardenTool().main(sys.argv[1:])

