#!/usr/bin/python

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:])

