#!/usr/bin/python
"""Provides a command-line interface to install and update PND applications."""

import os.path
from optparse import OptionParser, SUPPRESS_HELP
from pndstore_core import options

parser = OptionParser(usage='Usage: %prog [options] [package id(s)]')

parser.add_option('--working-dir', '-w',
    dest='working_dir', default=None,
    metavar='DIRECTORY', help=
        'find/store config and database in DIRECTORY [default: %s]'
        % options.working_dir)

parser.add_option('--update', '-y',
    action='store_true', dest='update', default=False,
    help='update both local and remote databases')
parser.add_option('--update-remote', '-Y',
    action='store_true', dest='update_remote', default=False,
    help='update database of remotely available applications')
parser.add_option('--update-local',
    action='store_true', dest='update_local', default=False,
    help='update database of locally installed applications')

parser.add_option('--install', '-i',
    dest='install', default=False,
    metavar='DIRECTORY', help='install PND by package ID to DIRECTORY')
parser.add_option('--list-upgrades', '',
    dest='list_upgrades', default=None, metavar='FIELDS',
    help='list packages with newer versions available; FIELDS may be id, version-installed, version-available, apps, or any comma-separated combination thereof')
parser.add_option('--upgrade', '',
    action='store_true', dest='upgrade', default=False,
    help='upgrade locally-installed packages with the given package IDs')
parser.add_option('--upgrade-by-appid', '',
    action='store_true', dest='upgrade_by_appid', default=False,
    help='upgrade locally-installed packages containing the given application IDs.')
parser.add_option('--upgrade-all', '-u',
    action='store_true', dest='upgrade_all', default=False,
    help='upgrade local packages with latest available')

parser.add_option('--remove', '-R',
    action='store_true', dest='remove', default=False,
    help='remove PND by package ID')
parser.add_option('--remove-appdata', '-N',
    action='store_true', dest='remove_appdata', default=False,
    help='remove appdata directories by package ID')

parser.add_option('--noconfirm', '',
    action='store_false', dest='confirm', default=True,
    help='perform actions without requesting confirmation')

opts, args = parser.parse_args()

# Check for bad option combinations.
if opts.install and opts.remove:
    parser.error("Cannot simultaneously install and remove packages.")
if opts.remove_appdata:
    parser.error("Sorry, appdata removal hasn't been implemented yet.")

if opts.working_dir is not None:
    options.working_dir = opts.working_dir

from pndstore_core import database_update, packages

if opts.update:
    opts.update_remote = True
    opts.update_local = True
if opts.update_local:
    print "Updating local database..."
    database_update.update_local()
    print "Done."
if opts.update_remote:
    print "Updating remote database..."
    database_update.update_remote()
    print "Done."

if opts.install:
    for p in set(map(packages.Package, args)):
        print "Installing %s..." % p.id
        p.install(opts.install)
        print "Done."

if opts.remove_appdata:
    # This must come before remove so the Package objects can be created.
    for p in set(map(packages.Package, args)):
        print "Removing all appdatas of %s..." % p.id
        p.remove_appdatas()
        print "Done."
if opts.remove:
    for p in set(map(packages.Package, args)):
        print "Removing %s..." % p.id
        p.remove()
        print "Done."

if opts.list_upgrades:
    upgrades = packages.get_updates()
    fields = {
        'id': lambda p: p.id,
        'version-installed': lambda p: p.local.db_entry['version'],
        'version-available': lambda p: p.get_latest_remote().db_entry['version'],
        'apps': lambda p: p.local.db_entry['applications'],
    }
    print '\n'.join( (' '.join(
        (fields[i](pkg) for i in opts.list_upgrades.split(',')) )
        for pkg in upgrades) )

if opts.upgrade:
    for p in set(map(packages.Package, args)):
        print "Upgrading %s..." % p.id
        p.upgrade()
        print "Done."
if opts.upgrade_by_appid:
    ps = set()
    for i in args:
        ps.update(packages.search_local_packages('applications', i))
    for p in ps:
        print "Upgrading %s..." % p.id
        p.upgrade()
        print "Done."

if opts.upgrade_all:
    # Comes after removal so unwanted packages are not upgraded just to be removed.
    upgrades = packages.get_updates()
    if upgrades:
        print "Packages to be upgraded:"
        for pkg in upgrades:
            print pkg.id, str(pkg.local.version), '->', str(pkg.get_latest().version)

        if opts.confirm: cont = raw_input("Continue upgrade? [Y/n]")
        else: cont = 'Y'
        if cont in ('', 'Y', 'y'):
            for pkg in upgrades:
                print "Upgrading %s..." % pkg.id
                pkg.upgrade()
                print "Done."

    else: print "No upgrades available."
