# Copyright (C) 2012 Vaadin Ltd. 
# Copyright (C) 2012 Richard Lincoln
# 
# 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.

"""Class implementing the inheritable event listening model."""

from muntjac.event.method_event_source import IMethodEventSource
from muntjac.event.listener_method import ListenerMethod


class EventRouter(IMethodEventSource):
    """C{EventRouter} class implementing the inheritable event
    listening model. For more information on the event model see the
    L{muntjac.event package documentation<muntjac.event>}.

    @author: Vaadin Ltd.
    @author: Richard Lincoln
    @version: 1.1.0
    """

    def __init__(self):
        #: List of registered listeners.
        self._listenerList = None


    def addListener(self, eventType, obj, method, arguments=None,
                eventArgIdx=None):
        # Registers a new listener with the specified activation method
        # to listen events generated by this component.

        if self._listenerList is None:
            self._listenerList = set()

        lm = ListenerMethod(eventType, obj, method, arguments, eventArgIdx)

        self._listenerList.add(lm)


    def removeListener(self, eventType, target, method=None):
        # Removes the event listener methods matching
        # the given given paramaters.
        if method is None:
            if self._listenerList is not None:
                for lm in self._listenerList:
                    if lm.matches(eventType, target):
                        self._listenerList.remove(lm)
                        return
        else:
            if isinstance(method, basestring):
                methodName = method

                method = getattr(target, methodName)

                if method is None:
                    raise ValueError()

                # Remove the listeners
                if self._listenerList is not None:
                    for lm in self._listenerList:
                        if lm.matches(eventType, target, method):
                            self._listenerList.remove(lm)
                            return
            else:
                if self._listenerList is not None:
                    for lm in self._listenerList:
                        if lm.matches(eventType, target, method):
                            self._listenerList.remove(lm)
                            return


    def removeAllListeners(self):
        """Removes all listeners from event router."""
        self._listenerList = None


    def fireEvent(self, event):
        """Sends an event to all registered listeners. The listeners will
        decide if the activation method should be called or not.

        @param event:
                   the Event to be sent to all listeners.
        """
        # It is not necessary to send any events if there are no listeners
        if self._listenerList is not None:
            # Make a copy of the listener list to allow listeners to be added
            # inside listener methods. Fixes #3605.

            # Send the event to all listeners. The listeners themselves
            # will filter out unwanted events.
            listeners = list(self._listenerList)
            for listener in listeners:
                listener.receiveEvent(event)


    def hasListeners(self, eventType):
        """Checks if the given Event type is listened by a listener registered
        to this router.

        @param eventType:
                   the event type to be checked
        @return: true if a listener is registered for the given event type
        """
        if self._listenerList is not None:
            for lm in self._listenerList:
                if lm.isType(eventType):
                    return True
        return False


    def getListeners(self, eventType):
        """Returns all listeners that match or extend the given event type.

        @param eventType:
                   The type of event to return listeners for.
        @return: A collection with all registered listeners. Empty if no
                listeners are found.
        """
        listeners = list()
        if self._listenerList is not None:
            for lm in self._listenerList:
                if lm.isOrExtendsType(eventType):
                    listeners.append(lm.getTarget())
        return listeners
