# -*- coding: utf-8 -*-
"""
Décorateur, métaclasse et classe mixin pour faciliter
l'implémentation des gestionnaires d'événements pygame.

Utilisation :
- hériter de EventHandlerMixin
- décorer les méthodes gestionnaires d'événements avec le décorateur 'event_handler'
  en passant en paramètre un ou plusieurs codes d'événement pygame

Il n'existe aucune contrainte sur le nommage de la méthode décorée.
La méthode gestionnaire d'événement reçoit l'événement pygame comme unique paramètre.

par exemple :

import pygame
class Machin(pygame.sprite.Sprite, EventHandlerMixin) :
    
    # .../...
    
    @event_handler(pygame.KEYDOWN)
    def handleKeyDown(self, event) :
        pass
    

$Id$
$URL$
"""
import types
import pygame
from StringIO import StringIO
from log import console, eventLogger

class _EventDispatcher :
    def __init__(self) :
        self.registry = {}
        
    def addEventListener(self, eventType, listener) :
        if self.registry.has_key(eventType) :
            self.registry[eventType][listener] = True
        else :
            self.registry[eventType] = {listener:True}
    
    def removeEventListener(self, eventType, listener) :
        try :
            del self.registry[eventType][listener]
        except KeyError :
            console.debug("no listener to remove")
    
    def dispatchEvents(self) :
        events = pygame.event.get()
        for event in events :
            eventLogger.info(event)
            listeners = self.registry.get(event.type, {})
            for listener in listeners.keys() :
                listener(event)

    def reset(self) :
        self.registry = {}
    
    def __repr__(self) :
        out = StringIO()
        keys = self.registry.keys()
        keys.sort()
        for k in keys :
            print >> out, "event", k
            for listener in self.registry[k].keys() :
                print >> out, listener.__name__
        out.seek(0)
        return out.read()
        

EventDispatcher = _EventDispatcher()

def event_handler(*eventTypes) :
    def markFunctionAsListener(m) :
        m.__islistener__ = True
        m.__eventtypes__ = eventTypes
        return m
    return markFunctionAsListener


class EventInitializer(type):
    
    def __init__(cls, name, bases, dict) :
        def init_listeners(self) :
            for k, v in dict.items() :
                if isinstance(v, types.FunctionType) and hasattr(v, '__islistener__') :
                    listener = getattr(self, k)
                    for eventType in v.__eventtypes__ :
                        EventDispatcher.addEventListener(eventType, listener)
        
        def ctor(self, *args, **kw) :
            default_ctor = dict.get('__init__')
            if not default_ctor :
                super(cls, self).__init__(*args, **kw)
            else :
                default_ctor(self, *args, **kw)
            init_listeners(self)
        
        cls.__init__ = ctor


class EventHandlerMixin(object) :
    __metaclass__ = EventInitializer
