#!/usr/bin/env python
#
# Copyright (c) 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.

"""Provisions Android devices with settings required for bots.

Usage:
  ./provision_devices.py [-d <device serial number>]
"""

import argparse
import datetime
import json
import logging
import os
import posixpath
import re
import subprocess
import sys
import time

from devil.android import battery_utils
from devil.android import device_blacklist
from devil.android import device_errors
from devil.android import device_temp_file
from devil.android import device_utils
from devil.android.sdk import version_codes
from devil.utils import run_tests_helper
from devil.utils import timeout_retry
from pylib import constants
from pylib import device_settings

_SYSTEM_WEBVIEW_PATHS = ['/system/app/webview', '/system/app/WebViewGoogle']
_CHROME_PACKAGE_REGEX = re.compile('.*chrom.*')
_TOMBSTONE_REGEX = re.compile('tombstone.*')


class _DEFAULT_TIMEOUTS(object):
  # L can take a while to reboot after a wipe.
  LOLLIPOP = 600
  PRE_LOLLIPOP = 180

  HELP_TEXT = '{}s on L, {}s on pre-L'.format(LOLLIPOP, PRE_LOLLIPOP)


class _PHASES(object):
  WIPE = 'wipe'
  PROPERTIES = 'properties'
  FINISH = 'finish'

  ALL = [WIPE, PROPERTIES, FINISH]


def ProvisionDevices(args):
  blacklist = (device_blacklist.Blacklist(args.blacklist_file)
               if args.blacklist_file
               else None)
  devices = [d for d in device_utils.DeviceUtils.HealthyDevices(blacklist)
             if not args.emulators or d.adb.is_emulator]
  if args.device:
    devices = [d for d in devices if d == args.device]
  if not devices:
    raise device_errors.DeviceUnreachableError(args.device)
  parallel_devices = device_utils.DeviceUtils.parallel(devices)
  if args.emulators:
    parallel_devices.pMap(SetProperties, args)
  else:
    parallel_devices.pMap(ProvisionDevice, blacklist, args)
  if args.auto_reconnect:
    _LaunchHostHeartbeat()
  blacklisted_devices = blacklist.Read() if blacklist else []
  if args.output_device_blacklist:
    with open(args.output_device_blacklist, 'w') as f:
      json.dump(blacklisted_devices, f)
  if all(d in blacklisted_devices for d in devices):
    raise device_errors.NoDevicesError
  return 0


def ProvisionDevice(device, blacklist, options):
  if options.reboot_timeout:
    reboot_timeout = options.reboot_timeout
  elif device.build_version_sdk >= version_codes.LOLLIPOP:
    reboot_timeout = _DEFAULT_TIMEOUTS.LOLLIPOP
  else:
    reboot_timeout = _DEFAULT_TIMEOUTS.PRE_LOLLIPOP

  def should_run_phase(phase_name):
    return not options.phases or phase_name in options.phases

  def run_phase(phase_func, reboot=True):
    try:
      device.WaitUntilFullyBooted(timeout=reboot_timeout, retries=0)