# Copyright (c) 2016 Google Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#     * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
#     * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import optparse
import logging
import sys

from webkitpy.tool.grammar import pluralize

_log = logging.getLogger(__name__)


class Command(object):
    # These class variables can be overridden in subclasses to set specific command behavior.
    name = None
    show_in_main_help = False
    help_text = None
    argument_names = None
    long_help = None

    def __init__(self, options=None, requires_local_commits=False):
        self.required_arguments = self._parse_required_arguments(self.argument_names)
        self.options = options
        self.requires_local_commits = requires_local_commits
        # option_parser can be overridden by the tool using set_option_parser
        # This default parser will be used for standalone_help printing.
        self.option_parser = HelpPrintingOptionParser(
            usage=optparse.SUPPRESS_USAGE,
            add_help_option=False,
            option_list=self.options)

    def _exit(self, code):
        sys.exit(code)

    # This design is slightly awkward, but we need the
    # the tool to be able to create and modify the option_parser
    # before it knows what Command to run.
    def set_option_parser(self, option_parser):
        self.option_parser = option_parser
        self._add_options_to_parser()

    def _add_options_to_parser(self):
        options = self.options or []
        for option in options:
            self.option_parser.add_option(option)

    @staticmethod
    def _parse_required_arguments(argument_names):
        required_args = []
        if not argument_names:
            return required_args
        split_args = argument_names.split(' ')
        for argument in split_args:
            if argument[0] == '[':
                # For now our parser is rather dumb.  Do some minimal validation that
                # we haven't confused it.
                if argument[-1] != ']':
                    raise Exception('Failure to parse argument string %s.  Argument %s is missing ending ]' %
                                    (argument_names, argument))
            else:
                required_args.append(argument)
        return required_args

    def name_with_arguments(self):
        usage_string = self.name
        if self.options:
            usage_string += ' [options]'
        if self.argument_names:
            usage_string += ' ' + self.argument_names
        return usage_string

    def parse_args(self, args):
        return self.option_parser.parse_args(args)

    def check_arguments_and_execute(self, options, args, tool=None):
        if len(args) < len(self.required_arguments):
            _log.error("%s required, %s provided.  Provided: %s  Required: %s\nSee '%s help %s' for usage.",
                       pluralize('argument', len(self.required_arguments)),
                       pluralize('argument', len(args)),
                       "'%s'" % ' '.join(args),
                       ' '.join(self.required_arguments),
                       tool.name(),
                       self.name)
            return 1
        return self.execute(options, args, tool) or 0

    def standalone_help(self):
        help_text = self.name_with_arguments().ljust(len(self.name_with_arguments()) + 3) + self.help_text + '\n\n'
        if self.long_help:
            help_text += '%s\n\n' % self.long_help
        help_text += self.option_parser.format_option_help(optparse.IndentedHelpFormatter())
        return help_text

    def execute(self, options, args, tool):
        raise NotImplementedError('subclasses must implement')

    # main() exists so that Commands can be turned into stand-alone scripts.
    # Other parts of the code will likely require modification to work stand-alone.
    def main(self, args=None):
        options, args = self.parse_args(args)
        # Some commands might require a dummy tool
        return self.check_arguments_and_execute(options, args)


class HelpPrintingOptionParser(optparse.OptionParser):

    def __init__(self, epilog_method=None, *args, **kwargs):
        self.epilog_method = epilog_method
        optparse.OptionParser.__init__(self, *args, **kwargs)

    def error(self, msg):
        self.print_usage(sys.stderr)
        error_message = '%s: error: %s\n' % (self.get_prog_name(), msg)
        # This method is overridden to add this one line to the output:
        error_message += '\nType \'%s --help\' to see usage.\n' % self.get_prog_name()
        self.exit(1, error_message)

    # We override format_epilog to avoid the default formatting which would paragraph-wrap the epilog
    # and also to allow us to compute the epilog lazily instead of in the constructor (allowing it to be context sensitive).
    def format_epilog(self, epilog):  # pylint: disable=unused-argument
        if self.epilog_method:
            return '\n%s\n' % self.epilog_method()
        return ''
