# Copyright 2018 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import io
import logging
import os
import time

from mobly import logger as mobly_logger
from mobly import utils
from mobly.controllers.android_device_lib import adb
from mobly.controllers.android_device_lib import errors
from mobly.controllers.android_device_lib.services import base_service

CREATE_LOGCAT_FILE_TIMEOUT_SEC = 5


class Error(errors.ServiceError):
  """Root error type for logcat service."""
  SERVICE_TYPE = 'Logcat'


class Config(object):
  """Config object for logcat service.

  Attributes:
    clear_log: bool, clears the logcat before collection if True.
    logcat_params: string, extra params to be added to logcat command.
    output_file_path: string, the path on the host to write the log file
      to, including the actual filename. The service will automatically
      generate one if not specified.
  """

  def __init__(self,
         logcat_params=None,
         clear_log=True,
         output_file_path=None):
    self.clear_log = clear_log
    self.logcat_params = logcat_params if logcat_params else ''
    self.output_file_path = output_file_path


class Logcat(base_service.BaseService):
  """Android logcat service for Mobly's AndroidDevice controller.

  Attributes:
    adb_logcat_file_path: string, path to the file that the service writes
      adb logcat to by default.
  """
  OUTPUT_FILE_TYPE = 'logcat'

  def __init__(self, android_device, configs=None):
    super(Logcat, self).__init__(android_device, configs)
    self._ad = android_device
    self._adb_logcat_process = None
    self._adb_logcat_file_obj = None
    self.adb_logcat_file_path = None
    # Logcat service uses a single config obj, using singular internal
    # name: `_config`.
    self._config = configs if configs else Config()

  def _enable_logpersist(self):
    """Attempts to enable logpersist daemon to persist logs."""
    # Logpersist is only allowed on rootable devices because of excessive
    # reads/writes for persisting logs.
    if not self._ad.is_rootable:
      return

    logpersist_warning = ('%s encountered an error enabling persistent'
                ' logs, logs may not get saved.')
    # Android L and older versions do not have logpersist installed,
    # so check that the logpersist scripts exists before trying to use
    # them.
    if not self._ad.adb.has_shell_command('logpersist.start'):
      logging.warning(logpersist_warning, self)
      return

    try:
      # Disable adb log spam filter for rootable devices. Have to stop
      # and clear settings first because 'start' doesn't support --clear
      # option before Android N.
      self._ad.adb.shell('logpersist.stop --clear')
      self._ad.adb.shell('logpersist.start')
    except adb.AdbError:
      logging.warning(logpersist_warning, self)

  def _is_timestamp_in_range(self, target, begin_time, end_time):
    low = mobly_logger.logline_timestamp_comparator(begin_time,
                            target) <= 0
    high = mobly_logger.logline_timestamp_comparator(end_time, target) >= 0
    return low and high

  def create_output_excerpts(self, test_info):
    """Convenient method for creating excerpts of adb logcat.

    This copies logcat lines from self.adb_logcat_file_path to an excerpt
    file, starting from the location where the previous excerpt ended.

    Call this method at the end of: `setup_class`, `teardown_test`, and
    `teardown_class`.

    Args:
      test_info: `self.current_test_info` in a Mobly test.

    Returns:
      List of strings, the absolute paths to excerpt files.
    """
    dest_path = test_info.output_path
    utils.create_dir(dest_path)
    filename = self._ad.generate_filename(self.OUTPUT_FILE_TYPE, test_info,
                        'txt')
    excerpt_file_path = os.path.join(dest_path, filename)
    with io.open(excerpt_file_path, 'w', encoding='utf-8',
           errors='replace') as out:
      # Devices may accidentally go offline during test,
      # check not None before readline().
      while self._adb_logcat_file_obj:
        line = self._adb_logcat_file_obj.readline()
        if not line:
          break
        out.write(line)
    self._ad.log.debug('logcat excerpt created at: %s', excerpt_file_path)
    return [excerpt_file_path]

  @property
  def is_alive(self):
    return True if self._adb_logcat_process else False

  def clear_adb_log(self):
    """Clears cached adb content."""
    try:
      self._ad.adb.logcat('-c')
    except adb.AdbError as e:
      # On Android O, the clear command fails due to a known bug.
      # Catching this so we don't crash from this Android issue.
      if b'failed to clear' in e.stderr:
        self._ad.log.warning(
          'Encountered known Android error to clear logcat.')
      else:
        raise

  def _assert_not_running(self):
    """Asserts the logcat service is not running.

    Raises:
      Error, if the logcat service is running.
    """
    if self.is_alive:
      raise Error(
        self._ad,
        'Logcat thread is already running, cannot start another one.')

  def update_config(self, new_config):
    """Updates the configuration for the service.

    The service needs to be stopped before updating, and explicitly started
    after the update.

    This will reset the service. Previous output files may be orphaned if
    output path is changed.

    Args:
      new_config: Config, the new config to use.
    """
    self._assert_not_running()
    self._ad.log.info('[LogcatService] Changing config from %s to %s',
              self._config, new_config)
    self._config = new_config

  def _open_logcat_file(self):
    """Create a file object that points to the beginning of the logcat file.
    Wait for the logcat file to be created by the subprocess if it doesn't
    exist.
    """
    if not self._adb_logcat_file_obj:
      start_time = time.time()
      while not os.path.exists(self.adb_logcat_file_path):
        if time.time() > start_time + CREATE_LOGCAT_FILE_TIMEOUT_SEC:
          raise Error(
            self._ad,
            'Timeout while waiting for logcat file to be created.')
        time.sleep(1)
      self._adb_logcat_file_obj = io.open(
        self.adb_logcat_file_path, 'r', encoding='utf-8',
        errors='replace')
      self._adb_logcat_file_obj.seek(0, os.SEEK_END)

  def _close_logcat_file(self):
    """Closes and resets the logcat file object, if it exists."""
    if self._adb_logcat_file_obj:
      self._adb_logcat_file_obj.close()
      self._adb_logcat_file_obj = None

  def start(self):
    """Starts a standing adb logcat collection.

    The collection runs in a separate subprocess and saves logs in a file.
    """
    self._assert_not_running()
    if self._config.clear_log:
      self.clear_adb_log()
    self._start()
    self._open_logcat_file()

  def _start(self):
    """The actual logic of starting logcat."""
    self._enable_logpersist()
    if self._config.output_file_path:
      self._close_logcat_file()
      self.adb_logcat_file_path = self._config.output_file_path
    if not self.adb_logcat_file_path:
      f_name = self._ad.generate_filename(self.OUTPUT_FILE_TYPE,
                        extension_name='txt')
      logcat_file_path = os.path.join(self._ad.log_path, f_name)
      self.adb_logcat_file_path = logcat_file_path
    utils.create_dir(os.path.dirname(self.adb_logcat_file_path))
    # In debugging mode of IntelijIDEA, "patch_args" remove
    # double quotes in args if starting and ending with it.
    # Add spaces at beginning and at last to fix this issue.
    cmd = ' "%s" -s %s logcat -v threadtime -T 1 %s >> "%s" ' % (
      adb.ADB, self._ad.serial, self._config.logcat_params,
      self.adb_logcat_file_path)
    process = utils.start_standing_subprocess(cmd, shell=True)
    self._adb_logcat_process = process

  def stop(self):
    """Stops the adb logcat service."""
    self._close_logcat_file()
    self._stop()

  def _stop(self):
    """Stops the background process for logcat."""
    if not self._adb_logcat_process:
      return
    try:
      utils.stop_standing_subprocess(self._adb_logcat_process)
    except:
      self._ad.log.exception('Failed to stop adb logcat.')
    self._adb_logcat_process = None

  def pause(self):
    """Pauses logcat.

    Note: the service is unable to collect the logs when paused, if more
    logs are generated on the device than the device's log buffer can hold,
    some logs would be lost.
    """
    self._stop()

  def resume(self):
    """Resumes a paused logcat service."""
    self._assert_not_running()
    # Not clearing the log regardless of the config when resuming.
    # Otherwise the logs during the paused time will be lost.
    self._start()
