#
# Copyright 2016 The Cobalt Authors. 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.
#
"""Build related constants and helper functions."""

import imp  # pylint: disable=deprecated-module
import importlib
import logging
import os
import sys

from starboard.build.platforms import PLATFORMS
from starboard.tools import paths

_STARBOARD_TOOLCHAINS_DIR_KEY = 'STARBOARD_TOOLCHAINS_DIR'
_STARBOARD_TOOLCHAINS_DIR_NAME = 'starboard-toolchains'


class ClangSpecification(object):
  """A specific version of Clang."""

  def __init__(self, revision, version):
    assert revision
    assert version
    self.revision = revision
    self.version = version


def GetToolchainsDir():
  """Gets the directory that contains all downloaded toolchains."""
  home_dir = os.environ.get('HOME')
  toolchains_dir = os.path.realpath(
      os.getenv(_STARBOARD_TOOLCHAINS_DIR_KEY,
                os.path.join(home_dir, _STARBOARD_TOOLCHAINS_DIR_NAME)))

  if not os.path.isdir(toolchains_dir):
    # Ensure the toolchains directory exists.
    os.mkdir(toolchains_dir)

  return toolchains_dir


def _GetClangBasePath(clang_spec):
  return os.path.join(GetToolchainsDir(),
                      'x86_64-linux-gnu-clang-chromium-' + clang_spec.revision)


def GetClangBinPath(clang_spec):
  return os.path.join(_GetClangBasePath(clang_spec), 'bin')


def _ModuleLoaded(module_name, module_path):
  if module_name not in sys.modules:
    return False
  # Sometimes one of these has .pyc and the other has .py, but we don't care.
  extensionless_loaded_path = os.path.splitext(
      os.path.abspath(sys.modules['platform_module'].__file__))[0]
  extensionless_module_path = os.path.splitext(os.path.abspath(module_path))[0]
  return extensionless_loaded_path == extensionless_module_path


def _LoadPlatformModule(platform_name, file_name, function_name):
  """Loads a platform module.

  The function will use the provided platform name to load
  a python file with a matching name that contains the module.

  Args:
    platform_name: Platform name.
    file_name: The file that contains the module. It can be
               gyp_configuration.py or test_filters.py
    function_name: The function name of the module.
                   For gyp_configuration.py, it is CreatePlatformConfig.
                   For test_filters.py, it is GetTestFilters

  Returns: Instance of a class derived from module path.
  """
  try:
    logging.debug('Loading platform %s for "%s".', file_name, platform_name)
    if platform_name in PLATFORMS:
      platform_path = os.path.join(paths.REPOSITORY_ROOT,
                                   PLATFORMS[platform_name])
      module_path = os.path.join(platform_path, file_name)
      if not _ModuleLoaded('platform_module', module_path):
        platform_module = imp.load_source('platform_module', module_path)
      else:
        platform_module = sys.modules['platform_module']
    else:
      module_path = os.path.join('config', f'{platform_name}.py')
      platform_module = importlib.import_module(f'config.{platform_name}')
  except (ImportError, IOError):
    logging.exception('Unable to import "%s".', module_path)
    return None

  if not hasattr(platform_module, function_name):
    logging.error('"%s" does not contain %s.', module_path, function_name)
    return None

  try:
    platform_attr = getattr(platform_module, function_name)()
    return platform_attr, platform_path
  except RuntimeError:
    logging.exception('Exception in %s.', function_name)
    return None


def _LoadPlatformConfig(platform_name):
  """Loads a platform specific configuration.

  The function will use the provided platform name to load
  a python file with a matching name that contains the platform
  specific configuration.

  Args:
    platform_name: Platform name.

  Returns:
    Instance of a class derived from PlatformConfiguration.
  """
  platform_configuration, platform_path = _LoadPlatformModule(
      platform_name, 'gyp_configuration.py', 'CreatePlatformConfig')
  platform_configuration.SetDirectory(platform_path)
  return platform_configuration


def _LoadPlatformTestFilters(platform_name):
  """Loads the platform specific test filters.

  The function will use the provided platform name to load
  a python file with a matching name that contains the platform
  specific test filters.

  Args:
    platform_name: Platform name.

  Returns:
    Instance of a class derived from TestFilters.
  """
  platform_test_filters, _ = _LoadPlatformModule(platform_name,
                                                 'test_filters.py',
                                                 'CreateTestFilters')
  return platform_test_filters


# Global cache of the platform configurations, so that platform config objects
# are only created once.
_PLATFORM_CONFIG_DICT = {}
_PLATFORM_TEST_FILTERS_DICT = {}


def GetPlatformConfig(platform_name):
  """Returns a platform specific configuration.

  This function will return a cached platform configuration object, loading it
  if it doesn't exist via a call to _LoadPlatformConfig().

  Args:
    platform_name: Platform name.

  Returns:
    Instance of a class derived from PlatformConfiguration.
  """

  if platform_name not in _PLATFORM_CONFIG_DICT:
    _PLATFORM_CONFIG_DICT[platform_name] = _LoadPlatformConfig(platform_name)

  return _PLATFORM_CONFIG_DICT[platform_name]


def GetPlatformTestFilters(platform_name):
  """Returns a platform specific test filters.

  Args:
    platform_name: Platform name.

  Returns:
    Instance of a class derived from TestFilters.
  """

  if platform_name not in _PLATFORM_TEST_FILTERS_DICT:
    _PLATFORM_TEST_FILTERS_DICT[platform_name] = _LoadPlatformTestFilters(
        platform_name)

  return _PLATFORM_TEST_FILTERS_DICT[platform_name]
