from dp2.ghosts import Ghost, PredicateGhost, Scheduler
from dp2.corpora import Path, Request, Presentation
from dp2.predicates import is_path

def dispatch(a):
    """dispatch(affection)

    Apply an affection to its target; assumes that the target is callable.
    """
    return a.target(a)

def resolve(request, levels=-1):
    """resolve(request, levels=N)

    Resolves a path, presents the ultimate head, unless N is given,
    in which case at most N levels of dereferencing are performed.
    """
    value = request.item
    while is_path(value) and levels:
        value = value.head
        levels -= 1
    return Presentation(actor=request.target,
                        object=value,
                        target=request.actor)

def send(aff):
    target = aff.target
    return Request(actor=lambda p: p.object(aff), item=target, target=resolve)

dispatch = PredicateGhost(dispatch)
dispatch.delegate(lambda a: is_path(a.target), send)

schedule = Scheduler(dispatch)
