
from time import time
from threading import Thread

try: # for Python < 2.3
	True, False
except NameError:
	True, False = 1, 0


class TaskHandler:
	"""The task handler.

	While the Task class only knows what task to perform with the run()-method,
	the TaskHandler has all the knowledge about the periodicity of the task.
	Instances of this class are managed by the Scheduler in the scheduled,
	running and onDemand dictionaries.

	"""


	## Init ##

	def __init__(self, scheduler, start, period, task, name):
		self._scheduler = scheduler
		self._task = task
		self._name = name
		self._thread = None
		self._isRunning = False
		self._suspend = False
		self._lastTime = None
		self._startTime = start
		self._registerTime = time()
		self._reregister = True
		self._rerun = False
		self._period = abs(period)


	## Scheduling ##

	def reset(self, start, period, task, reregister):
		self._startTime = start
		self._period = abs(period)
		self._task = task
		self._reregister = reregister

	def runTask(self):
		"""Run this task in a background thread."""
		if self._suspend:
			self._scheduler.notifyCompletion(self)
			return
		self._rerun = False
		self._thread = Thread(None, self._task._run, self.name(), (self,))
		self._isRunning = True
		self._thread.start()

	def reschedule(self):
		"""Determine whether this task should be rescheduled.

		Increments the startTime and returns true if this is
		a periodically executed task.

		"""
		if self._period == 0 or not self._reregister:
			return False
		else:
			if self._lastTime - self._startTime > self._period:
				# if the time taken to run the task exceeds the period
				self._startTime = self._lastTime + self._period
			else:
				self._startTime += self._period
			return True

	def notifyCompletion(self):
		self._isRunning = False
		self._lastTime = time()
		self._scheduler.notifyCompletion(self)

	def notifyFailure(self):
		self._isRunning = False
		self._lastTime = time()
		self._scheduler.notifyFailure(self)


	## Attributes ##

	def isRunning(self):
		return self._isRunning

	def runAgain(self):
		"""Determine whether this task should be run again.

		This method lets the Scheduler check to see whether this task should be
		re-run when it terminates.

		"""
		return self._rerun

	def isOnDemand(self):
		"""Return True if this task is not scheduled for periodic execution."""
		return self._period == 0

	def runOnCompletion(self):
		"""Request that this task be re-run after its current completion.

		Intended for on-demand tasks that are requested by the Scheduler while
		they are already running.

		"""
		self._rerun = True

	def unregister(self):
		"""Request that this task not be kept after its current completion.

		Used to remove a task from the scheduler.

		"""
		self._reregister = False
		self._rerun = False

	def disable(self):
		"""Disable future invocations of this task."""
		self._suspend = True

	def enable(self):
		"""Enable future invocations of this task."""
		self._suspend = False

	def period(self):
		"""Return the period of this task."""
		return self._period

	def setPeriod(self, period):
		"""Change the period for this task."""
		self._period = period

	def stop(self):
		self._isRunning = False

	def name(self):
		return self._name

	def startTime(self, newTime=None):
		if newTime:
			self._startTime = newTime
		return self._startTime
