"""
R.E.L.
Registed Event Listener
module that uses various methods to emulate event-like behavior
functions:
    read(socket, callback, *args)
    write(socket, callback, *args)
    timeout(delay, callback, *args)
    signal(sig, callback, *args)
    event(callback,arg=None,evtype=0,handle=None)
    dispatch()
    loop()
    abort()
    init()
"""
import sys, threading, time, pprint
from registrar import SelectRegistrar, PollRegistrar, EpollRegistrar, KqueueRegistrar
from listener import EV_PERSIST, EV_READ, EV_SIGNAL, EV_TIMEOUT, EV_WRITE
try:
    import event as pyevent
except ImportError:
    pyevent = None
 
def override():
    if 'event' in sys.modules and sys.modules['event'].__class__.__name__ == "fakemodule":
        return
    class fakemodule(object):
        def __init__(self, **kwargs):
            for key, val in kwargs.items():
                setattr(self, key, val)
    pyevent_03_keys = [
        'EV_PERSIST',
        'EV_READ',
        'EV_SIGNAL',
        'EV_TIMEOUT',
        'EV_WRITE',
        '__author__',
        '__builtins__',
        '__copyright__',
        '__doc__',
        '__event_exc',
        '__file__',
        '__license__',
        '__name__',
        '__url__',
        '__version__',
        'abort',
        'dispatch',
        'event',
        'init',
        'loop',
        'read',
        'signal',
        'sys',
        'timeout',
        'write'
    ]
    kw = {}
    for key in pyevent_03_keys:
        kw[key] = globals().get(key, None)
    fakeevent = fakemodule(**kw)
    sys.modules['event'] = fakeevent
 
running = False
registrar = None
threader = None
verbose = False
supported_methods = ['pyevent','epoll','poll','kqueue','select']
 
mapping = {
    'select': SelectRegistrar,
    'epoll': EpollRegistrar,
    'poll': PollRegistrar,
    'kqueue': KqueueRegistrar
}
 
def _display(text):
    if verbose:
        print "Registered Event Listener output:",text
 
def __report():
    print "=" * 60
    print "rel status report".center(60)
    print str(time.time()).center(60)
    print "-" * 60
    print "events".center(60)
    pprint.pprint(registrar.events)
    print "signals".center(60)
    pprint.pprint(registrar.signals)
    print "timers".center(60)
    pprint.pprint(registrar.timers)
    print "=" * 60
    return True
 
class Thread_Checker(object):
    def __init__(self, threaded):
        self.active = threaded and registrar == pyevent
        if threaded and registrar != pyevent:
            _display('GIL hack unnecessary for non-pyevent registrar. GIL hack disabled.')
        self.go()
 
    def go(self):
        if self.active:
            _display('Thread Checking Enabled')
            self.checker = timeout(1,self.check)
            self.sleeper = timeout(0.01, self.release)
            self.sleeper.delete()
 
    def stop(self):
        if self.active:
            _display('Thread Checking Disabled')
            self.checker.delete()
            self.sleeper.delete()
 
    def release(self, *args):
        time.sleep(.005)
        return True
 
    def check(self):
        if threading.activeCount() > 1:
            if not self.sleeper.pending():
                _display('Enabling GIL hack')
                self.sleeper.add(.01)
        else:
            if self.sleeper.pending():
                _display('Disabling GIL hack')
                self.sleeper.delete()
        return True
 
def check_init():
    if not registrar:
        initialize()
 
def get_registrar(method):
    if method == 'pyevent':
        if not pyevent:
            raise ImportError, "could not import event"
        return pyevent
    if method in mapping:
        return mapping[method]()
    raise ImportError
 
def initialize(methods=supported_methods,options=()):
    """
    initialize(methods=['pyevent','epoll','poll','kqueue','select'],options=[])
    possible options:
        'verbose' - prints out certain events
        'report' - prints status of non-pyevent registrar every 5 seconds
        'strict' - ONLY try specified methods
        'threaded' - enable GIL hack -- pyevent only!
    """
    global registrar
    global threader
    global verbose
    verbose = "verbose" in options
    if "strict" not in options:
        for m in supported_methods:
            if m not in methods:
                methods.append(m)
    for method in methods:
        try:
            registrar = get_registrar(method)
            break
        except ImportError:
            _display('Could not import "%s"'%method)
    if registrar is None:
        raise ImportError, "Could not import any of given methods: %s" % (methods,)
    _display('Initialized with "%s"'%method)
    threader = Thread_Checker('threaded' in options)
    if "report" in options:
        if registrar == pyevent:
            _display('Reporting disabled in pyevent. Choose epoll, poll, or select to enable reporting.')
        else:
            timeout(5,__report)
    return method
 
def read(sock,cb,*args):
    check_init()
    return registrar.read(sock,cb,*args)
 
def write(sock,cb,*args):
    check_init()
    return registrar.write(sock,cb,*args)
 
def timeout(delay, cb, *args):
    check_init()
    return registrar.timeout(delay,cb,*args)
 
def signal(sig, callback, *args):
    check_init()
    return registrar.signal(sig,callback,*args)
 
def dispatch():
    global running
    if not running:
        running = True
        check_init()
        registrar.dispatch()
 
def loop():
    check_init()
    registrar.loop()
 
def abort():
    global running
    running = False
    check_init()
    registrar.abort()
 
def init():
    global running
    running = False
    check_init()
    threader.stop()
    registrar.init()
    threader.go()
 
def event(callback,arg=None,evtype=0,handle=None):
    check_init()
    return registrar.event(callback,arg,evtype,handle)