class Human:
    def __init__(self, name):
        self.name = name

    def greet(self):
        return "Hello, I'm " + self.name

    @staticmethod
    def getTypicalWeight():
        return "150"

    @staticmethod
    def getLastName(FirstName):
        LastNames = {   'Bart' : 'Simpson',
                        'Leela' : 'Turanga',
                        'James' : 'Bond'}
        return LastNames[FirstName]

class Friendship:
    get friend_of(self):
        return self._friend_of
    set friend_of(self, v):
        self._friend_of = v


# test super/mixin
@mixin(Friendship)
class Friend(Human):
    def __init__(self, name, friend_of):
        super(name)
        self._friend_of = friend_of
        # test non-super class call
        self = {}
        Object.assign(self, {screaming_name: name.toUpperCase()})
        # if there is extra `var self = this` the below will fail 
        assert.notEqual(this, self)

    def greet(self):
        return "Yo, it's me, " + self.name
        
    # should be injected by mixin
    #get friend_of(self):
    #    return self._friend_of
        
    def nickname(self, name):
        self.name = name

    @staticmethod
    def factory(*args):
        return Friend(*args)
       
bob = Human("Bob")
joe = Friend("Joe", "bob")

assert.equal(joe.greet(), "Yo, it's me, Joe")
assert.equal(joe.friend_of, 'bob')
joe.friend_of = bob
assert.equal(joe._friend_of, bob)
assert.equal(joe.friend_of, bob)
assert.ok(isinstance(joe, Friend))
assert.ok(isinstance(joe, Human))

angela = Friend.factory("Angela", joe)
assert.equal(angela.greet(), "Yo, it's me, Angela")
assert.equal(angela.friend_of, joe)


# generators
def gen():
    def f(a, y):
        return a+y
        
    ten = 10
    yield 1
    yield
    yield ten * 10, 200, 300
    yield from [11,22]
    yield def():
            pass
    a = yield 5
    assert.equal(a, 'hi!')
    a = yield def():
                pass
    return f(yield a, yield 'almost done')

g = gen()
assert.equal(g.next().value, 1)
assert.equal(g.next().value, undefined)
assert.ok(g.next().value == [100, 200, 300])

assert.equal(g.next().value, 11)
assert.equal(g.next().value, 22)

assert.ok(isinstance(g.next('hi!').value, Function))
assert.equal(g.next().value, 5)
f = g.next('hi!').value
assert.ok(isinstance(f, Function))
assert.equal(g.next(f).value, f)
assert.equal(g.next('a').value, 'almost done')
t = g.next('b')
assert.equal(t.value, 'ab')
assert.equal(t.done, True)

# generators as class methods
class Barman(Human):
    def __init__(self, name):
        super(name)
    
    def gimme_drink(self):
        wish = yield 'pepsi'
        wish = yield wish 
        yield wish
        return 'go home'
        
    @staticmethod
    def call_barman():
        # small hack to turn a function into a generator with single return
        if 0: yield 
        return Barman('Tom')

assert.ok(Object.getPrototypeOf(Barman.call_barman) is Object.getPrototypeOf(JS('function* () {}')))        
tom = Barman.call_barman().next().value
assert.equal(tom.name, 'Tom')
tom_gimme_drink = tom.gimme_drink()
assert.equal( tom_gimme_drink.next().value, 'pepsi' )
assert.equal( tom_gimme_drink.next('beer').value, 'beer' )
assert.equal( tom_gimme_drink.next('whiskey').value, 'whiskey' )
assert.equal( tom_gimme_drink.next('more').value, 'go home' )

# yield in parentheses 
def echo(v):
    return v
    
def yield_in_parens():
    def concat3(a,b,c):
        return a+b+c
        
    a = (yield 1)('hi')
    a = (yield a).prop
    yield echo((yield a).prop)
    yield concat3('blah-', (yield a).prop, '-blah')
    yield (yield 5) + 2

    
    
tmp = yield_in_parens()
assert.equal(tmp.next().value, 1)
assert.equal(tmp.next(echo).value, 'hi')
assert.equal(tmp.next({prop: 'blah'}).value, 'blah')
assert.equal(tmp.next({prop: 'blah'}).value, 'blah')
assert.equal(tmp.next({prop: 'blah'}).value, 'blah')
assert.equal(tmp.next({prop: 'blah'}).value, 'blah-blah-blah')
assert.equal(tmp.next().value, 5)
assert.equal(tmp.next(10).value, 12)

# es6 hash short notation
key_val = 'val'
es6_hash = {a:'av', key_val, b:'bv'}
assert.equal(es6_hash['key_val'], 'val')

es6_hash = { key_val, b:'bv'}
assert.equal(es6_hash['key_val'], 'val')

es6_hash = {  b:'bv', key_val}
assert.equal(es6_hash['key_val'], 'val')

es6_hash = { key_val }
assert.equal(es6_hash['key_val'], 'val')

es6_hash = { (key_val):key_val, key_val, b:'bv'}
assert.equal(es6_hash['val'], 'val')
assert.equal(es6_hash['key_val'], 'val')

