class Subject:
	def __init__(self):
		self.observers=[]

	def attach(self,observer):
		self.observers.append(observer)

	def notify(self):
		for o in self.observers:
			o.update()

class Observer:
	def __init__(self):
		pass

	def update(self):
		pass

class LevelPopObserver(Observer):
	def __init__(self, popcan):
		self.__popcan=popcan

	def update(self):
		print "#" * (self.__popcan.get_amount()/10)
		print ""

class SimplePopObserver(Observer):
	def __init__(self, popcan):
		self.__popcan=popcan

	def update(self):
		print self.__popcan.to_s()

class EmptyPopObserver(Observer):
	def __init__(self, popcan):
		self.__popcan=popcan

	def update(self):
		if self.__popcan.get_amount()==0:
			print "!!!! GET SOME MORE POP!!!!"

class PopCan(Subject):
	""" 
	A PopCan contains an amount of soda. 
	It must be open in order to drink from it.
	PopCans can not be refilled, nor can they be closed.
	"""

	def __init__(self, initialAmount=355, brand="Coke"):
		""" 
		Create a new closed can of Pop. 
		Keyword arguments:
		initialAmount - the initial amount of soda in the can, must be >=0 (default 355)
		brand - the brand of soda in the can (default "Coke")
		"""
		Subject.__init__(self)
		if initialAmount<0: 
			initialAmount=0
		self.__brand=brand
		""" the brand of soda (ie Coke, Barqs, RootBeer) """
		self.__amount=initialAmount
		""" the amount of soda in this PopCan. At all times amount>=0 """
		self.__open=False
		""" whether self is open or closed """
	def get_amount(self):
		return self.__amount

	def is_empty(self):
		return self.__amount==0

	def drink(self, drinkAmount):
		"""
		Remove drinkAmount of soda from self. 
		If self is open or drinkAmount<0, this has no effect on self.
		If drinkAmount>the amount in self, then self will be emptied.
		amount - the amount of pop to drink
		returns - self
		"""
		if self.__open==True and drinkAmount>0:
			self.__amount=self.__amount-drinkAmount
			if self.__amount<0: self.__amount=0
			self.notify()
		return self

	def chug(self): 
		"""
		Try to drink all the soda from self.
		returns - self
		"""
		self.drink(self.__amount)
		return self

	def open(self): 
		"""
		Open self, so someone can drink some soda.
		returns - self
		"""
		self.__open=True
		self.notify()
		return self

	def to_s(self):
		"""
		returns - a string representation of self
		"""
		return "amount="+str(self.__amount)+" open="+str(self.__open)

if __name__=='__main__':
	p1=PopCan()
	so=SimplePopObserver(p1)
	lo=LevelPopObserver(p1)
	eo=EmptyPopObserver(p1)

	p1.attach(so)
	p1.attach(lo)
	p1.attach(eo)

	p1.open()
	p1.drink(20)
	p1.drink(20)
	p1.drink(20)
	p1.drink(300)
	p1.drink(500)
	p1.drink(500)

