from Queue import Queue
from types import FunctionType
from dp2 import corpora, predicates

class Ghost:
    """effectively, a Generic Function...

    ... with an arbitrary dispatch-method...
    ... where methods are really, just, generically, delegates...
    ... and where new methods/delegates can be easily added to the *tree*.

    This class exists only to serve as a base for derived ghost-classes--
    for reduction of redundant code and so that isinstance(..., Ghost)
    can be used generically to test if pyobjs are first-class ghosts.

    The Ghost class is itself usable, but does little beside wrapping
    a single callable pyobj with ghost-methods.
    """
    def __init__(self, handler):
        # maybe this should take `delegator' and `selector' arguments....
        # Naaaahhh--that'd be reason to define a subclass--let's be pseudo-OO
        # about it--this *is* still Python....

        self.handler = handler

    def delegate(self, match, handler):
        pass

    def undelegate(self, match=None, handler=None):
        pass

    def list_delegates(self):
        """return list of delegates, not including default handler
        """
        return []

    def find_handler(self, *object):
        return self.handler

    def apply(self, handler, corpora):
        return apply(handler, corpora)

    def handle_object(self, *object):
        return self.apply(self.find_handler(*object), object)

    def __call__(self, *object):
        return self.handle_object(*object)

class PredicateGhost(Ghost):
    """a very powerful ghost that dispatches on arbitrary predicates
    """
    def __init__(self, defhandler):
        self.predicates = [None]
        self.map = {None: defhandler}
        self.rmap = {defhandler: None}

    def delegate(self, predicate, handler, superhandler=None):
        if isinstance(superhandler, int): #superpredicate N
            self.map[self.predicates[superhandler]].delegate(predicate,
                                                             handler)
        elif superhandler is None:
            self.predicates.insert(0, predicate)
            self.map[predicate] = handler
            self.rmap[handler] = predicate
        elif isinstance(superhandler, FunctionType): #superpredicate
            self.map[superhandler].delegate(predicate, handler)

    def undelegate(self, match=None, handler=None):
        if match:
            if match in self.predicates:
                self.predicates.remove(match)
                del self.map[match]
        if handler:
            if self.rmap.has_key(handler):
                h = self.rmap[handler]
                self.predicates.remove(h)
                del self.map[h], self.rmap[handler]

    def list_delegates(self):
        mcopy = self.map.copy()
        del mcopy[None]
        return mcopy.values()

    def find_handler(self, *object): #, depth=0):
        depth = 0
        for pred in self.predicates:
            if not pred: #we've hit the bottom of the stack
                return self.map[pred]
            else:
                use_this = pred(*object)
                if callable(use_this):
                    return use_this
                elif use_this:
                    if depth: #almost there--go deeper!
                        return self.map[pred].find_handler(object, depth-1)
                    else:
                        return self.map[pred] #found it!

class Scheduler(Ghost):
    def __init__(self, dispatcher):
        self.queue = Queue()
        self.running = False
        self.dispatch = dispatcher
        Ghost.__init__(self, self.queue.put)

    def iteration(self):
        event = self.queue.get()
        if event:
            if isinstance(event, (list, tuple)):
                map(self, event)
            else:
                event = self.dispatch(event)
                if event:
                    self(event)
        else:
            print 'discarding false event:', event

    def loop(self, condition=None):
        """Run The Event-Loop.

        This can be called with a nullary predicate to invoke a sub-loop
        and produce modality, e.g.: to implement actions that block
        waiting for responses.
        """
        if not callable(condition):
            self.running = True
            condition = lambda: self.running
        while condition(): # and self.running?
            self.iteration()

    def stop(self):
        self.running = False
        self(None)
