"""Dispatch-processor API

This is a post-processing processor API based on dispatching
each element of a result tree in a top-down recursive call
structure.  It is the API used by the SimpleParseGrammar Parser,
and likely will be the default processor for SimpleParse.
"""
from simpleparse.processor import Processor

class DispatchProcessor(Processor):
    """Dispatch results-tree in a top-down recursive pattern with
    attribute lookup to determine production -> method correspondence.

    To use the class, subclass it, then define methods for
    processing each production.  The methods should take this form:
        def production_name( self, (tag, left, right, children), buffer):
            pass
    Where children may be either a list, or None, and buffer is the
    entire buffer being parsed.
    """
    def __call__( self, value, buffer ):
        """Process the results of the parsing run over buffer

        Value can either be: (success, tags, next) for a top-level
        production, or (tag, left, right, children) for a non-top
        production.
        """
        if len( value ) == 3:
            # is a top-level production
            success, tags, next = value
            if success:
                result = dispatchList( self, tags, buffer )
                return success, result, next
            else:
                return success, tags, next
        else:
            # is a 4-item result tuple/tree
            return dispatch( self, value, buffer )


def dispatch( source, tag, buffer ):
    """Dispatch on source for tag with buffer

    Find the attribute or key tag[0] of source,
    then call it with (tag, buffer)
    """
    try:
        function = getattr (source, tag[0])
    except AttributeError:
        try:
            function = source[tag[0]]
        except:
            raise AttributeError( '''No processing function for tag "%s" in object %s! Check the parser definition!'''%(tag[0], repr(source)))
    return function( tag, buffer )

def dispatchList( source, taglist, buffer ):
    """Dispatch on source for each tag in taglist with buffer"""
    if taglist:
        return list(map( dispatch, [source]*len(taglist), taglist, [buffer]*len(taglist)))
    else:
        return []

def multiMap( taglist, source=None, buffer=None ):
    """Convert a taglist to a mapping from tag-object:[list-of-tags]
    
    For instance, if you have items of 3 different types, in any order,
    you can retrieve them all sorted by type with multimap( childlist)
    then access them by tagobject key.
    """
    set = {}
    if not taglist:
        return set
    for tag in taglist:
        key = tag[0]
        if source and buffer:
            tag = dispatch( source, tag, buffer )
        set.setdefault(key,[]).append( tag )
    return set
def singleMap( taglist, source=None, buffer=None ):
    """Convert a taglist to a mapping from tag-object:tag, overwritting early with late tags"""
    set = {}
    if not taglist:
        return set
    for tag in taglist:
        key = tag[0]
        if source and buffer:
            tag = dispatch( source, tag, buffer )
        set[key] = tag
    return set
    
def getString(info, buffer):
    """Return the string value of the tag passed"""
    (tag, left, right, sublist) = info
    return buffer[ left:right ]

try:
    from simpleparse.stt.TextTools import countlines
except ImportError:
    def lines( start=None, end=None, buffer=None ):
        """Return line number in file at character index (string.count version)"""
        return buffer.count('\n', start or 0, end or len(buffer))
else:
    def lines( start=None, end=None, buffer=None ):
        """Return line number in file at character index (mx.TextTools version)"""
        return countlines (buffer[start or 0:end or len(buffer)])
    
    
