#!/usr/bin/python
import sys
sys.path.insert(0, "/usr/lib/entropy/lib")
sys.path.insert(0, "/usr/lib/entropy/client")
sys.path.insert(0, "../lib")
sys.path.insert(0, "../client")

import os
import argparse

from entropy.locks import EntropyResourcesLock
from entropy.output import brown, print_warning, print_error, teal
from entropy.i18n import _
from entropy.client.interfaces import Client
import entropy.dep
import entropy.tools

from solo.commands.install import SoloInstall
from solo.utils import print_package_info

import kswitch


if __name__ == "__main__":

    app_name = os.path.basename(sys.argv[0])
    parser = argparse.ArgumentParser(
        description=_("Sabayon Kernel Switcher"),
        formatter_class=argparse.RawDescriptionHelpFormatter,
        prog=app_name)

    def _add_standard_args(_parser, restricted):
        _parser.add_argument("--quiet", "-q", action="store_true",
                            default=False,
                            help=_("quiet mode"))
        _parser.add_argument("--verbose", "-v", action="store_true",
                            default=False,
                            help=_("verbose mode"))
        if not restricted:
            _parser.add_argument("--ask", "-a", action="store_true",
                                 default=False,
                                 help=_("ask confirmation"))
            _parser.add_argument("--pretend", "-p", action="store_true",
                                 default=False,
                                 help=_("just show what would be done"))

    subparsers = parser.add_subparsers(
        title="kernel-switcher",
        description=_("available commands"))

    def _wrap_locked_api(method, *args, **kwargs):
        etp_client = None
        acquired = False
        lock = EntropyResourcesLock(output=Client)
        try:
            lock.acquire_shared()
            acquired = True

            etp_client = Client()

            return method(etp_client, *args, **kwargs)
        finally:
            if etp_client is not None:
                etp_client.shutdown()
            if acquired:
                lock.release()

    def _switch_kernel(f_nsargs):

        def _install(etp_client, matches):
            install = SoloInstall([])
            inst_rc, _show_cfgupd = install._install_action(
                etp_client, True, True,
                f_nsargs.pretend, f_nsargs.ask, f_nsargs.verbose,
                f_nsargs.quiet, False, False, False, False, False,
                False, False, 1, [], package_matches=list(matches))
            if _show_cfgupd:
                install._show_config_files_update(etp_client)
                install._show_preserved_libraries(etp_client)
            if f_nsargs.pretend:
                # this won't trigger any post install action
                return 1
            return inst_rc

        def _switch(etp_client):
            switcher = kswitch.KernelSwitcher(etp_client)
            kernel_package = f_nsargs.kernel

            pkg_id, pkg_repo = etp_client.atom_match(kernel_package)
            if pkg_id == -1:
                print_error("%s: %s" % (
                        brown(_("Package does not exist")),
                        teal(kernel_package),))
                return 1

            kernel_match = (pkg_id, pkg_repo)
            kernel_matches = switcher.list()
            if kernel_match not in kernel_matches:
                print_error(
                    "%s: %s" % (brown(_("Not a kernel")),
                                teal(kernel_package),))
                return 1

            try:
                return switcher.switch(
                    kernel_match, _install,
                    from_running=f_nsargs.from_running)
            except kswitch.CannotFindRunningKernel:
                print_error(
                    brown(_("Cannot find your currently running kernel.")))
                print_error(
                    brown(_("Try without --from-running.")))
                return 1

        if not entropy.tools.is_root():
            print_error(
                brown(_("superuser access required")))
            return 1
        return _wrap_locked_api(_switch)

    def _list_kernels(f_nsargs):

        def _list(etp_client):
            switcher = kswitch.KernelSwitcher(etp_client)
            kernels = switcher.list()
            if not kernels:
                print_warning(_("No kernel packages found"))
                return 1

            inst_repo = etp_client.installed_repository()
            with inst_repo.shared():
                for pkg_id, pkg_repo in kernels:

                    repo = etp_client.open_repository(pkg_repo)
                    print_package_info(
                        pkg_id, etp_client, repo,
                        show_repo_if_quiet = True,
                        extended=f_nsargs.verbose,
                        quiet=f_nsargs.quiet)
            return 0

        return _wrap_locked_api(_list)

    switch_parser = subparsers.add_parser(
        "switch", help=_("install a new or just another kernel"))
    switch_parser.set_defaults(func=_switch_kernel)
    switch_parser.add_argument(
        "--from-running", action="store_true",
        default=False,
        help=_("use 'uname -r' to determine the running kernel"))
    switch_parser.add_argument(
        "kernel", metavar="<kernel>",
        help=_("the new kernel package dependency name"))
    _add_standard_args(switch_parser, False)

    list_parser = subparsers.add_parser(
        "list", help=_("list kernels"))
    list_parser.set_defaults(func=_list_kernels)
    _add_standard_args(list_parser, True)

    help_parser = subparsers.add_parser(
        "help", help=_("this help"))
    def _print_help(*_args):
        parser.print_help()
    help_parser.set_defaults(func=_print_help)

    try:
        nsargs = parser.parse_args(sys.argv[1:])
    except IOError as err:
        parser.print_help()
        raise SystemExit(1)

    # Python 3.3 bug #16308
    if not hasattr(nsargs, "func"):
        parser.print_help()
        raise SystemExit(1)

    try:
        rc = nsargs.func(nsargs)
    except KeyboardInterrupt:
        rc = 1
    raise SystemExit(rc)
