#
# Copyright 2017 Google Inc. All Rights Reserved.
#
# 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.
#
"""Abstraction for running Cobalt development tools."""

import abc
import importlib
import os
import sys

import _env  # pylint: disable=unused-import
import starboard.tools.platform as platform_module


def GetGypModuleForPlatform(platform):
  """Gets the module containing a platform's GYP configuration.

  Args:
    platform:  Platform on which the app will be run, ex. "linux-x64x11".

  Returns:
    The module containing the platform's GYP configuration.

  Raises:
    RuntimeError:  The specified platform does not exist.
  """
  if platform_module.IsValid(platform):
    platform_path = platform_module.Get(platform).path
    if platform_path not in sys.path:
      sys.path.append(platform_path)
    gyp_module = importlib.import_module("gyp_configuration")
    return gyp_module
  else:
    raise RuntimeError("Specified platform does not exist.")


def _GetLauncherForPlatform(platform):
  """Gets the module containing a platform's concrete launcher implementation.

  Args:
    platform: Platform on which the app will be run, ex. "linux-x64x11".

  Returns:
    The module containing the platform's launcher implementation.
  """

  gyp_config = GetGypModuleForPlatform(platform).CreatePlatformConfig()
  if not hasattr(gyp_config, "GetLauncher"):
    return None
  else:
    return gyp_config.GetLauncher()


def DynamicallyBuildOutDirectory(platform, config):
  """Constructs the location used to store executable targets/their components.

  Args:
    platform: The platform to run the executable on, ex. "linux-x64x11".
    config: The build configuration, ex. "qa".

  Returns:
    The path to the directory containing executables and/or their components.
  """
  path = os.path.abspath(
      os.path.join(os.path.dirname(__file__),
                   os.pardir, os.pardir, "out",
                   "{}_{}".format(platform, config)))
  return path


def LauncherFactory(platform, target_name, config, device_id=None,
                    target_params=None, output_file=None,
                    out_directory=None, env_variables=None):
  """Creates the proper launcher based upon command line args.

  Args:
    platform:  The platform on which the app will run.
    target_name:  The name of the executable target (ex. "cobalt").
    config:  Type of configuration used by the launcher (ex. "qa", "devel").
    device_id:  The identifier for the devkit being used.  Can be None.
    target_params: Command line arguments to the executable.  Can be None.
    output_file: Open file object used for storing the launcher's output. If
      None, sys.stdout is used.
    out_directory: Directory containing the executable target. If None is
      provided, the path to the directory is dynamically generated.
    env_variables:  Environment variables for the executable

  Returns:
    An instance of the concrete launcher class for the desired platform.

  Raises:
    RuntimeError: The platform does not exist, or there is no project root.
  """

  #  Creates launcher for provided platform if the platform has a valid port
  launcher_module = _GetLauncherForPlatform(platform)

  #  TODO: Refactor when all old launchers have been deleted
  #  If a platform that does not have a new launcher is provided, attempt
  #  to create an adapter to the old one.
  if not launcher_module:
    old_path = os.path.abspath(os.path.join(os.path.dirname(__file__),
                                            os.pardir, os.pardir, "tools",
                                            "lbshell"))
    if os.path.exists(os.path.join(old_path, "app_launcher.py")):
      sys.path.append(old_path)
      bridge_module = importlib.import_module("app_launcher_bridge")
      return bridge_module.LauncherAdapter(
          platform, target_name, config, device_id, target_params=target_params,
          output_file=output_file, out_directory=out_directory,
          env_variables=env_variables)
    else:
      raise RuntimeError("No launcher implemented for the given platform.")
  else:
    return launcher_module.Launcher(
        platform, target_name, config, device_id, target_params=target_params,
        output_file=output_file, out_directory=out_directory,
        env_variables=env_variables)


class AbstractLauncher(object):
  """Class that specifies all required behavior for Cobalt app launchers."""

  __metaclass__ = abc.ABCMeta

  def __init__(self, platform, target_name, config, device_id, **kwargs):
    self.platform = platform
    self.target_name = target_name
    self.config = config
    self.device_id = device_id
    self.out_directory = kwargs.get("out_directory", None)

    #  The following pattern makes sure that variables will be initialized
    #  properly whether a kwarg is passed in with a value of None or it
    #  is not passed in at all.
    output_file = kwargs.get("output_file", None)
    if not output_file:
      output_file = sys.stdout
    self.output_file = output_file

    target_command_line_params = kwargs.get("target_params", None)
    if target_command_line_params is None:
      target_command_line_params = []
    self.target_command_line_params = target_command_line_params

    env_variables = kwargs.get("env_variables", None)
    if env_variables is None:
      env_variables = {}
    self.env_variables = env_variables

    # Launchers that need different startup timeout times should reassign
    # this variable during initialization.
    self.startup_timeout_seconds = 2 * 60

  @abc.abstractmethod
  def Run(self):
    """Runs the launcher's executable.  Must be implemented in subclasses.

    Returns:
      The return code from the launcher's executable.
    """
    pass

  @abc.abstractmethod
  def Kill(self):
    """Kills the launcher. Must be implemented in subclasses."""
    pass

  def SendResume(self):
    """Sends resume signal to the launcher's executable."""
    raise RuntimeError("Resume not supported for this platform.")

  def GetStartupTimeout(self):
    """Gets the number of seconds to wait before assuming a launcher timeout."""
    return self.startup_timeout_seconds

  def GetHostAndPortGivenPort(self, port):
    """Creates a host/port tuple for use on the target device.

    This is used to gain access to a service on the target device, and
    can be overridden when the host/port of that service is only accessible
    at runtime and/or via forwarding.

    Args:
      port:  Port number for the desired service on the target device.

    Returns:
      (Host, port) tuple for use in connecting to the target device.
    """
    return self.device_id, port

  def GetTargetPath(self):
    """Constructs the path to an executable target.

    The default path returned by this method takes the form of:

      "/path/to/out/<platform>_<config>/target_name"

    Returns:
      The path to an executable target.
    """
    if self.out_directory:
      out_directory = self.out_directory
    else:
      out_directory = DynamicallyBuildOutDirectory(self.platform, self.config)

    return os.path.abspath(os.path.join(out_directory, self.target_name))

  def _CloseOutputFile(self):
    if self.output_file != sys.stdout and not self.output_file.closed:
      self.output_file.close()
