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

from __future__ import absolute_import
import logging

from six.moves import range  # pylint: disable=redefined-builtin
from devil import base_error
from devil.android import device_errors
from devil.android import device_utils
from devil.utils import parallelizer
from devil.utils import reraiser_thread
from devil.utils import timeout_retry
from pylib.local.device import local_device_environment
from pylib.local.emulator import avd

# Mirroring https://bit.ly/2OjuxcS#23
_MAX_ANDROID_EMULATORS = 16


class LocalEmulatorEnvironment(local_device_environment.LocalDeviceEnvironment):

  def __init__(self, args, output_manager, error_func):
    super(LocalEmulatorEnvironment, self).__init__(args, output_manager,
                                                   error_func)
    self._avd_config = avd.AvdConfig(args.avd_config)
    if args.emulator_count < 1:
      error_func('--emulator-count must be >= 1')
    elif args.emulator_count >= _MAX_ANDROID_EMULATORS:
      logging.warning('--emulator-count capped at 16.')
    self._emulator_count = min(_MAX_ANDROID_EMULATORS, args.emulator_count)
    self._emulator_window = args.emulator_window
    self._writable_system = ((hasattr(args, 'use_webview_provider')
                              and args.use_webview_provider)
                             or (hasattr(args, 'replace_system_package')
                                 and args.replace_system_package)
                             or (hasattr(args, 'system_packages_to_remove')
                                 and args.system_packages_to_remove))

    self._emulator_instances = []
    self._device_serials = []

  #override
  def SetUp(self):
    self._avd_config.Install()

    emulator_instances = [
        self._avd_config.CreateInstance() for _ in range(self._emulator_count)
    ]

    def start_emulator_instance(e):

      def impl(e):
        try:
          e.Start(
              window=self._emulator_window,
              writable_system=self._writable_system)
        except avd.AvdException:
          logging.exception('Failed to start emulator instance.')
          return None
        try:
          device_utils.DeviceUtils(e.serial).WaitUntilFullyBooted()
        except base_error.BaseError:
          e.Stop()
          raise
        return e

      def retry_on_timeout(exc):
        return (isinstance(exc, device_errors.CommandTimeoutError)
                or isinstance(exc, reraiser_thread.TimeoutError))

      return timeout_retry.Run(
          impl,
          timeout=120 if self._writable_system else 30,
          retries=2,
          args=[e],
          retry_if_func=retry_on_timeout)

    parallel_emulators = parallelizer.SyncParallelizer(emulator_instances)
    self._emulator_instances = [
        emu
        for emu in parallel_emulators.pMap(start_emulator_instance).pGet(None)
        if emu is not None
    ]
    self._device_serials = [e.serial for e in self._emulator_instances]

    if not self._emulator_instances:
      raise Exception('Failed to start any instances of the emulator.')
    elif len(self._emulator_instances) < self._emulator_count:
      logging.warning(
          'Running with fewer emulator instances than requested (%d vs %d)',
          len(self._emulator_instances), self._emulator_count)

    super(LocalEmulatorEnvironment, self).SetUp()

  #override
  def TearDown(self):
    try:
      super(LocalEmulatorEnvironment, self).TearDown()
    finally:
      parallelizer.SyncParallelizer(self._emulator_instances).Stop()
