
"""
Events generated by the extension mechanism.
"""

from typing import Sequence
from .defs import LoadedExtension
from ....base import create_singleton_identity
from ....base.bus import (
    EventId, EventBus, ListenerSetup, EventCallback,
)


TARGET_EXTENSION_LOADER = create_singleton_identity('core.extensions.api')

EVENT_ID_EXTENSION_LOADED = EventId('core.extensions.api loaded')


class ExtensionLoadedEvent:
    """
    A signal that an exception completed loading.  Not guaranteed to be sent
    in the order that they were loaded.
    """
    __slots__ = ('__extension', '__loaded_dependencies')

    def __init__(
            self, extension: LoadedExtension, loaded_dependencies: Sequence[LoadedExtension]
    ) -> None:
        self.__extension = extension
        self.__loaded_dependencies = tuple(loaded_dependencies)

    @property
    def extension(self) -> LoadedExtension:
        """The extension that was loaded."""
        return self.__extension

    @property
    def loaded_dependencies(self) -> Sequence[LoadedExtension]:
        """All the missing dependent extensions loaded because this was loaded.  Those
        should have generated their own messages."""
        return self.__loaded_dependencies


def as_extension_loaded_listener(
        callback: EventCallback[ExtensionLoadedEvent]
) -> ListenerSetup[ExtensionLoadedEvent]:
    """Type-safe listener generator."""
    return (EVENT_ID_EXTENSION_LOADED, callback,)


EVENT_ID_REQUEST_LOAD_EXTENSION = EventId('core.extensions.api request-load')

class RequestLoadExtensionEvent:
    """
    Request to the extension loading mechanism to load an extension.

    If the extension has already been loaded, then this will not generate a
    corresponding ExtensionLoadedEvent.

    Requesting extensions through an Event means that the version is up to the
    extension API to determine.  Likewise, the extension can be loaded as an
    insecure extension (forced into restricted access).
    """
    __slots__ = ('_extension_name',)

    def __init__(self, extension_name: str) -> None:
        self._extension_name = extension_name

    @property
    def extension_name(self) -> str:
        """The requested extension to load."""
        return self._extension_name


def send_request_load_extension_event(bus: EventBus, name: str) -> None:
    """Generate an event to request the loading of an extension."""
    bus.trigger(
        EVENT_ID_REQUEST_LOAD_EXTENSION,
        TARGET_EXTENSION_LOADER,
        RequestLoadExtensionEvent(name)
    )
