class Runner(object):
	def __init__(self, config, target):
		self.target = target
		self.config = config
		self.args = (config,)
		self.create()
	def canCreate(klass):
		try:
			__import__(klass.getModuleName())
			return True
		except ImportError:
			return False
	canCreate = classmethod(canCreate)
	def create(self):
		self.module = __import__(self.__class__.getModuleName())
	def getModuleName(klass):
		return NotImplementedError
	def run(self):
		return NotImplementedError

class HotShotRunner(Runner):
	def getModuleName(klass):
		return 'hotshot'
	getModuleName = classmethod(getModuleName)
	def run(self):
		prof = self.module.Profile(self.config.profileFile)
		return prof.runcall(self.target, *self.args)

class PyProfilerRunner(Runner):
	def getModuleName(klass):
		return 'profile'
	getModuleName = classmethod(getModuleName)
	def run(self):
		prof = self.module.Profile()
		try:
			result = prof.runcall(self.module, *self.args)
		except KeyboardInterrupt, e:
			## FIXME: We shouldn't have to know how to write this here.
			import sys
			sys.stderr.write('%s [%s aborted]: Please wait while profile stats are saved.\n' % (self.config.progname, self.config.cmd))
			prof.dump_stats(self.config.profileFile)
			raise e
		except SystemExit:
			pass
		prof.dump_stats(self.config.profileFile)
		return result

class StandardRunner(Runner):
	def getModuleName(klass):
		return None
	getModuleName = classmethod(getModuleName)
	def run(self):
		apply(self.target, self.args)
	def canCreate(self):
		return True
	def create(self):
		pass

def getRunner(config, module):
	args = [config,module]
	if config.profile is True:
		if HotShotRunner.canCreate():
			return apply(HotShotRunner, args)
		elif PyProfilerRunner.canCreate():
			return apply(PyProfilerRunner, args)
	else:
		return apply(StandardRunner, args)
