import time
import abc

class Timer(object):
	def __init__(self, name='Timer', listener=None):
		self.name = name
		self.listener = listener
		self.isActive = False
		self.mode = 'periodic'
		self.interval = 0
		self.elapseTime = 0
		self.count = 0

	def start(self, interval, mode='periodic'):
		now = time.time()
		self.interval = interval
		self.mode = mode
		self.elapseTime = now + interval
		self.isActive = self.elapseTime > now
		pass

	def stop(self):
		self.isActive = False
		self.count = 0

	def __str__(self):
		return self.name

	def isElapsed(self):
		result = False
		now = time.time()
		if self.isActive:
			if self.elapseTime <= now:
				result = True
				if 'periodic' in self.mode:
					self.start(self.interval, self.mode)

		return result

class TimerListener(abc.ABC):
	def __init__(self):
		pass

	@abc.abstractmethod
	def onTimer(self, timer):
		pass

class TimerManager(object):
	def __init__(self):
		self.timers = []
		pass

	def registerTimer(self, timer):
		self.timers.append(timer)

	def process(self):
		for timer in self.timers:
			if timer.isElapsed():
				if timer.listener is not None:
					timer.listener.onTimer(timer)
					timer.count += 1

	def getMinTimeout(self, default=1.0):
		minTimeout = default
		timeouts = []
		for timer in self.timers:
			now = time.time()
			if timer.isActive:
				timeout = max(0, timer.elapseTime-now)
				timeouts.append(timeout)

		if len(timeouts) > 0:
			minTimeout = min(timeouts)

		return minTimeout

if __name__ == '__main__':
	class Test (TimerListener):
		def __init__(self):
			self.timerMgr = TimerManager()
			self.timer200 = Timer('Timer 200', self)
			self.timer500 = Timer('Timer 500', self)
			self.timer1000 = Timer('Timer 1000', self)
			self.timerMgr.registerTimer(self.timer200)
			self.timerMgr.registerTimer(self.timer500)
			self.timerMgr.registerTimer(self.timer1000)

			self.timer200.start(0.200)
			self.timer500.start(0.500)
			self.timer1000.start(1.000)
			pass

		def onTimer(self, timer):
			print ("{}, Count: {}".format(timer, timer.count))
			if timer.count == 30:
				timer.stop()

		def run(self):
			while(True):
				wait = self.timerMgr.getMinTimeout(None)
				if wait is None:
					break
				time.sleep(wait)

				self.timerMgr.process()

	test = Test()
	test.run()

