# Copyright (c) 2012 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.
"""Finds browsers that can be controlled by telemetry."""

import logging

from telemetry.core.backends.webdriver import webdriver_desktop_browser_finder
from telemetry.core.backends.chrome import android_browser_finder
from telemetry.core.backends.chrome import cros_browser_finder
from telemetry.core.backends.chrome import desktop_browser_finder

BROWSER_FINDERS = [
  desktop_browser_finder,
  android_browser_finder,
  cros_browser_finder,
  webdriver_desktop_browser_finder,
  ]

ALL_BROWSER_TYPES = ','.join([bf.ALL_BROWSER_TYPES for bf in BROWSER_FINDERS])


class BrowserTypeRequiredException(Exception):
  pass

class BrowserFinderException(Exception):
  pass

def FindBrowser(options):
  """Finds the best PossibleBrowser object to run given the provided
  BrowserOptions object. The returned possiblity object can then be used to
  connect to and control the located browser. A BrowserFinderException will
  be raised if the BrowserOptions argument is improperly set or if an error
  occurs when finding a browser.
  """
  if options.browser_type == 'exact' and options.browser_executable == None:
    raise BrowserFinderException(
        '--browser=exact requires --browser-executable to be set.')
  if options.browser_type != 'exact' and options.browser_executable != None:
    raise BrowserFinderException(
        '--browser-executable requires --browser=exact.')

  if options.browser_type == 'cros-chrome' and options.cros_remote == None:
    raise BrowserFinderException(
        'browser_type=cros-chrome requires cros_remote be set.')
  if (options.browser_type != 'cros-chrome' and
      options.browser_type != 'cros-chrome-guest' and
      options.cros_remote != None):
    raise BrowserFinderException(
        '--remote requires --browser=cros-chrome or cros-chrome-guest.')

  browsers = []
  default_browsers = []
  for finder in BROWSER_FINDERS:
    curr_browsers = finder.FindAllAvailableBrowsers(options)
    new_default_browser = finder.SelectDefaultBrowser(curr_browsers)
    if new_default_browser:
      default_browsers.append(new_default_browser)
    browsers.extend(curr_browsers)

  if options.browser_type == None:
    if default_browsers:
      default_browser = sorted(default_browsers,
                               key=lambda b: b.last_modification_time())[-1]

      logging.warning('--browser omitted. Using most recent local build: %s' %
                      default_browser.browser_type)
      options.browser_type = default_browser.browser_type
      # TODO: We should do this even when --browser is specified.
      default_browser.UpdateExecutableIfNeeded()
      return default_browser
    raise BrowserTypeRequiredException(
        '--browser must be specified. Available browsers:\n%s' %
        '\n'.join(sorted(set([b.browser_type for b in browsers]))))

  if options.browser_type == 'any':
    types = ALL_BROWSER_TYPES.split(',')
    def compare_browsers_on_type_priority(x, y):
      x_idx = types.index(x.browser_type)
      y_idx = types.index(y.browser_type)
      return x_idx - y_idx
    browsers.sort(compare_browsers_on_type_priority)
    if len(browsers) >= 1:
      return browsers[0]
    else:
      return None

  matching_browsers = [b for b in browsers
      if b.browser_type == options.browser_type and b.SupportsOptions(options)]

  chosen_browser = None
  if len(matching_browsers) == 1:
    chosen_browser = matching_browsers[0]
  elif len(matching_browsers) > 1:
    logging.warning('Multiple browsers of the same type found: %s' % (
                    repr(matching_browsers)))
    chosen_browser = sorted(matching_browsers,
                            key=lambda b: b.last_modification_time())[-1]

  if chosen_browser:
    logging.info('Chose browser: %s' % (repr(chosen_browser)))

  return chosen_browser

def GetAllAvailableBrowserTypes(options):
  """Returns an array of browser types supported on this system.
  A BrowserFinderException will be raised if the BrowserOptions argument is
  improperly set or if an error occurs when finding a browser.
  """
  browsers = []
  for finder in BROWSER_FINDERS:
    browsers.extend(finder.FindAllAvailableBrowsers(options))

  type_list = set([browser.browser_type for browser in browsers])
  type_list = list(type_list)
  type_list.sort()
  return type_list

@@ -159,16 +159,17 @@
 E file.%0A
+%0A
 %22%22%22Finds
@@ -782,16 +782,17 @@
   pass%0A%0A
+%0A
 class Br
@@ -832,16 +832,17 @@
   pass%0A%0A
+%0A
 def Find
@@ -906,230 +906,164 @@
 ect 
-to run given the provided%0A  BrowserOptions object. The returned possiblity object can then be used to%0A  connect to and control the located browser. A BrowserFinderException will%0A  be raised if the BrowserOptions argument i
+given a BrowserOptions object.%0A%0A  Args:%0A    A BrowserOptions object.%0A%0A  Returns:%0A    A PossibleBrowser object.%0A%0A  Raises:%0A    BrowserFinderException: Option
 s im
@@ -1074,31 +1074,29 @@
 erly set
+,
  or 
-if 
 an error
 %0A  occur
@@ -1091,40 +1091,17 @@
 rror
-%0A 
  occur
-s when finding a browser
+red
 .%0A  
@@ -2712,16 +2712,196 @@
 browser%0A
+%0A    if len(browsers) == 1:%0A      logging.warning('--browser omitted. Using only available browser: %25s' %25%0A                      browsers%5B0%5D.browser_type)%0A      return browsers%5B0%5D%0A%0A
     rais
@@ -3155,34 +3155,30 @@
 def 
-c
+C
 ompare
-_b
+B
 rowsers
-_on_type_p
+OnTypeP
 rior
@@ -3321,34 +3321,30 @@
 ort(
-c
+C
 ompare
-_b
+B
 rowsers
-_on_type_p
+OnTypeP
 rior
@@ -4037,16 +4037,17 @@
 rowser%0A%0A
+%0A
 def GetA
@@ -4098,136 +4098,187 @@
 ns a
-n array of browser types supported on this system.%0A  A BrowserFinderException will be raised if the BrowserOptions argument is%0A 
+ list of available browser types.%0A%0A  Args:%0A    options: A BrowserOptions object.%0A%0A  Returns:%0A    A list of browser type strings.%0A%0A  Raises:%0A    BrowserFinderException: Options are
  imp
@@ -4292,15 +4292,13 @@
  set
+,
  or 
-if 
 an e
@@ -4311,32 +4311,11 @@
 ccur
-s when finding a browser
+red
 .%0A  
@@ -4545,16 +4545,16 @@
 .sort()%0A
-
   return
@@ -4564,8 +4564,9 @@
 pe_list%0A
+%0A

Make browser finder use default browser if only one available.