# Copyright 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.
import logging as real_logging
import os
import sys

from telemetry.core import discover
from telemetry.core import local_server
from telemetry.core import memory_cache_http_server
from telemetry.core import network_controller
from telemetry.core import tracing_controller
from telemetry.core import util
from telemetry.internal.platform import (platform_backend as
                                         platform_backend_module)

_host_platform = None
# Remote platform is a dictionary from device ids to remote platform instances.
_remote_platforms = {}


def _InitHostPlatformIfNeeded():
  global _host_platform
  if _host_platform:
    return
  backend = None
  backends = _IterAllPlatformBackendClasses()
  for platform_backend_class in backends:
    if platform_backend_class.IsPlatformBackendForHost():
      backend = platform_backend_class()
      break
  if not backend:
    raise NotImplementedError()
  _host_platform = Platform(backend)


def GetHostPlatform():
  _InitHostPlatformIfNeeded()
  return _host_platform


def _IterAllPlatformBackendClasses():
  platform_dir = os.path.dirname(os.path.realpath(
      platform_backend_module.__file__))
  return discover.DiscoverClasses(
      platform_dir, util.GetTelemetryDir(),
      platform_backend_module.PlatformBackend).itervalues()


def GetPlatformForDevice(device, finder_options, logging=real_logging):
  """ Returns a platform instance for the device.
    Args:
      device: a device.Device instance.
  """
  if device.guid in _remote_platforms:
    return _remote_platforms[device.guid]
  try:
    for platform_backend_class in _IterAllPlatformBackendClasses():
      if platform_backend_class.SupportsDevice(device):
        _remote_platforms[device.guid] = (
            platform_backend_class.CreatePlatformForDevice(device,
                                                           finder_options))
        return _remote_platforms[device.guid]
    return None
  except Exception:
    current_exception = sys.exc_info()
    logging.error('Fail to create platform instance for %s.', device.name)
    raise current_exception[0], current_exception[1], current_exception[2]


class Platform(object):
  """The platform that the target browser is running on.

  Provides a limited interface to interact with the platform itself, where
  possible. It's important to note that platforms may not provide a specific
  API, so check with IsFooBar() for availability.
  """

  def __init__(self, platform_backend):
    self._platform_backend = platform_backend
    self._platform_backend.InitPlatformBackend()
    self._platform_backend.SetPlatform(self)
    self._network_controller = network_controller.NetworkController(
        self._platform_backend.network_controller_backend)
    self._tracing_controller = tracing_controller.TracingController(
        self._platform_backend.tracing_controller_backend)
    self._local_server_controller = local_server.LocalServerController(
        self._platform_backend)
    self._is_monitoring_power = False

  @property
  def is_host_platform(self):
    return self == GetHostPlatform()

  @property
  def network_controller(self):
    """Control network settings and servers to simulate the Web."""
    return self._network_controller

  @property
  def tracing_controller(self):
    return self._tracing_controller

  def CanMonitorThermalThrottling(self):
    """Platforms may be able to detect thermal throttling.

    Some fan-less computers go into a reduced performance mode when their heat
    exceeds a certain threshold. Performance tests in particular should use this
    API to detect if this has happened and interpret results accordingly.
    """
    return self._platform_backend.CanMonitorThermalThrottling()

  def IsThermallyThrottled(self):
    """Returns True if the device is currently thermally throttled."""
    return self._platform_backend.IsThermallyThrottled()

  def HasBeenThermallyThrottled(self):
    """Returns True if the device has been thermally throttled."""
    return self._platform_backend.HasBeenThermallyThrottled()

  def GetDeviceTypeName(self):
    """Returns a string description of the Platform device, or None.

    Examples: Nexus 7, Nexus 6, Desktop"""
    return self._platform_backend.GetDeviceTypeName()

  def GetArchName(self):
    """Returns a string description of the Platform architecture.

    Examples: x86_64 (posix), AMD64 (win), armeabi-v7a, x86"""
    return self._platform_backend.GetArchName()

  def GetOSName(self):
    """Returns a string description of the Platform OS.

    Examples: WIN, MAC, LINUX, CHROMEOS"""
    return self._platform_backend.GetOSName()

  def GetOSVersionName(self):
    """Returns a logically sortable, string-like description of the Platform OS
    version.

    Examples: VISTA, WIN7, LION, MOUNTAINLION"""
    return self._platform_backend.GetOSVersionName()

  def GetOSVersionNumber(self):
    """Returns an integer description of the Platform OS major version.

    Examples: On Mac, 13 for Mavericks, 14 for Yosemite."""
    return self._platform_backend.GetOSVersionNumber()

  def GetSystemTotalPhysicalMemory(self):
    """Returns an integer with the total physical memory in bytes."""
    return self._platform_backend.GetSystemTotalPhysicalMemory()

  def CanFlushIndividualFilesFromSystemCache(self):
    """Returns true if the disk cache can be flushed for specific files."""
    return self._platform_backend.CanFlushIndividualFilesFromSystemCache()

  def SupportFlushEntireSystemCache(self):
    """Returns true if entire system cache can be flushed.

    Also checks that platform has required privilegues to flush system caches.
    """
    return self._platform_backend.SupportFlushEntireSystemCache()

  def FlushEntireSystemCache(self):
    """Flushes the OS's file cache completely.

    This function may require root or administrator access. Clients should
    call SupportFlushEntireSystemCache to check first.
    """
    return self._platform_backend.FlushEntireSystemCache()

  def FlushSystemCacheForDirectory(self, directory):
    """Flushes the OS's file cache for the specified directory.

    This function does not require root or administrator access."""
    return self._platform_backend.FlushSystemCacheForDirectory(directory)

  def FlushDnsCache(self):
    """Flushes the OS's DNS cache completely.

    This function may require root or administrator access."""
    return self._platform_backend.FlushDnsCache()

  def LaunchApplication(self,
                        application,
                        parameters=None,
                        elevate_privilege=False):
    """"Launches the given |application| with a list of |parameters| on the OS.

    Set |elevate_privilege| to launch the application with root or admin rights.

    Returns:
      A popen style process handle for host platforms.
    """
    return self._platform_backend.LaunchApplication(
        application,
        parameters,
        elevate_privilege=elevate_privilege)

  def IsApplicationRunning(self, application):
    """Returns whether an application is currently running."""
    return self._platform_backend.IsApplicationRunning(application)

  def CanLaunchApplication(self, application):
    """Returns whether the platform can launch the given application."""
    return self._platform_backend.CanLaunchApplication(application)

  def InstallApplication(self, application):
    """Installs the given application."""
    return self._platform_backend.InstallApplication(application)

  def CanCaptureVideo(self):
    """Returns a bool indicating whether the platform supports video capture."""
    return self._platform_backend.CanCaptureVideo()

  def StartVideoCapture(self, min_bitrate_mbps):
    """Starts capturing video.

    Outer framing may be included (from the OS, browser window, and webcam).

    Args:
      min_bitrate_mbps: The minimum capture bitrate in MegaBits Per Second.
          The platform is free to deliver a higher bitrate if it can do so
          without increasing overhead.

    Raises:
      ValueError if the required |min_bitrate_mbps| can't be achieved.
    """
    return self._platform_backend.StartVideoCapture(min_bitrate_mbps)

  def StopVideoCapture(self):
    """Stops capturing video.

    Returns:
      A telemetry.core.video.Video object.
    """
    return self._platform_backend.StopVideoCapture()

  def CanMonitorPower(self):
    """Returns True iff power can be monitored asynchronously via
    StartMonitoringPower() and StopMonitoringPower().
    """
    return self._platform_backend.CanMonitorPower()

  def CanMeasurePerApplicationPower(self):
    """Returns True if the power monitor can measure power for the target
    application in isolation. False if power measurement is for full system
    energy consumption."""
    return self._platform_backend.CanMeasurePerApplicationPower()

  def StartMonitoringPower(self, browser):
    """Starts monitoring power utilization statistics.

    Args:
      browser: The browser to monitor.
    """
    assert self._platform_backend.CanMonitorPower()
    self._platform_backend.StartMonitoringPower(browser)
    self._is_monitoring_power = True

  def StopMonitoringPower(self):
    """Stops monitoring power utilization and returns stats

    Returns:
      None if power measurement failed for some reason, otherwise a dict of
      power utilization statistics containing: {
        # An identifier for the data provider. Allows to evaluate the precision
        # of the data. Example values: monsoon, powermetrics, ds2784
        'identifier': identifier,

        # The instantaneous power (voltage * current) reading in milliwatts at
        # each sample.
        'power_samples_mw':  [mw0, mw1, ..., mwN],

        # The full system energy consumption during the sampling period in
        # milliwatt hours. May be estimated by integrating power samples or may
        # be exact on supported hardware.
        'energy_consumption_mwh': mwh,

        # The target application's energy consumption during the sampling period
        # in milliwatt hours. Should be returned iff
        # CanMeasurePerApplicationPower() return true.
        'application_energy_consumption_mwh': mwh,

        # A platform-specific dictionary of additional details about the
        # utilization of individual hardware components.
        component_utilization: {
          ...
        }
        # Platform-specific data not attributed to any particular hardware
        # component.
        platform_info: {

          # Device-specific onboard temperature sensor.
          'average_temperature_c': c,

           ...
        }

      }
    """
    ret_val = self._platform_backend.StopMonitoringPower()
    self._is_monitoring_power = False
    return ret_val

  def IsMonitoringPower(self):
    """Returns true if power is currently being monitored, false otherwise."""
    # TODO(rnephew): Remove when crbug.com/553601 is solved.
    real_logging.info('IsMonitoringPower: %s', self._is_monitoring_power)
    return self._is_monitoring_power

  def CanMonitorNetworkData(self):
    """Returns true if network data can be retrieved, false otherwise."""
    return self._platform_backend.CanMonitorNetworkData()

  def GetNetworkData(self, browser):
    """Get current network data.
    Returns:
      Tuple of (sent_data, received_data) in kb if data can be found,
      None otherwise.
    """
    assert browser.platform == self
    return self._platform_backend.GetNetworkData(browser)

  def IsCooperativeShutdownSupported(self):
    """Indicates whether CooperativelyShutdown, below, is supported.
    It is not necessary to implement it on all platforms."""
    return self._platform_backend.IsCooperativeShutdownSupported()

  def CooperativelyShutdown(self, proc, app_name):
    """Cooperatively shut down the given process from subprocess.Popen.

    Currently this is only implemented on Windows. See
    crbug.com/424024 for background on why it was added.

    Args:
      proc: a process object returned from subprocess.Popen.
      app_name: on Windows, is the prefix of the application's window
          class name that should be searched for. This helps ensure
          that only the application's windows are closed.

    Returns True if it is believed the attempt succeeded.
    """
    return self._platform_backend.CooperativelyShutdown(proc, app_name)

  def CanTakeScreenshot(self):
    return self._platform_backend.CanTakeScreenshot()

  # TODO(nednguyen): Implement this on Mac, Linux & Win. (crbug.com/369490)
  def TakeScreenshot(self, file_path):
    """ Takes a screenshot of the platform and save to |file_path|.

    Note that this method may not be supported on all platform, so check with
    CanTakeScreenshot before calling this.

    Args:
      file_path: Where to save the screenshot to. If the platform is remote,
        |file_path| is the path on the host platform.

    Returns True if it is believed the attempt succeeded.
    """
    return self._platform_backend.TakeScreenshot(file_path)

  def StartLocalServer(self, server):
    """Starts a LocalServer and associates it with this platform.
    |server.Close()| should be called manually to close the started server.
    """
    self._local_server_controller.StartServer(server)

  @property
  def http_server(self):
    return self._local_server_controller.GetRunningServer(
        memory_cache_http_server.MemoryCacheHTTPServer, None)

  def SetHTTPServerDirectories(self, paths):
    """Returns True if the HTTP server was started, False otherwise."""
    if isinstance(paths, basestring):
      paths = set([paths])
    paths = set(os.path.realpath(p) for p in paths)

    # If any path is in a subdirectory of another, remove the subdirectory.
    duplicates = set()
    for parent_path in paths:
      for sub_path in paths:
        if parent_path == sub_path:
          continue
        if os.path.commonprefix((parent_path, sub_path)) == parent_path:
          duplicates.add(sub_path)
    paths -= duplicates

    if self.http_server:
      if paths and self.http_server.paths == paths:
        return False

      self.http_server.Close()

    if not paths:
      return False

    server = memory_cache_http_server.MemoryCacheHTTPServer(paths)
    self.StartLocalServer(server)
    return True

  def StopAllLocalServers(self):
    self._local_server_controller.Close()

  @property
  def local_servers(self):
    """Returns the currently running local servers."""
    return self._local_server_controller.local_servers

  def HasBattOrConnected(self):
    return  self._platform_backend.HasBattOrConnected()
