# Copyright 2017 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.
"""Starboard Raspberry Pi platform configuration."""

import os

from starboard.build import clang as clang_specification
from starboard.build import platform_configuration
from starboard.tools import build
from starboard.tools.testing import test_filter
from starboard.tools.toolchain import ar
from starboard.tools.toolchain import bash
from starboard.tools.toolchain import clang
from starboard.tools.toolchain import clangxx
from starboard.tools.toolchain import cp
from starboard.tools.toolchain import touch

# Use a bogus path instead of None so that anything based on $RASPI_HOME won't
# inadvertently end up pointing to something in the root directory, and this
# will show up in an error message when that fails.
_UNDEFINED_RASPI_HOME = '/UNDEFINED/RASPI_HOME'


class RaspiPlatformConfig(platform_configuration.PlatformConfiguration):
  """Starboard Raspberry Pi platform configuration."""

  def __init__(self,
               platform,
               sabi_json_path='starboard/sabi/default/sabi.json'):
    super(RaspiPlatformConfig, self).__init__(platform)
    self.AppendApplicationConfigurationPath(os.path.dirname(__file__))
    self.raspi_home = os.environ.get('RASPI_HOME', _UNDEFINED_RASPI_HOME)
    self.sabi_json_path = sabi_json_path
    self.sysroot = os.path.realpath(os.path.join(self.raspi_home, 'sysroot'))

  def GetBuildFormat(self):
    """Returns the desired build format."""
    # The comma means that ninja and qtcreator_ninja will be chained and use the
    # same input information so that .gyp files will only have to be parsed
    # once.
    return 'ninja,qtcreator_ninja'

  def GetVariables(self, configuration):
    variables = super(RaspiPlatformConfig, self).GetVariables(configuration)
    variables.update({
        'clang':
            0,
        'sysroot':
            self.sysroot,
        'include_path_platform_deploy_gypi':
            'starboard/raspi/shared/platform_deploy.gypi',
        'STRIP':
            os.environ.get('STRIP')
    })

    return variables

  def GetEnvironmentVariables(self):
    if not hasattr(self, 'host_compiler_environment'):
      self.host_compiler_environment = build.GetHostCompilerEnvironment(
          clang_specification.GetClangSpecification(), False)

    env_variables = self.host_compiler_environment
    toolchain = os.path.realpath(
        os.path.join(
            self.raspi_home,
            'tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64'))
    toolchain_bin_dir = os.path.join(toolchain, 'bin')
    env_variables.update({
        'CC': os.path.join(toolchain_bin_dir, 'arm-linux-gnueabihf-gcc'),
        'CXX': os.path.join(toolchain_bin_dir, 'arm-linux-gnueabihf-g++'),
        'STRIP': os.path.join(toolchain_bin_dir, 'arm-linux-gnueabihf-strip'),
    })
    return env_variables

  def SetupPlatformTools(self, build_number):
    # Nothing to setup, but validate that RASPI_HOME is correct.
    if self.raspi_home == _UNDEFINED_RASPI_HOME:
      raise RuntimeError('RasPi builds require the "RASPI_HOME" '
                         'environment variable to be set.')
    if not os.path.isdir(self.sysroot):
      raise RuntimeError('RasPi builds require $RASPI_HOME/sysroot '
                         'to be a valid directory.')

  def GetTargetToolchain(self, **kwargs):
    environment_variables = self.GetEnvironmentVariables()
    cc_path = environment_variables['CC']
    cxx_path = environment_variables['CXX']

    return [
        clang.CCompiler(path=cc_path),
        clang.CxxCompiler(path=cxx_path),
        clang.AssemblerWithCPreprocessor(path=cc_path),
        ar.StaticThinLinker(),
        ar.StaticLinker(),
        clangxx.ExecutableLinker(path=cxx_path, write_group=True),
        clangxx.SharedLibraryLinker(path=cxx_path),
        cp.Copy(),
        touch.Stamp(),
        bash.Shell(),
    ]

  def GetHostToolchain(self, **kwargs):
    environment_variables = self.GetEnvironmentVariables()
    cc_path = environment_variables['CC_host']
    cxx_path = environment_variables['CXX_host']

    return [
        clang.CCompiler(path=cc_path),
        clang.CxxCompiler(path=cxx_path),
        clang.AssemblerWithCPreprocessor(path=cc_path),
        ar.StaticThinLinker(),
        ar.StaticLinker(),
        clangxx.ExecutableLinker(path=cxx_path, write_group=True),
        clangxx.SharedLibraryLinker(path=cxx_path),
        cp.Copy(),
        touch.Stamp(),
        bash.Shell(),
    ]

  def GetLauncherPath(self):
    """Gets the path to the launcher module for this platform."""
    return os.path.dirname(__file__)

  def GetGeneratorVariables(self, config_name):
    del config_name
    generator_variables = {
        'qtcreator_session_name_prefix': 'cobalt',
    }
    return generator_variables

  def GetTestFilters(self):
    filters = super(RaspiPlatformConfig, self).GetTestFilters()
    for target, tests in self.__FILTERED_TESTS.iteritems():
      filters.extend(test_filter.TestFilter(target, test) for test in tests)
    return filters

  __FILTERED_TESTS = {  # pylint: disable=invalid-name
      'nplb': [
          'SbDrmTest.AnySupportedKeySystems',
      ],
      'player_filter_tests': [
          # The implementations for the raspberry pi (0 and 2) are incomplete
          # and not meant to be a reference implementation. As such we will
          # not repair these failing tests for now.
          'VideoDecoderTests/VideoDecoderTest.EndOfStreamWithoutAnyInput/0',
          'VideoDecoderTests/VideoDecoderTest.MultipleResets/0',
      ],
  }

  def GetPathToSabiJsonFile(self):
    return self.sabi_json_path
