# -*- coding: utf-8 -*-
"""
Event Module
------------

Contains the event decorator and should have nothing else.
"""

__all__ = [
    'event'
]

# std imports
from functools import wraps

# package imports
import net


def event(name):
    """
    Registers a function as an event trigger. Event triggers are hooks into the
    event system between peers. Peers that ``net.subscribe`` to a peer, register
    an event on that peer.

    Lets say PeerA subscribes to an event on PeerB using the following code.

    .. code-block:: python

        # code on PeerA

        peerB_id = "peerb"

        @net.subscribe("doing_something")
        def handleEvent(whatPeerBDid):
            ...do something

    The subscribe decorator has communicated with PeerB and registered itself as
    on the list of peer to update if "doing_something" is ever triggered. On
    PeerB's side we have the following.

    .. code-block:: python

        # code on PeerB

        @net.event("doing_something")
        def imDoingSomething(*args, **kwargs):
            return args, kwargs

    .. note::

        All functions flagged as an event MUST return args and kwargs exactly as
        displayed above.

    Now lets say in PeerB we want to trigger the event in a for loop and have it
    hand off the values to all the subscribed peers, PeerA in this case.

    .. code-block:: python

        for i in range(0, 10):
            imDoingSomething(i)  # <- this will notify PeerA and pass the value of 'i'.

    Keep in mind, you can have any number of peers subscribe to any kind of
    event. So if we had 5 peers subscribe to PeerB they would all be passed this
    value at runtime.

    Lastly, these event functions act as a buffer between the runtime code of
    your application and the delivery of the content to the peer. For example:

    .. code-block:: python

        var = MyCustomObject()  # some JSON incompatible object

        ...do a bunch of delivery prep and muddy up the application code...

        imDoingSomething(var)

    Instead

    .. code-block:: python

        @net.event("doing_something")
        def imDoingSomething(*args, **kwargs):

            obj = args[0]

            ...clean and prepare for transit here...

            args[0] = cleanedObj

            return args, kwargs

    As you can see, these functions act as a hook into the delivery system when
    the event is triggered.
    """
    def wrapper(func):
        @wraps(func)
        def interface(*args, **kwargs):

            new_args, new_kwargs = func(*args, **kwargs)
            net.Peer().trigger_event(name, *new_args, **new_kwargs)

            return new_args, new_kwargs
        return interface
    return wrapper
