#
# 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.
#
"""Functionality to enumerate and represent starboard ports."""

import logging
import os
import re

import _env  # pylint: disable=unused-import
from starboard.tools import environment

# The list of files that must be present in a directory to allow it to be
# considered a valid platform.
_PLATFORM_FILES = [
    'gyp_configuration.gypi',
    'gyp_configuration.py',
    'starboard_platform.gyp',
    'configuration_public.h',
    'atomic_public.h',
    'thread_types_public.h',
]


# Whether to emit warnings if it finds a directory that almost has a platform.
# TODO: Enable when tree is clean.
_WARN_ON_ALMOST = False


def _IsValidPlatformFilenameList(directory, filenames):
  """Determines if |filenames| contains the required files for a valid port."""
  missing = set(_PLATFORM_FILES) - set(filenames)
  if missing:
    if len(missing) < (len(_PLATFORM_FILES) / 2) and _WARN_ON_ALMOST:
      logging.warning('Directory %s contains several files needed for a '
                      'platform, but not all of them. In particular, it is '
                      'missing: %s', directory, ', '.join(missing))
  return not missing


def _GetPlatformName(root, directory):
  """Gets the name of a platform found at |directory| off of |root|."""
  assert directory.startswith(root)
  start = len(root) + 1  # Remove the trailing slash from the root.

  assert start < len(directory)

  # Calculate the name based on relative path from search root to directory.
  return re.sub(r'[^a-zA-Z0-9_]', r'-', directory[start:])


def _EnumeratePlatforms(root_path, exclusion_set=None):
  """Generator that iterates over Starboard platforms found under |path|."""
  if not exclusion_set:
    exclusion_set = set()

  for current_path, directories, filenames in os.walk(root_path):
    # Don't walk into any directories in the exclusion set.
    directories[:] = (x for x in directories
                      if os.path.join(current_path, x) not in exclusion_set)

    # Determine if the current directory is a valid port directory.
    if _IsValidPlatformFilenameList(current_path, filenames):
      if current_path == root_path:
        logging.warning('Found platform at search path root: %s', current_path)
      name = _GetPlatformName(root_path, current_path)
      yield PlatformInfo(name, current_path)


def _FindAllPlatforms():
  """Search the filesystem for all valid Starboard platforms.

  Returns:
    A Mapping of name->PlatformInfo.
  """

  result = {}
  search_path = environment.GetStarboardPortRoots()

  # Ignore search path directories inside other search path directories.
  exclusion_set = set(search_path)

  for entry in search_path:
    if not os.path.isdir(entry):
      continue
    for platform_info in _EnumeratePlatforms(entry, exclusion_set):
      if platform_info.name in result:
        logging.error('Found duplicate port name "%s" at "%s" and "%s"',
                      platform_info.name, result[platform_info.name],
                      platform_info.path)
      result[platform_info.name] = platform_info

  return result


# Cache of name->PlatformInfo mapping.
_INFO_MAP = None


def _GetInfoMap():
  """Gets mapping of platform names to PlatformInfo objects."""
  global _INFO_MAP
  if not _INFO_MAP:
    _INFO_MAP = _FindAllPlatforms()
  return _INFO_MAP


# Cache of the sorted list of all platform names.
_ALL = None


def GetAll():
  """Gets a sorted list of all valid Starboard platform names."""
  global _ALL
  if not _ALL:
    _ALL = sorted(_GetInfoMap().keys())
  return _ALL


def Get(platform_name):
  """Gets the PlatformInfo for the given platform name, or None."""
  return _GetInfoMap().get(platform_name)


def GetAllInfos():
  """Gets a sorted sequence of PlatformInfo objects for all valid platforms."""
  return (Get(p) for p in GetAll())


def IsValid(platform_name):
  """Determines whether the given platform name is valid."""
  return platform_name in _GetInfoMap()


class PlatformInfo(object):
  """Information about a specific Starboard platform."""

  def __init__(self, name, path):
    self.name = name
    self.path = path
