# -*- python -*-

class Food:
    def __init__(self, name, energy):
        self.name = name
        self.energy = energy

    def eaten(self):
        return self.energy

class Meat(Food):
    def __init__(self, name, energy):
        self.valid = True
        Food.__init__(self, name, energy)

    def eaten(self):
        if not self.valid: raise "bad food"
        self.valid = False
        return Food.eaten(self)

class Animal:
    def __init__(self, name, energy, when_slaughtered, food_accepted):
        self.valid = True
        self.name = name
        self.energy = energy
        self.food_accepted = food_accepted
        self.when_slaughtered = when_slaughtered

    def eat(self, food):
        if not self.valid: raise "bad animal"
        
        if self.food_accepted(food.name):
            self.energy += food.eaten()
        else:
            raise "%s doesn't accept food %s" % (self.name, food.name)

    def slaughter(self):
        if not self.valid: raise "bad animal"

        self.valid = False
        return Meat(self.when_slaughtered, self.energy)
        

meats = [ "beef", "dead_rabbit", "dead_human" ]

def is_meat(food_name): return food_name in meats

def new_grass(energy): return Food("grass", energy)
def new_carrot(energy): return Food("carrot", energy)

def new_cow(energy): return Animal("cow", energy, "beef", lambda n: n == "grass")
def new_rabbit(energy): return Animal("rabbit", energy, "dead_rabbit", lambda n: n == "carrot")
def new_human(energy): return Animal("human", energy, "dead_human", lambda n: n == "carrot" or is_meat(n))

grass    = new_grass(5)
carrot   = new_carrot(10)

a_rabbit      = new_rabbit(100)
a_cow         = new_cow(1000)
a_human       = new_human(300)
another_human = new_human(350)

for o in [ a_rabbit, a_cow, a_human ]:
    print "%s -> %d" % (o.name, o.energy)

a_rabbit.eat(carrot)
a_cow.eat(grass)

a_dead_rabbit = a_rabbit.slaughter()
a_beef = a_cow.slaughter()

a_human.eat(carrot)
a_human.eat(carrot)
a_human.eat(a_beef)
a_human.eat(a_dead_rabbit)

a_human.eat(another_human.slaughter())

if a_human.energy != 1785: raise "failed"


should_fail = """

new_cow(10).slaughter().eat(grass) # meat (food) can't eat
new_cow(10).slaughter().slaughter() # meat (food) can't be slaughtered
carrot.eat(grass)      # vegetable (food) can't eat
carrot.slaughter()     # vegetable (food) can't be slaughtered

new_cow(10).eat(carrot) # cow do not eat carrot
new_cow(10).eat(new_cow(10).slaughter()) # cow do not eat beef
a_human.eat(new_cow(10)) # can't eat live animals
a_human.eat(grass)     # human do not eat grass
a_human.eat(a_beef)    # a_beef is already eaten
a_cow.eat(grass)       # a_cow is dead, it can't eat
a_cow.slaughter()      # a_cow is dead, it can't be slaughtered again

"""

for i in should_fail.split("\n"):
    try:
        eval(i)
    except:
        continue
    raise "%s should_have_failed" % i
