import YamlTest
from here import *
from test import assertEquals
from types import DictType, ListType, TupleType, InstanceType

"""
This is experimental code.  It generates simulated events
for a pull-based YAML parser.
"""

class MockEmitter:
    """
    A pushed-based emitter may be more awkward to write, 
    because you have to keep track of more state.
    """
    def __init__(self):
        self.events = []

    def append(self, *event):
        self.events.append(event)        

    def pushScalar(self, data):
        self.append('getType', 'scalar')
        self.append('getScalar', data)

    def appendType(self, typ):
        self.append('getType', typ)

    def startSeq(self):
        self.appendType('seq')
        
    def endSeq(self):
        self.appendType(None)

    def startMap(self):
        self.appendType('map')
        
    def endMap(self):
        self.appendType(None)

class Dumper:
    def __init__(self, emitter):
        self.emitter = emitter

    def dump(self, data):
        if type(data) in (ListType, TupleType):
            return self.dumpList(data)
        elif type(data) is DictType:
            return self.dumpDict(data)
        else:
            self.emitter.pushScalar(data)

    def dumpList(self, data):
        self.emitter.startSeq()
        for item in data:
            self.dump(item)
        self.emitter.endSeq()

    def dumpDict(self, data):
        self.emitter.startMap()
        keys = data.keys()
        keys.sort() # XXX - only for now
        for key in keys:
            value = data[key]
            self.dump(key)
            self.dump(value)
        self.emitter.endMap()

def mockEvents(data):
    emitter = MockEmitter()
    dumper = Dumper(emitter)
    dumper.dump(data)
    return emitter.events

class Test(YamlTest.YamlTest):

    def testScalar(self):
        assertEquals(mockEvents('foobar'), self.scalar('foobar'))

    def scalar(self, data):
        return [ 
            ('getType', 'scalar'),
            ('getScalar', data)
        ]

    def list123(self):
        (result) = (
            [('getType', 'seq' )] +
            self.scalar(1) +
            self.scalar(2) +
            self.scalar(3) +
            [( 'getType', None )])
        return result

    def testList(self):
        assertEquals(mockEvents([1,2,3]), self.list123())

    def dictFoobar(self):
        (result) = (
            [('getType', 'map')] +
            self.scalar('bar') +
            self.scalar(2) + 
            self.scalar('foo') +
            self.scalar(1) +
            [( 'getType', None)])
        return result

    def testDict(self):
        events = mockEvents({'foo': 1, 'bar': 2})
        assertEquals(events, self.dictFoobar())

    def testListDict(self):
        events = mockEvents([ [1,2,3], {'foo': 1, 'bar': 2} ])
        self.assertEquals(
            events,
            [('getType', 'seq' )] +
            self.list123() +
            self.dictFoobar() + 
            [('getType', None)])            

if __name__ == '__main__':
    import unittest
    unittest.main()
