# Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.

import errno
import os.path

from IPython.config.application import Application
from IPython.core.application import (
    BaseIPythonApplication, base_flags, base_aliases
)
from IPython.utils.traitlets import Instance, Dict, Unicode, Bool

from .kernelspec import KernelSpecManager, _pythonfirst

class ListKernelSpecs(BaseIPythonApplication):
    description = """List installed kernel specifications."""
    kernel_spec_manager = Instance(KernelSpecManager)

    # Not all of the base aliases are meaningful (e.g. profile)
    aliases = {k: base_aliases[k] for k in ['ipython-dir', 'log-level']}
    flags = {'debug': base_flags['debug'],}

    def _kernel_spec_manager_default(self):
        return KernelSpecManager(parent=self, ipython_dir=self.ipython_dir)

    def start(self):
        print("Available kernels:")
        for kernelname in sorted(self.kernel_spec_manager.find_kernel_specs(),
                                 key=_pythonfirst):
            print("  %s" % kernelname)


class InstallKernelSpec(BaseIPythonApplication):
    description = """Install a kernel specification directory."""
    kernel_spec_manager = Instance(KernelSpecManager)

    def _kernel_spec_manager_default(self):
        return KernelSpecManager(ipython_dir=self.ipython_dir)

    sourcedir = Unicode()
    kernel_name = Unicode("", config=True,
        help="Install the kernel spec with this name"
    )
    def _kernel_name_default(self):
        return os.path.basename(self.sourcedir)

    user = Bool(False, config=True,
        help="""
        Try to install the kernel spec to the per-user directory instead of
        the system or environment directory.
        """
    )
    replace = Bool(False, config=True,
        help="Replace any existing kernel spec with this name."
    )

    aliases = {'name': 'InstallKernelSpec.kernel_name'}
    for k in ['ipython-dir', 'log-level']:
        aliases[k] = base_aliases[k]

    flags = {'user': ({'InstallKernelSpec': {'user': True}},
                "Install to the per-user kernel registry"),
             'replace': ({'InstallKernelSpec': {'replace': True}},
                "Replace any existing kernel spec with this name."),
             'debug': base_flags['debug'],
            }

    def parse_command_line(self, argv):
        super(InstallKernelSpec, self).parse_command_line(argv)
        # accept positional arg as profile name
        if self.extra_args:
            self.sourcedir = self.extra_args[0]
        else:
            print("No source directory specified.")
            self.exit(1)

    def start(self):
        try:
            self.kernel_spec_manager.install_kernel_spec(self.sourcedir,
                                                 kernel_name=self.kernel_name,
                                                 user=self.user,
                                                 replace=self.replace,
                                                )
        except OSError as e:
            if e.errno == errno.EACCES:
                print("Permission denied")
                self.exit(1)
            elif e.errno == errno.EEXIST:
                print("A kernel spec is already present at %s" % e.filename)
                self.exit(1)
            raise

class InstallNativeKernelSpec(BaseIPythonApplication):
    description = """Install the native kernel spec directory for this Python."""
    kernel_spec_manager = Instance(KernelSpecManager)

    def _kernel_spec_manager_default(self):
        return KernelSpecManager(ipython_dir=self.ipython_dir)

    user = Bool(False, config=True,
        help="""
        Try to install the kernel spec to the per-user directory instead of
        the system or environment directory.
        """
    )

    # Not all of the base aliases are meaningful (e.g. profile)
    aliases = {k: base_aliases[k] for k in ['ipython-dir', 'log-level']}
    flags = {'user': ({'InstallNativeKernelSpec': {'user': True}},
                "Install to the per-user kernel registry"),
             'debug': base_flags['debug'],
            }

    def start(self):
        try:
            self.kernel_spec_manager.install_native_kernel_spec(user=self.user)
        except OSError as e:
            self.exit(e)

class KernelSpecApp(Application):
    name = "ipython kernelspec"
    description = """Manage IPython kernel specifications."""

    subcommands = Dict({
        'list': (ListKernelSpecs, ListKernelSpecs.description.splitlines()[0]),
        'install': (InstallKernelSpec, InstallKernelSpec.description.splitlines()[0]),
        'install-self': (InstallNativeKernelSpec, InstallNativeKernelSpec.description.splitlines()[0]),
    })

    aliases = {}
    flags = {}

    def start(self):
        if self.subapp is None:
            print("No subcommand specified. Must specify one of: %s"% list(self.subcommands))
            print()
            self.print_description()
            self.print_subcommands()
            self.exit(1)
        else:
            return self.subapp.start()