class RtfExpr:
    def __init__(self, nodes):
        self.nodes = nodes

    def evaluate(self, context):
        processor = context.processor
        processor.pushResultTree(context.currentInstruction.baseUri)
        try:
            for child in self.nodes:
                child.instantiate(context, processor)
            result = processor.popResult()
        finally:
            #This causes assertion error to be thrown in the event
            #of an exception in instantiating child nodes, which
            #masks the true exception.  Find a better way to clean up --UO
            #result = processor.popResult()
            pass
        return result

    def pprint(self, indent=''):
        print indent + str(self)

    def __str__(self):
        return '<RtfExpr at %x: %s>' % (id(self), str(self.nodes))
        

class SortedExpression:
    def __init__(self, expression, sortKeys):
        self.expression = expression
        self.sortKeys = sortKeys or []
        return

    def __str__(self):
        return "<SortedExpr at 0x%x: %s>" % (id(self), repr(self.expression))
    
    def compare(self, (node1, keys1), (node2, keys2)):
        for i in xrange(len(self.cmps)):
            diff = self.cmps[i](keys1[i], keys2[i])
            if diff: return diff
        # compare in document order
        # WARNING - This assumes domlette trees
        #return cmp(node1.docIndex, node2.docIndex)
        return cmp(node1, node2)

    def evaluate(self, context):
        if self.expression is None:
            base = context.node.childNodes
        else:
            base = self.expression.evaluate(context)
            if type(base) is not type([]):
                raise TypeError('expected nodeset, %s found' % type(base).__name__)

        # create initial sort structure
        state = context.copy()
        size = len(base)
        nodekeys = [None]*size
        pos = 1
        for node in base:
            context.node, context.position, context.size = node, pos, size
            context.currentNode = node
            keys = map(lambda sk, c=context: sk.evaluate(c), self.sortKeys)
            nodekeys[pos - 1] = (node, keys)
            pos += 1
        context.set(state)

        # get the compare function for each of the sort keys
        self.cmps = map(lambda sk, c=context: sk.getComparer(c), self.sortKeys)
        nodekeys.sort(self.compare)
        # extract the sorted nodes
        return map(lambda nk: nk[0], nodekeys)
