from time import time
from sys import maxint

from DelayedApplyMixin import DelayedApplyMixin

class ConcurrentObject(DelayedApplyMixin):
	"""
	Inherit from this guy to make an object with everything it needs to go in a Concurrent list.
	
	Update() is performed once per cycle.

	Draw() is performed once per cycle to update visual representation.
	"""
	def __init__(self):
		DelayedApplyMixin.__init__(self)
		self.priority = 1
		self.frequency = 1
	
	def Pump(self):
		"""
		Call methods by name and pass arguments too.
		"""
		self.DoAll()

class Concurrent(ConcurrentObject):
	"""
	This high level state machine runs the update and draw routines of all game objects in order of priority.
	"""
	def __init__(self):
		ConcurrentObject.__init__(self)
		self.objects = []
		self.removes = []
		self.adds = []
		self.frame = 0
		self.lastTime = time()
	
	def Run(self):
		self.Pump()
		self.Update()
		self.Draw()
	
	def Pump(self):
		ConcurrentObject.Pump(self)
		# make every object look at all messages pending
		[o.Pump() for o in self.objects if hasattr(o, "Pump") and not self.frame % o.frequency]
	
	def Update(self):
		self.frame += 1
		# make every object update it's current state
		[o.Update() for o in self.objects if hasattr(o, "Update") and not self.frame % o.frequency]
		# make additions and removals of objects pending
		[self.objects.append(o) for o in self.adds]
		[self.objects.remove(o) for o in self.removes]
		
		# reset additions and removes arrays
		if len(self.removes):
			self.removes = []
		
		if len(self.adds):
			self.objects.sort(lambda x, y: cmp(x.priority, y.priority))
			self.adds = []
		
		self.lastTime = time()
	
	def Draw(self):
		[o.Draw() for o in self.objects if hasattr(o, "Draw")]
	
	def Add(self, object):
		self.adds.append(object)
	
	def Remove(self, object):
		self.removes.append(object)
	
	def Clear(self):
		self.objects = []
	
	def Elapsed(self, max=maxint):
		return min(time() - self.lastTime, max)

