# Copyright (C) 2008 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import re
import sys
import textwrap

from color import Coloring
from command import MirrorSafeCommand
from command import PagedCommand
from error import RepoExitError
from subcmds import all_commands
from wrapper import Wrapper


class InvalidHelpCommand(RepoExitError):
    """Invalid command passed into help."""


class Help(PagedCommand, MirrorSafeCommand):
    COMMON = False
    helpSummary = "Display detailed help on a command"
    helpUsage = """
%prog [--all|command]
"""
    helpDescription = """
Displays detailed usage information about a command.
"""

    def _PrintCommands(self, commandNames):
        """Helper to display |commandNames| summaries."""
        maxlen = 0
        for name in commandNames:
            maxlen = max(maxlen, len(name))
        fmt = "  %%-%ds  %%s" % maxlen

        for name in commandNames:
            command = all_commands[name]()
            try:
                summary = command.helpSummary.strip()
            except AttributeError:
                summary = ""
            print(fmt % (name, summary))

    def _PrintAllCommands(self):
        print("usage: repo COMMAND [ARGS]")
        self.PrintAllCommandsBody()

    def PrintAllCommandsBody(self):
        print("The complete list of recognized repo commands is:")
        commandNames = list(sorted(all_commands))
        self._PrintCommands(commandNames)
        print(
            "See 'repo help <command>' for more information on a "
            "specific command."
        )
        print("Bug reports:", Wrapper().BUG_URL)

    def _PrintCommonCommands(self):
        print("usage: repo COMMAND [ARGS]")
        self.PrintCommonCommandsBody()

    def PrintCommonCommandsBody(self):
        print("The most commonly used repo commands are:")

        commandNames = list(
            sorted(
                name for name, command in all_commands.items() if command.COMMON
            )
        )
        self._PrintCommands(commandNames)

        print(
            "See 'repo help <command>' for more information on a specific "
            "command.\nSee 'repo help --all' for a complete list of recognized "
            "commands."
        )
        print("Bug reports:", Wrapper().BUG_URL)

    def _PrintCommandHelp(self, cmd, header_prefix=""):
        class _Out(Coloring):
            def __init__(self, gc):
                Coloring.__init__(self, gc, "help")
                self.heading = self.printer("heading", attr="bold")
                self._first = True

            def _PrintSection(self, heading, bodyAttr):
                try:
                    body = getattr(cmd, bodyAttr)
                except AttributeError:
                    return
                if body == "" or body is None:
                    return

                if not self._first:
                    self.nl()
                self._first = False

                self.heading("%s%s", header_prefix, heading)
                self.nl()
                self.nl()

                me = "repo %s" % cmd.NAME
                body = body.strip()
                body = body.replace("%prog", me)

                # Extract the title, but skip any trailing {#anchors}.
                asciidoc_hdr = re.compile(r"^\n?#+ ([^{]+)(\{#.+\})?$")
                for para in body.split("\n\n"):
                    if para.startswith(" "):
                        self.write("%s", para)
                        self.nl()
                        self.nl()
                        continue

                    m = asciidoc_hdr.match(para)
                    if m:
                        self.heading("%s%s", header_prefix, m.group(1))
                        self.nl()
                        self.nl()
                        continue

                    lines = textwrap.wrap(
                        para.replace("  ", " "),
                        width=80,
                        break_long_words=False,
                        break_on_hyphens=False,
                    )
                    for line in lines:
                        self.write("%s", line)
                        self.nl()
                    self.nl()

        out = _Out(self.client.globalConfig)
        out._PrintSection("Summary", "helpSummary")
        cmd.OptionParser.print_help()
        out._PrintSection("Description", "helpDescription")

    def _PrintAllCommandHelp(self):
        for name in sorted(all_commands):
            cmd = all_commands[name](manifest=self.manifest)
            self._PrintCommandHelp(cmd, header_prefix=f"[{name}] ")

    def _Options(self, p):
        p.add_option(
            "-a",
            "--all",
            dest="show_all",
            action="store_true",
            help="show the complete list of commands",
        )
        p.add_option(
            "--help-all",
            dest="show_all_help",
            action="store_true",
            help="show the --help of all commands",
        )

    def Execute(self, opt, args):
        if len(args) == 0:
            if opt.show_all_help:
                self._PrintAllCommandHelp()
            elif opt.show_all:
                self._PrintAllCommands()
            else:
                self._PrintCommonCommands()

        elif len(args) == 1:
            name = args[0]

            try:
                cmd = all_commands[name](manifest=self.manifest)
            except KeyError:
                print(
                    "repo: '%s' is not a repo command." % name, file=sys.stderr
                )
                raise InvalidHelpCommand(name)

            self._PrintCommandHelp(cmd)

        else:
            self._PrintCommandHelp(self)