#!/usr/bin/python3
'''download-click: download click apps'''
#
#  Copyright (C) 2013 Canonical Ltd.
#
#  This program is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; version 3 of the License.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <http://www.gnu.org/licenses/>.

import urllib.request
import optparse
import os
import shutil
import simplejson
import sys
import time

from clickreviews import common

top_url = "https://search.apps.ubuntu.com"


def get_store_json(url):
    '''Download json from the store and turn it into a python obj'''
    req = urllib.request.Request(url)
    opener = urllib.request.build_opener()
    f = opener.open(req)
    obj = simplejson.load(f)
    return obj


def download(entry, download_dir=None):
    '''Download a click app'''
    if 'resource_url' not in entry:
        common.error("Could not find 'resource_url' in:\n%s" % entry)
    resource_url = top_url + entry['resource_url']

    res = get_store_json(resource_url)
    if 'download_url' not in res:
        common.error("Could not find 'download_url' in:\n%s" % res)
    download_url = res['download_url']

    if download_dir is None:
        download_dir = os.getcwd()
    elif not os.path.exists(download_dir):
        os.mkdir(download_dir)

    fn = os.path.join(download_dir, download_url.split('/')[-1])
    if os.path.exists(fn):
        common.warn("'%s' already exists, skipping" % os.path.basename(fn))
        return True
    common.msg("Downloading %s" % os.path.basename(fn))
    # FIXME: on 2013-10-15 this will break
    url = download_url + "?noauth=1"
    common.msg("-- Downloading %s" % url)

    #  attempt to deal with intermittent failures
    count = 0
    max_tries = 10
    result = False
    err_str = ""
    while not result and count < max_tries:
        try:
            (tmp, headers) = urllib.request.urlretrieve(url)
            shutil.move(tmp, fn)
            result = True
            common.msg("-- Success!")
        except urllib.error.HTTPError as error:
            err_str = "-- urlretrieve() failed: %d: %s" % (error.code,
                                                           error.reason)
            count += 1
            time.sleep(5)
    if not result:
        common.warn("%s (tried %d times)" % (err_str, max_tries))
    return result

if __name__ == "__main__":
    parser = optparse.OptionParser()
    parser.add_option("--all",
                      help="Download all published apps",
                      action='store_true',
                      default=False)
    parser.add_option("-d", "--download-dir",
                      dest="download_dir",
                      help="Specifiy download directory",
                      metavar="DIR",
                      default=None)
    (opt, args) = parser.parse_args()

    if not opt.all and len(args) < 1:
        common.error("%s --all|<pkgname>" % os.path.basename(sys.argv[0]))

    url = top_url + "/api/v1/search?q="
    items = get_store_json(url)
    if not isinstance(items, list):
        common.error("Didn't get valid result from: %s" % url)

    errors = False
    if opt.all:
        for entry in items:
            if not download(entry, opt.download_dir):
                errors = True
    else:
        for pkgname in args:
            entry = None
            for i in items:
                if i['name'] == pkgname:
                    entry = i
                    break

            if not entry:
                common.warn("Could not find '%s', skipping" % pkgname)
                continue

            if not download(entry, opt.download_dir):
                errors = True
    if errors:
        common.error("problem downloading")
