# Copyright 2014 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 fnmatch
import imp
import logging
import modulefinder
import optparse
import os
import sys
import zipfile

from telemetry import benchmark
from telemetry.core import command_line
from telemetry.core import discover
from telemetry.core import util
from telemetry.page import cloud_storage
from telemetry.util import bootstrap
from telemetry.util import path_set


DEPS_FILE = 'bootstrap_deps'


def _InDirectory(subdirectory, directory):
  subdirectory = os.path.realpath(subdirectory)
  directory = os.path.realpath(directory)
  common_prefix = os.path.commonprefix([subdirectory, directory])
  return common_prefix == directory


def FindBootstrapDependencies(base_dir):
  deps_file = os.path.join(base_dir, DEPS_FILE)
  if not os.path.exists(deps_file):
    return []
  deps_paths = bootstrap.ListAllDepsPaths(deps_file)
  return set(
      os.path.realpath(os.path.join(util.GetChromiumSrcDir(), os.pardir, path))
      for path in deps_paths)


def FindPythonDependencies(module_path):
  logging.info('Finding Python dependencies of %s' % module_path)

  # Load the module to inherit its sys.path modifications.
  imp.load_source(
      os.path.splitext(os.path.basename(module_path))[0], module_path)

  # Analyze the module for its imports.
  finder = modulefinder.ModuleFinder()
  finder.run_script(module_path)

  # Filter for only imports in Chromium.
  for module in finder.modules.itervalues():
    # If it's an __init__.py, module.__path__ gives the package's folder.
    module_path = module.__path__[0] if module.__path__ else module.__file__
    if not module_path:
      continue

    module_path = os.path.realpath(module_path)
    if not _InDirectory(module_path, util.GetChromiumSrcDir()):
      continue

    yield module_path


def FindPageSetDependencies(base_dir):
  logging.info('Finding page sets in %s' % base_dir)

  # Add base_dir to path so our imports relative to base_dir will work.
  sys.path.append(base_dir)
  tests = discover.DiscoverClasses(base_dir, base_dir, benchmark.Benchmark,
                                   index_by_class_name=True)

  for test_class in tests.itervalues():
    test_obj = test_class()

    # Ensure the test's default options are set if needed.
    parser = optparse.OptionParser()
    test_obj.AddCommandLineArgs(parser)
    options = optparse.Values()
    for k, v in parser.get_default_values().__dict__.iteritems():
      options.ensure_value(k, v)

    # Page set paths are relative to their runner script, not relative to us.
    util.GetBaseDir = lambda: base_dir
    # TODO: Loading the page set will automatically download its Cloud Storage
    # deps. This is really expensive, and we don't want to do this by default.
    page_set = test_obj.CreatePageSet(options)

    # Add all of its serving_dirs as dependencies.
    for serving_dir in page_set.serving_dirs:
      yield serving_dir
    for page in page_set:
      if page.is_file:
        yield page.serving_dir


def FindExcludedFiles(files, options):
  def MatchesConditions(path, conditions):
    for condition in conditions:
      if condition(path):
        return True
    return False

  # Define some filters for files.
  def IsHidden(path):
    for pathname_component in path.split(os.sep):
      if pathname_component.startswith('.'):
        return True
    return False
  def IsPyc(path):
    return os.path.splitext(path)[1] == '.pyc'
  def IsInCloudStorage(path):
    return os.path.exists(path + '.sha1')
  def MatchesExcludeOptions(path):
    for pattern in options.exclude: