# Copyright 2017 Open Source Robotics Foundation, 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 sys
import threading

import ament_index_python

from rclpy.constants import S_TO_NS
from rclpy.context import Context

g_default_context = None
g_context_lock = threading.Lock()


def get_default_context(*, shutting_down=False):
    """Return the global default context singleton."""
    global g_context_lock
    with g_context_lock:
        global g_default_context
        if g_default_context is None:
            g_default_context = Context()
        if shutting_down:
            old_context = g_default_context
            g_default_context = None
            return old_context
        return g_default_context


def remove_ros_args(args=None):
    # imported locally to avoid loading extensions on module import
    from rclpy.impl.implementation_singleton import rclpy_implementation
    return rclpy_implementation.rclpy_remove_ros_args(
        args if args is not None else sys.argv)


def ok(*, context=None):
    if context is None:
        context = get_default_context()
    return context.ok()


def shutdown(*, context=None):
    if context is None:
        context = get_default_context(shutting_down=True)
    return context.shutdown()


def try_shutdown(*, context=None):
    """Shutdown rclpy if not already shutdown."""
    if context is None:
        context = get_default_context()
    return context.try_shutdown()


def get_rmw_implementation_identifier():
    # imported locally to avoid loading extensions on module import
    from rclpy.impl.implementation_singleton import rclpy_implementation
    return rclpy_implementation.rclpy_get_rmw_implementation_identifier()


def get_available_rmw_implementations():
    """Return the set of all available RMW implementations as registered in the ament index."""
    rmw_implementations = ament_index_python.get_resources('rmw_typesupport')
    return {name for name in rmw_implementations if name != 'rmw_implementation'}


def timeout_sec_to_nsec(timeout_sec):
    """
    Convert timeout in seconds to rcl compatible timeout in nanoseconds.

    Python tends to use floating point numbers in seconds for timeouts. This utility converts a
    python-style timeout to an integer in nanoseconds that can be used by rcl_wait.

    :param timeout_sec: Seconds to wait. Block forever if None or negative. Don't wait if < 1ns
    :type timeout_sec: float or None
    :rtype: int
    :returns: rcl_wait compatible timeout in nanoseconds
    """
    if timeout_sec is None or timeout_sec < 0:
        # Block forever
        return -1
    else:
        # wait for given time
        return int(float(timeout_sec) * S_TO_NS)

@@ -595,16 +595,26 @@
 cense.%0A%0A
+import os%0A
 import s
@@ -2255,32 +2255,37 @@
 tions():%0A    %22%22%22
+%0A    
 Return the set o
@@ -2353,24 +2353,327 @@
 t index.
-%22%22%22%0A    
+%0A%0A    The result can be overridden by setting an environment variable named%0A    %60%60RMW_IMPLEMENTATIONS%60%60.%0A    The variable can contain RMW implementation names separated by the platform%0A    specific path separator.%0A    Including an unavailable RMW implementation results in a RuntimeError.%0A    %22%22%22%0A    available_
 rmw_impl
@@ -2719,16 +2719,25 @@
 sources(
+%0A        
 'rmw_typ
@@ -2755,16 +2755,50 @@
     
-return %7B
+available_rmw_implementations = %7B%0A        
 name
@@ -2810,16 +2810,26 @@
 name in 
+available_
 rmw_impl
@@ -2839,16 +2839,24 @@
 ntations
+%0A       
  if name
@@ -2882,16 +2882,834 @@
 tion'%7D%0A%0A
+    # filter by implementations in environment variable if provided%0A    rmw_implementations = os.environ.get('RMW_IMPLEMENTATIONS')%0A    if rmw_implementations:%0A        rmw_implementations = rmw_implementations.split(os.pathsep)%0A        missing_rmw_implementations = set(rmw_implementations) - %5C%0A            available_rmw_implementations%0A        if missing_rmw_implementations:%0A            raise RuntimeError(%0A                f'The RMW implementations %7Bmissing_rmw_implementations%7D '%0A                %22specified in 'RMW_IMPLEMENTATIONS' are not available (%22 +%0A                ', '.join(sorted(available_rmw_implementations)) + ')')%0A        available_rmw_implementations = %7B%0A            name for name in available_rmw_implementations%0A            if name in rmw_implementations%7D%0A%0A    return available_rmw_implementations%0A%0A
 %0Adef tim

add env var to filter available RMW implementations (#522)