# Copyright 2013 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.

""" A simple device interface for build steps.

"""

import logging
import os
import re
import sys

from util import build_utils

BUILD_ANDROID_DIR = os.path.join(os.path.dirname(__file__), '..', '..')
sys.path.append(BUILD_ANDROID_DIR)

from devil.android import device_errors
from devil.android import device_utils
from devil.android.sdk import adb_wrapper


def GetAttachedDevices():
  return [a.GetDeviceSerial()
          for a in adb_wrapper.AdbWrapper.Devices()]


class BuildDevice(object):
  def __init__(self, configuration):
    self.id = configuration['id']
    self.description = configuration['description']
    self.install_metadata = configuration['install_metadata']
    self.device = device_utils.DeviceUtils(self.id)

  def RunShellCommand(self, *args, **kwargs):
    return self.device.RunShellCommand(*args, **kwargs)

  def PushChangedFiles(self, *args, **kwargs):
    return self.device.PushChangedFiles(*args, **kwargs)

  def GetSerialNumber(self):
    return self.id

  def Install(self, *args, **kwargs):
    return self.device.Install(*args, **kwargs)

  def InstallSplitApk(self, *args, **kwargs):
    return self.device.InstallSplitApk(*args, **kwargs)

  def GetInstallMetadata(self, apk_package):
    """Gets the metadata on the device for the apk_package apk."""
    # Matches lines like:
    # -rw-r--r-- system   system    7376582 2013-04-19 16:34 \
    #   org.chromium.chrome.apk
    # -rw-r--r-- system   system    7376582 2013-04-19 16:34 \
    #   org.chromium.chrome-1.apk
    apk_matcher = lambda s: re.match('.*%s(-[0-9]*)?.apk$' % apk_package, s)
    matches = filter(apk_matcher, self.install_metadata)
    return matches[0] if matches else None


def GetConfigurationForDevice(device_id):
  device = device_utils.DeviceUtils(device_id)
  configuration = None
  has_root = False
  is_online = device.IsOnline()
  if is_online:
    cmd = 'ls -l /data/app; getprop ro.build.description'
    cmd_output = device.RunShellCommand(cmd)
    has_root = not 'Permission denied' in cmd_output[0]
    if not has_root:
      # Disable warning log messages from EnableRoot()
      logging.getLogger().disabled = True
      try:
        device.EnableRoot()
        has_root = True
      except device_errors.CommandFailedError:
        has_root = False
      finally:
        logging.getLogger().disabled = False
      cmd_output = device.RunShellCommand(cmd)

    configuration = {
        'id': device_id,
        'description': cmd_output[-1],
        'install_metadata': cmd_output[:-1],
      }
  return configuration, is_online, has_root


def WriteConfigurations(configurations, path):
  # Currently we only support installing to the first device.
  build_utils.WriteJson(configurations[:1], path, only_if_changed=True)


def ReadConfigurations(path):
  return build_utils.ReadJson(path)


def GetBuildDevice(configurations):
  assert len(configurations) == 1
  return BuildDevice(configurations[0])


def GetBuildDeviceFromPath(path):
  configurations = ReadConfigurations(path)
  if len(configurations) > 0:
    return GetBuildDevice(ReadConfigurations(path))
  return None

