# Copyright 2016 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import argparse
import os.path
import sys

_SRC_DIR = os.path.abspath(os.path.join(
    os.path.dirname(__file__), '..', '..', '..'))
sys.path.append(os.path.join(_SRC_DIR, 'build', 'android'))
from pylib import constants

class Options(object):
  """Global options repository.

  ParseArgs must be called before use. See _ARGS for common members, these will
  be available as instance attributes (eg, OPTIONS.clear_cache).
  """
  # Tuples of (argument name, default value, help string).
  _ARGS = [ ('chrome_package_name', 'chrome',
             'build/android/pylib/constants package description'),
            ('devtools_hostname', 'localhost',
             'hostname for devtools websocket connection'),
            ('devtools_port', 9222,
             'port for devtools websocket connection'),
            ('local_build_dir', None,
             'Build directory for local binary files such as chrome'),
            ('local_noisy', False,
             'Enable local chrome console output'),
            ('local_profile_dir', None,
             'profile directory to use for local runs'),
            ('no_sandbox', False,
             'pass --no-sandbox to browser (local run only; see also '
             'https://chromium.googlesource.com/chromium/src/+/master/'
             'docs/linux_suid_sandbox_development.md)'),
            ('devices_file', _SRC_DIR + '/third_party/WebKit/Source/devtools'
             '/front_end/emulated_devices/module.json', 'File containing a'
             ' list of emulated devices characteristics.')
          ]


  def __init__(self):
    self._arg_set = set()
    self._parsed_args = None

  def AddGlobalArgument(self, arg_name, default, help_str):
    """Add a global argument.

    Args:
      arg_name: the name of the argument. This will be used as an optional --
        argument.
      default: the default value for the argument. The type of this default will
        be used as the type of the argument.
      help_str: the argument help string.
    """
    self._ARGS.append((arg_name, default, help_str))

  def ParseArgs(self, arg_list, description=None, extra=None):
    """Parse command line arguments.

    Args:
      arg_list: command line argument list.
      description: description to use in argument parser.
      extra: additional required arguments to add. These will be exposed as
        instance attributes. This is either a list of extra arguments, or a
        single string or tuple. If a tuple, the first item is the argument and
        the second a default, otherwise the argument is required. Arguments are
        used as in argparse, ie those beginning with -- are named, and those
        without a dash are positional. Don't use a single dash.
    """
    parser = self._MakeParser(description, extra)
    self._parsed_args = parser.parse_args(arg_list)

  def ExtractArgs(self, arg_list):
    """Extract arguments from arg_str.

    Args:
      arg_list: command line argument list. It will be changed so that arguments
        used by this options instance are removed.
    """
    parser = self._MakeParser()
    (self._parsed_args, unused) = parser.parse_known_args(arg_list)
    del arg_list[:]
    arg_list.extend(unused)

  def GetParentParser(self, group_name='Global'):
    """Returns a parser suitable for passing in as a parent to argparse.

    Args:
      group_name: A group name for the parser (see argparse's
        add_argument_group).

    Returns:
      An argparse parser instance.
    """
    return self._MakeParser(group=group_name)

  def SetParsedArgs(self, parsed_args):
    """Set parsed args. Used with GetParentParser.

    Args:
      parsed_args: the result of argparse.parse_args or similar.
    """
    self._parsed_args = parsed_args

  def _MakeParser(self, description=None, extra=None, group=None):
    self._arg_set = set()
    add_help = True if group is None else False
    parser = argparse.ArgumentParser(
        description=description, add_help=add_help)
    container = parser if group is None else parser.add_argument_group(group)
    for arg, default, help_str in self._ARGS:
      # All global options are named.
      arg = '--' + arg
      self._AddArg(container, arg, default, help_str=help_str)
    if extra is not None:
      if type(extra) is not list:
        extra = [extra]
      for arg in extra:
        if type(arg) is tuple:
          argname, default = arg
          self._AddArg(container, argname, default)
        else:
          self._AddArg(container, arg, None, required=True)
    return parser

  def _AddArg(self, container, arg, default, required=False, help_str=None):
    assert not arg.startswith('-') or arg.startswith('--'), \
        "Single dash arguments aren't supported: %s" % arg
    arg_name = arg
    if arg.startswith('--'):
      arg_name = arg[2:]
    assert arg_name not in self._arg_set, \
      '%s extra arg is a duplicate' % arg_name
    self._arg_set.add(arg_name)

    kwargs = {}
    if required and arg.startswith('--'):
      kwargs['required'] = required
    if help_str is not None:
      kwargs['help'] = help_str
    if default is not None:
      if type(default) is bool:
        # If the default of a switch is true, setting the flag stores false.
        if default:
          kwargs['action'] = 'store_false'
        else:
          kwargs['action'] = 'store_true'
      else:
        kwargs['default'] = default
        kwargs['type'] = type(default)

    container.add_argument(arg, **kwargs)

  def __getattr__(self, name):
    if name in self._arg_set:
      assert self._parsed_args, 'Option requested before ParseArgs called'
      return getattr(self._parsed_args, name)
    raise AttributeError(name)

  def ChromePackage(self):
    return constants.PACKAGE_INFO[self.chrome_package_name]

  def LocalBinary(self, binary_name):
    """Get local binary path from its name."""
    assert self.local_build_dir, '--local_build_dir needs to be set.'
    path = os.path.join(self.local_build_dir, binary_name)
    assert os.path.isfile(path), \
        'Missing binary file {} (wrong --local_build_dir?).'.format(path)
    return path


OPTIONS = Options()
