# Copyright 2018 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

import os
import pdb
import signal
import sys

try:
	import asyncio as _real_asyncio
	from asyncio.events import AbstractEventLoop as _AbstractEventLoop
except ImportError:
	# Allow ImportModulesTestCase to succeed.
	_real_asyncio = None
	_AbstractEventLoop = object

import portage


class AsyncioEventLoop(_AbstractEventLoop):
	"""
	Implementation of asyncio.AbstractEventLoop which wraps asyncio's
	event loop and is minimally compatible with _PortageEventLoop.
	"""

	# Use portage's internal event loop in subprocesses, as a workaround
	# for https://bugs.python.org/issue22087, and also
	# https://bugs.python.org/issue29703 which affects pypy3-5.10.1.
	supports_multiprocessing = False

	def __init__(self, loop=None):
		loop = loop or _real_asyncio.get_event_loop()
		self._loop = loop
		self.run_until_complete = (self._run_until_complete
			if portage._internal_caller else loop.run_until_complete)
		self.call_soon = loop.call_soon
		self.call_soon_threadsafe = loop.call_soon_threadsafe
		self.call_later = loop.call_later
		self.call_at = loop.call_at
		self.is_running = loop.is_running
		self.is_closed = loop.is_closed
		self.close = loop.close
		self.create_future = (loop.create_future
			if hasattr(loop, 'create_future') else self._create_future)
		self.create_task = loop.create_task
		self.add_reader = loop.add_reader
		self.remove_reader = loop.remove_reader
		self.add_writer = loop.add_writer
		self.remove_writer = loop.remove_writer
		self.run_in_executor = loop.run_in_executor
		self.time = loop.time
		self.default_exception_handler = loop.default_exception_handler
		self.call_exception_handler = loop.call_exception_handler
		self.set_debug = loop.set_debug
		self.get_debug = loop.get_debug
		self._wakeup_fd = -1

		if portage._internal_caller:
			loop.set_exception_handler(self._internal_caller_exception_handler)

	@staticmethod
	def _internal_caller_exception_handler(loop, context):
		"""
		An exception handler which drops to a pdb shell if std* streams
		refer to a tty, and otherwise kills the process with SIGTERM.

		In order to avoid potential interference with API consumers, this
		implementation is only used when portage._internal_caller is True.
		"""
		loop.default_exception_handler(context)
		if 'exception' in context:
			# If we have a tty then start the debugger, since in might
			# aid in diagnosis of the problem. If there's no tty, then
			# exit immediately.
			if all(s.isatty() for s in (sys.stdout, sys.stderr, sys.stdin)):
				pdb.set_trace()
			else:
				# Normally emerge will wait for all coroutines to complete
				# after SIGTERM has been received. However, an unhandled
				# exception will prevent the interrupted coroutine from
				# completing, therefore use the default SIGTERM handler
				# in order to ensure that emerge exits immediately (though
				# uncleanly).
				signal.signal(signal.SIGTERM, signal.SIG_DFL)
				os.kill(os.getpid(), signal.SIGTERM)

	def _create_future(self):
		"""
		Provide AbstractEventLoop.create_future() for python3.4.
		"""
		return _real_asyncio.Future(loop=self._loop)

	@property
	def _asyncio_child_watcher(self):
		"""
		Portage internals use this as a layer of indirection for
		asyncio.get_child_watcher(), in order to support versions of
		python where asyncio is not available.

		@rtype: asyncio.AbstractChildWatcher
		@return: the internal event loop's AbstractChildWatcher interface
		"""
		return _real_asyncio.get_child_watcher()

	@property
	def _asyncio_wrapper(self):
		"""
		Portage internals use this as a layer of indirection in cases
		where a wrapper around an asyncio.AbstractEventLoop implementation
		is needed for purposes of compatiblity.

		@rtype: asyncio.AbstractEventLoop
		@return: the internal event loop's AbstractEventLoop interface
		"""
		return self

	def _run_until_complete(self, future):
		"""
		An implementation of AbstractEventLoop.run_until_complete that supresses
		spurious error messages like the following reported in bug 655656:

		    Exception ignored when trying to write to the signal wakeup fd:
		    BlockingIOError: [Errno 11] Resource temporarily unavailable

		In order to avoid potential interference with API consumers, this
		implementation is only used when portage._internal_caller is True.
		"""
		if self._wakeup_fd != -1:
			signal.set_wakeup_fd(self._wakeup_fd)
			self._wakeup_fd = -1
			# Account for any signals that may have arrived between
			# set_wakeup_fd calls.
			os.kill(os.getpid(), signal.SIGCHLD)
		try:
			return self._loop.run_until_complete(future)
		finally:
			self._wakeup_fd = signal.set_wakeup_fd(-1)
